From 246f239d9f40f633160f0c18f87a20922d4e77bb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:06:37 +0200 Subject: Merging debian version 1.65.0+dfsg1-2. Signed-off-by: Daniel Baumann --- Cargo.lock | 865 +---- Cargo.toml | 17 +- README.md | 27 +- RELEASES.md | 103 + compiler/rustc_apfloat/src/lib.rs | 2 + compiler/rustc_arena/src/lib.rs | 8 +- compiler/rustc_ast/Cargo.toml | 9 +- compiler/rustc_ast/src/ast.rs | 266 +- compiler/rustc_ast/src/ast_traits.rs | 90 +- compiler/rustc_ast/src/attr/mod.rs | 153 +- compiler/rustc_ast/src/lib.rs | 8 +- compiler/rustc_ast/src/mut_visit.rs | 77 +- compiler/rustc_ast/src/node_id.rs | 2 +- compiler/rustc_ast/src/token.rs | 49 + compiler/rustc_ast/src/tokenstream.rs | 127 +- compiler/rustc_ast/src/util/literal.rs | 32 +- compiler/rustc_ast/src/util/parser.rs | 68 +- compiler/rustc_ast/src/visit.rs | 66 +- compiler/rustc_ast_lowering/Cargo.toml | 14 +- compiler/rustc_ast_lowering/src/asm.rs | 191 +- compiler/rustc_ast_lowering/src/block.rs | 13 +- compiler/rustc_ast_lowering/src/errors.rs | 347 ++ compiler/rustc_ast_lowering/src/expr.rs | 235 +- compiler/rustc_ast_lowering/src/index.rs | 45 +- compiler/rustc_ast_lowering/src/item.rs | 162 +- compiler/rustc_ast_lowering/src/lib.rs | 479 ++- .../rustc_ast_lowering/src/lifetime_collector.rs | 15 +- compiler/rustc_ast_lowering/src/pat.rs | 112 +- compiler/rustc_ast_lowering/src/path.rs | 46 +- compiler/rustc_ast_passes/Cargo.toml | 1 + compiler/rustc_ast_passes/src/ast_validation.rs | 298 +- compiler/rustc_ast_passes/src/errors.rs | 245 ++ compiler/rustc_ast_passes/src/feature_gate.rs | 97 +- compiler/rustc_ast_passes/src/lib.rs | 6 +- compiler/rustc_ast_passes/src/node_count.rs | 22 +- compiler/rustc_ast_pretty/src/lib.rs | 2 + compiler/rustc_ast_pretty/src/pprust/state.rs | 38 +- compiler/rustc_ast_pretty/src/pprust/state/item.rs | 6 +- compiler/rustc_attr/src/builtin.rs | 398 +- compiler/rustc_attr/src/lib.rs | 5 +- compiler/rustc_attr/src/session_diagnostics.rs | 398 ++ .../rustc_borrowck/src/constraint_generation.rs | 2 +- compiler/rustc_borrowck/src/constraints/mod.rs | 11 +- compiler/rustc_borrowck/src/dataflow.rs | 4 +- .../src/diagnostics/bound_region_errors.rs | 4 +- .../src/diagnostics/conflict_errors.rs | 34 +- .../src/diagnostics/explain_borrow.rs | 64 +- compiler/rustc_borrowck/src/diagnostics/mod.rs | 14 +- .../rustc_borrowck/src/diagnostics/move_errors.rs | 4 +- .../src/diagnostics/mutability_errors.rs | 160 +- .../src/diagnostics/outlives_suggestion.rs | 1 - .../src/diagnostics/region_errors.rs | 156 +- .../rustc_borrowck/src/diagnostics/region_name.rs | 18 +- compiler/rustc_borrowck/src/invalidation.rs | 26 +- compiler/rustc_borrowck/src/lib.rs | 56 +- compiler/rustc_borrowck/src/location.rs | 5 +- compiler/rustc_borrowck/src/nll.rs | 5 +- compiler/rustc_borrowck/src/places_conflict.rs | 15 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 192 +- .../src/region_infer/opaque_types.rs | 57 +- compiler/rustc_borrowck/src/region_infer/values.rs | 4 +- compiler/rustc_borrowck/src/renumber.rs | 30 +- compiler/rustc_borrowck/src/session_diagnostics.rs | 125 +- .../rustc_borrowck/src/type_check/canonical.rs | 35 +- .../src/type_check/constraint_conversion.rs | 69 +- .../src/type_check/free_region_relations.rs | 64 +- compiler/rustc_borrowck/src/type_check/mod.rs | 223 +- compiler/rustc_borrowck/src/universal_regions.rs | 22 +- compiler/rustc_builtin_macros/Cargo.toml | 13 +- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_builtin_macros/src/assert.rs | 4 +- .../rustc_builtin_macros/src/assert/context.rs | 7 +- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 6 +- compiler/rustc_builtin_macros/src/cmdline_attrs.rs | 8 +- compiler/rustc_builtin_macros/src/concat.rs | 2 +- compiler/rustc_builtin_macros/src/concat_bytes.rs | 5 +- compiler/rustc_builtin_macros/src/derive.rs | 9 +- .../rustc_builtin_macros/src/deriving/bounds.rs | 1 - .../rustc_builtin_macros/src/deriving/clone.rs | 5 +- .../rustc_builtin_macros/src/deriving/cmp/eq.rs | 4 +- .../rustc_builtin_macros/src/deriving/cmp/ord.rs | 5 +- .../src/deriving/cmp/partial_eq.rs | 69 +- .../src/deriving/cmp/partial_ord.rs | 5 +- .../rustc_builtin_macros/src/deriving/debug.rs | 15 +- .../rustc_builtin_macros/src/deriving/decodable.rs | 3 +- .../rustc_builtin_macros/src/deriving/default.rs | 9 +- .../rustc_builtin_macros/src/deriving/encodable.rs | 5 +- .../src/deriving/generic/mod.rs | 87 +- .../src/deriving/generic/ty.rs | 5 +- compiler/rustc_builtin_macros/src/deriving/hash.rs | 5 +- compiler/rustc_builtin_macros/src/deriving/mod.rs | 2 +- compiler/rustc_builtin_macros/src/edition_panic.rs | 4 +- compiler/rustc_builtin_macros/src/format.rs | 193 +- .../rustc_builtin_macros/src/global_allocator.rs | 7 +- compiler/rustc_builtin_macros/src/lib.rs | 5 +- .../rustc_builtin_macros/src/proc_macro_harness.rs | 2 +- compiler/rustc_builtin_macros/src/source_util.rs | 2 +- .../src/standard_library_imports.rs | 5 +- compiler/rustc_builtin_macros/src/test.rs | 9 +- compiler/rustc_builtin_macros/src/test_harness.rs | 15 +- compiler/rustc_codegen_cranelift/.cirrus.yml | 2 +- .../.github/workflows/main.yml | 10 +- compiler/rustc_codegen_cranelift/Cargo.lock | 151 +- compiler/rustc_codegen_cranelift/Cargo.toml | 14 +- compiler/rustc_codegen_cranelift/Readme.md | 4 +- .../build_sysroot/Cargo.lock | 20 +- .../build_system/abi_checker.rs | 60 + .../build_system/build_backend.rs | 4 +- .../build_system/build_sysroot.rs | 10 +- .../rustc_codegen_cranelift/build_system/mod.rs | 58 +- .../build_system/prepare.rs | 11 +- .../build_system/rustc_info.rs | 9 + .../rustc_codegen_cranelift/build_system/tests.rs | 619 +++ .../rustc_codegen_cranelift/build_system/utils.rs | 29 +- compiler/rustc_codegen_cranelift/clean_all.sh | 2 +- compiler/rustc_codegen_cranelift/config.txt | 35 + .../example/alloc_system.rs | 2 +- .../rustc_codegen_cranelift/example/mini_core.rs | 12 +- .../example/mini_core_hello_world.rs | 117 +- .../0001-abi-checker-Disable-failing-tests.patch | 36 + .../0023-sysroot-Ignore-failing-tests.patch | 12 + compiler/rustc_codegen_cranelift/rust-toolchain | 2 +- compiler/rustc_codegen_cranelift/scripts/tests.sh | 203 - .../rustc_codegen_cranelift/src/abi/comments.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../rustc_codegen_cranelift/src/abi/pass_mode.rs | 29 +- .../rustc_codegen_cranelift/src/abi/returning.rs | 10 +- compiler/rustc_codegen_cranelift/src/analyze.rs | 2 +- compiler/rustc_codegen_cranelift/src/archive.rs | 1 + compiler/rustc_codegen_cranelift/src/base.rs | 281 +- compiler/rustc_codegen_cranelift/src/common.rs | 46 +- .../src/concurrency_limiter.rs | 168 + compiler/rustc_codegen_cranelift/src/constant.rs | 85 +- .../rustc_codegen_cranelift/src/debuginfo/emit.rs | 2 +- .../src/debuginfo/line_info.rs | 213 +- .../rustc_codegen_cranelift/src/debuginfo/mod.rs | 282 +- .../rustc_codegen_cranelift/src/discriminant.rs | 31 +- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 560 +-- compiler/rustc_codegen_cranelift/src/driver/jit.rs | 49 +- compiler/rustc_codegen_cranelift/src/global_asm.rs | 114 + compiler/rustc_codegen_cranelift/src/inline_asm.rs | 176 +- .../src/intrinsics/cpuid.rs | 2 +- .../rustc_codegen_cranelift/src/intrinsics/llvm.rs | 1 + .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 68 +- .../rustc_codegen_cranelift/src/intrinsics/simd.rs | 38 +- compiler/rustc_codegen_cranelift/src/lib.rs | 55 +- compiler/rustc_codegen_cranelift/src/main_shim.rs | 15 +- .../rustc_codegen_cranelift/src/optimize/mod.rs | 17 - .../rustc_codegen_cranelift/src/pretty_clif.rs | 61 +- compiler/rustc_codegen_cranelift/src/toolchain.rs | 6 +- compiler/rustc_codegen_cranelift/src/trap.rs | 25 +- compiler/rustc_codegen_cranelift/src/unsize.rs | 1 + .../rustc_codegen_cranelift/src/value_and_place.rs | 13 +- compiler/rustc_codegen_cranelift/test.sh | 13 +- compiler/rustc_codegen_gcc/example/alloc_system.rs | 2 +- .../0024-core-Disable-portable-simd-test.patch | 1 - compiler/rustc_codegen_gcc/src/abi.rs | 39 +- compiler/rustc_codegen_gcc/src/archive.rs | 1 + compiler/rustc_codegen_gcc/src/builder.rs | 174 +- compiler/rustc_codegen_gcc/src/common.rs | 4 - compiler/rustc_codegen_gcc/src/consts.rs | 12 +- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 20 +- compiler/rustc_codegen_gcc/src/lib.rs | 1 + compiler/rustc_codegen_llvm/Cargo.toml | 1 + compiler/rustc_codegen_llvm/src/abi.rs | 105 +- compiler/rustc_codegen_llvm/src/asm.rs | 9 - compiler/rustc_codegen_llvm/src/attributes.rs | 7 +- compiler/rustc_codegen_llvm/src/back/archive.rs | 49 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 22 +- compiler/rustc_codegen_llvm/src/back/write.rs | 26 +- compiler/rustc_codegen_llvm/src/builder.rs | 91 +- compiler/rustc_codegen_llvm/src/callee.rs | 13 +- compiler/rustc_codegen_llvm/src/common.rs | 87 +- compiler/rustc_codegen_llvm/src/consts.rs | 35 +- compiler/rustc_codegen_llvm/src/context.rs | 14 +- .../rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 2 - .../rustc_codegen_llvm/src/coverageinfo/mod.rs | 1 - .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 19 +- .../src/debuginfo/metadata/enums/cpp_like.rs | 740 +++- .../src/debuginfo/metadata/enums/mod.rs | 96 +- .../src/debuginfo/metadata/enums/native.rs | 12 +- .../src/debuginfo/metadata/type_map.rs | 11 + compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 1 - compiler/rustc_codegen_llvm/src/debuginfo/utils.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 1 - compiler/rustc_codegen_llvm/src/intrinsic.rs | 96 +- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs | 11 - compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 23 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 17 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 1 - compiler/rustc_codegen_llvm/src/type_of.rs | 1 - compiler/rustc_codegen_ssa/Cargo.toml | 1 - compiler/rustc_codegen_ssa/src/back/archive.rs | 73 +- compiler/rustc_codegen_ssa/src/back/link.rs | 402 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 67 +- compiler/rustc_codegen_ssa/src/back/metadata.rs | 16 +- .../rustc_codegen_ssa/src/back/symbol_export.rs | 20 +- compiler/rustc_codegen_ssa/src/back/write.rs | 29 +- compiler/rustc_codegen_ssa/src/base.rs | 81 +- .../rustc_codegen_ssa/src/debuginfo/type_names.rs | 56 +- compiler/rustc_codegen_ssa/src/lib.rs | 32 +- compiler/rustc_codegen_ssa/src/meth.rs | 21 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 6 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 221 +- compiler/rustc_codegen_ssa/src/mir/constant.rs | 36 +- compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 16 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 14 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 9 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 19 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 18 +- compiler/rustc_codegen_ssa/src/mir/statement.rs | 14 +- compiler/rustc_codegen_ssa/src/target_features.rs | 11 +- compiler/rustc_codegen_ssa/src/traits/builder.rs | 157 +- compiler/rustc_codegen_ssa/src/traits/consts.rs | 1 - compiler/rustc_const_eval/src/const_eval/error.rs | 8 +- .../src/const_eval/eval_queries.rs | 40 +- .../rustc_const_eval/src/const_eval/machine.rs | 117 +- compiler/rustc_const_eval/src/const_eval/mod.rs | 21 +- .../rustc_const_eval/src/const_eval/valtrees.rs | 35 +- compiler/rustc_const_eval/src/errors.rs | 125 +- compiler/rustc_const_eval/src/interpret/cast.rs | 39 +- .../rustc_const_eval/src/interpret/eval_context.rs | 13 +- compiler/rustc_const_eval/src/interpret/intern.rs | 16 +- .../rustc_const_eval/src/interpret/intrinsics.rs | 71 +- .../src/interpret/intrinsics/caller_location.rs | 2 +- .../src/interpret/intrinsics/type_name.rs | 2 +- compiler/rustc_const_eval/src/interpret/machine.rs | 66 +- compiler/rustc_const_eval/src/interpret/memory.rs | 111 +- compiler/rustc_const_eval/src/interpret/operand.rs | 234 +- .../rustc_const_eval/src/interpret/operator.rs | 18 +- compiler/rustc_const_eval/src/interpret/place.rs | 35 +- .../rustc_const_eval/src/interpret/projection.rs | 9 +- compiler/rustc_const_eval/src/interpret/step.rs | 14 +- .../rustc_const_eval/src/interpret/terminator.rs | 34 +- compiler/rustc_const_eval/src/interpret/traits.rs | 2 +- .../rustc_const_eval/src/interpret/validity.rs | 259 +- compiler/rustc_const_eval/src/lib.rs | 2 +- .../rustc_const_eval/src/might_permit_raw_init.rs | 6 +- .../src/transform/check_consts/check.rs | 8 +- .../src/transform/check_consts/ops.rs | 161 +- .../src/transform/check_consts/qualifs.rs | 66 +- .../src/transform/promote_consts.rs | 30 +- .../rustc_const_eval/src/transform/validate.rs | 93 +- compiler/rustc_data_structures/Cargo.toml | 23 +- compiler/rustc_data_structures/src/fingerprint.rs | 4 +- compiler/rustc_data_structures/src/fx.rs | 15 +- compiler/rustc_data_structures/src/lib.rs | 5 +- compiler/rustc_data_structures/src/map_in_place.rs | 127 +- .../src/obligation_forest/mod.rs | 4 + compiler/rustc_data_structures/src/sorted_map.rs | 20 +- compiler/rustc_data_structures/src/sync.rs | 4 +- compiler/rustc_data_structures/src/thin_vec.rs | 135 - .../rustc_data_structures/src/thin_vec/tests.rs | 42 - .../src/transitive_relation.rs | 121 +- .../src/transitive_relation/tests.rs | 48 +- compiler/rustc_driver/Cargo.toml | 3 +- compiler/rustc_driver/src/lib.rs | 61 +- compiler/rustc_driver/src/pretty.rs | 16 +- compiler/rustc_driver/src/session_diagnostics.rs | 40 + .../rustc_error_codes/src/error_codes/E0695.md | 3 - compiler/rustc_error_codes/src/lib.rs | 2 + .../locales/en-US/ast_lowering.ftl | 139 + .../locales/en-US/ast_passes.ftl | 91 + .../rustc_error_messages/locales/en-US/attr.ftl | 107 + .../locales/en-US/borrowck.ftl | 58 +- .../locales/en-US/builtin_macros.ftl | 4 +- .../locales/en-US/const_eval.ftl | 78 +- .../rustc_error_messages/locales/en-US/driver.ftl | 13 + .../rustc_error_messages/locales/en-US/expand.ftl | 21 +- .../rustc_error_messages/locales/en-US/infer.ftl | 171 + .../locales/en-US/interface.ftl | 43 + .../rustc_error_messages/locales/en-US/lint.ftl | 366 +- .../locales/en-US/metadata.ftl | 275 ++ .../rustc_error_messages/locales/en-US/middle.ftl | 17 + .../locales/en-US/mir_dataflow.ftl | 29 + .../locales/en-US/monomorphize.ftl | 26 + .../rustc_error_messages/locales/en-US/parser.ftl | 148 +- .../rustc_error_messages/locales/en-US/passes.ftl | 230 +- .../locales/en-US/plugin_impl.ftl | 4 + .../rustc_error_messages/locales/en-US/privacy.ftl | 20 +- .../locales/en-US/query_system.ftl | 25 + .../locales/en-US/save_analysis.ftl | 1 + .../rustc_error_messages/locales/en-US/session.ftl | 68 + .../locales/en-US/symbol_mangling.ftl | 1 + .../locales/en-US/trait_selection.ftl | 26 + .../locales/en-US/ty_utils.ftl | 47 + .../rustc_error_messages/locales/en-US/typeck.ftl | 88 +- compiler/rustc_error_messages/src/lib.rs | 23 +- compiler/rustc_errors/Cargo.toml | 7 +- .../src/annotate_snippet_emitter_writer.rs | 25 +- compiler/rustc_errors/src/diagnostic.rs | 50 +- compiler/rustc_errors/src/diagnostic_builder.rs | 33 +- compiler/rustc_errors/src/emitter.rs | 140 +- compiler/rustc_errors/src/json.rs | 19 +- compiler/rustc_errors/src/lib.rs | 162 +- compiler/rustc_errors/src/translation.rs | 103 + compiler/rustc_expand/src/base.rs | 58 +- compiler/rustc_expand/src/build.rs | 43 +- compiler/rustc_expand/src/config.rs | 74 +- compiler/rustc_expand/src/errors.rs | 48 + compiler/rustc_expand/src/expand.rs | 40 +- compiler/rustc_expand/src/lib.rs | 6 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 11 +- compiler/rustc_expand/src/mbe/metavar_expr.rs | 2 +- compiler/rustc_expand/src/mbe/transcribe.rs | 34 +- compiler/rustc_expand/src/module.rs | 8 +- compiler/rustc_expand/src/placeholders.rs | 8 +- compiler/rustc_expand/src/proc_macro_server.rs | 71 +- compiler/rustc_feature/src/accepted.rs | 6 + compiler/rustc_feature/src/active.rs | 22 +- compiler/rustc_feature/src/builtin_attrs.rs | 33 +- compiler/rustc_feature/src/lib.rs | 6 +- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_fs_util/src/lib.rs | 3 + compiler/rustc_graphviz/src/lib.rs | 2 + compiler/rustc_hir/src/def.rs | 25 +- compiler/rustc_hir/src/definitions.rs | 1 - compiler/rustc_hir/src/errors.rs | 10 + compiler/rustc_hir/src/hir.rs | 219 +- compiler/rustc_hir/src/hir_id.rs | 12 +- compiler/rustc_hir/src/intravisit.rs | 168 +- compiler/rustc_hir/src/lang_items.rs | 15 +- compiler/rustc_hir/src/lib.rs | 8 +- compiler/rustc_hir/src/pat_util.rs | 19 +- compiler/rustc_hir/src/stable_hash_impls.rs | 17 +- compiler/rustc_hir/src/target.rs | 15 +- compiler/rustc_hir/src/weak_lang_items.rs | 6 + compiler/rustc_hir_pretty/src/lib.rs | 150 +- compiler/rustc_incremental/src/lib.rs | 2 +- compiler/rustc_index/src/lib.rs | 4 +- compiler/rustc_index/src/vec.rs | 4 +- compiler/rustc_infer/Cargo.toml | 1 + compiler/rustc_infer/src/errors/mod.rs | 499 +++ .../rustc_infer/src/errors/note_and_explain.rs | 172 + compiler/rustc_infer/src/infer/at.rs | 6 +- .../src/infer/canonical/canonicalizer.rs | 13 +- .../src/infer/canonical/query_response.rs | 74 +- .../rustc_infer/src/infer/canonical/substitute.rs | 7 +- compiler/rustc_infer/src/infer/combine.rs | 54 +- .../rustc_infer/src/infer/error_reporting/mod.rs | 349 +- .../src/infer/error_reporting/need_type_info.rs | 347 +- .../nice_region_error/different_lifetimes.rs | 147 +- .../nice_region_error/find_anon_type.rs | 10 +- .../mismatched_static_lifetime.rs | 54 +- .../nice_region_error/placeholder_error.rs | 5 +- .../nice_region_error/static_impl_trait.rs | 6 +- .../nice_region_error/trait_impl_difference.rs | 15 +- .../rustc_infer/src/infer/error_reporting/note.rs | 150 +- compiler/rustc_infer/src/infer/free_regions.rs | 13 +- compiler/rustc_infer/src/infer/freshen.rs | 1 - .../rustc_infer/src/infer/higher_ranked/mod.rs | 13 +- .../src/infer/lexical_region_resolve/mod.rs | 307 +- compiler/rustc_infer/src/infer/mod.rs | 126 +- compiler/rustc_infer/src/infer/nll_relate/mod.rs | 62 +- compiler/rustc_infer/src/infer/opaque_types.rs | 34 +- .../rustc_infer/src/infer/opaque_types/table.rs | 2 +- compiler/rustc_infer/src/infer/outlives/env.rs | 62 +- compiler/rustc_infer/src/infer/outlives/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/obligations.rs | 36 +- .../src/infer/outlives/test_type_match.rs | 15 +- compiler/rustc_infer/src/infer/outlives/verify.rs | 6 +- .../src/infer/region_constraints/mod.rs | 31 +- compiler/rustc_infer/src/infer/sub.rs | 17 +- compiler/rustc_infer/src/infer/type_variable.rs | 1 + compiler/rustc_infer/src/infer/undo_log.rs | 2 +- compiler/rustc_infer/src/lib.rs | 5 +- compiler/rustc_interface/Cargo.toml | 1 + compiler/rustc_interface/src/errors.rs | 89 + compiler/rustc_interface/src/interface.rs | 8 +- compiler/rustc_interface/src/lib.rs | 8 +- compiler/rustc_interface/src/passes.rs | 103 +- compiler/rustc_interface/src/queries.rs | 20 +- compiler/rustc_interface/src/tests.rs | 11 +- compiler/rustc_interface/src/util.rs | 4 +- compiler/rustc_lexer/src/lib.rs | 4 +- compiler/rustc_lint/src/array_into_iter.rs | 3 +- compiler/rustc_lint/src/builtin.rs | 197 +- compiler/rustc_lint/src/context.rs | 135 +- compiler/rustc_lint/src/early.rs | 30 +- compiler/rustc_lint/src/errors.rs | 162 + .../rustc_lint/src/hidden_unicode_codepoints.rs | 4 +- compiler/rustc_lint/src/internal.rs | 18 +- compiler/rustc_lint/src/late.rs | 59 +- compiler/rustc_lint/src/let_underscore.rs | 175 + compiler/rustc_lint/src/levels.rs | 132 +- compiler/rustc_lint/src/lib.rs | 55 +- compiler/rustc_lint/src/methods.rs | 18 +- compiler/rustc_lint/src/nonstandard_style.rs | 25 +- compiler/rustc_lint/src/noop_method_call.rs | 3 +- compiler/rustc_lint/src/passes.rs | 14 +- compiler/rustc_lint/src/types.rs | 115 +- compiler/rustc_lint/src/unused.rs | 102 +- compiler/rustc_lint_defs/src/builtin.rs | 64 +- compiler/rustc_lint_defs/src/lib.rs | 27 +- compiler/rustc_llvm/build.rs | 11 +- .../rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp | 13 - .../llvm-wrapper/CoverageMappingWrapper.cpp | 11 - compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 74 +- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 67 +- compiler/rustc_llvm/src/lib.rs | 2 + compiler/rustc_log/src/lib.rs | 3 + compiler/rustc_macros/Cargo.toml | 2 +- .../rustc_macros/src/diagnostics/diagnostic.rs | 84 +- .../src/diagnostics/diagnostic_builder.rs | 110 +- compiler/rustc_macros/src/diagnostics/fluent.rs | 56 +- compiler/rustc_macros/src/diagnostics/mod.rs | 20 +- .../rustc_macros/src/diagnostics/subdiagnostic.rs | 740 ++-- compiler/rustc_macros/src/diagnostics/utils.rs | 59 +- compiler/rustc_macros/src/lib.rs | 33 +- compiler/rustc_macros/src/query.rs | 502 +-- compiler/rustc_macros/src/symbols.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 56 +- compiler/rustc_metadata/src/dependency_format.rs | 79 +- compiler/rustc_metadata/src/errors.rs | 679 ++++ compiler/rustc_metadata/src/fs.rs | 25 +- compiler/rustc_metadata/src/lib.rs | 11 +- compiler/rustc_metadata/src/locator.rs | 329 +- compiler/rustc_metadata/src/native_libs.rs | 346 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 402 +- .../src/rmeta/decoder/cstore_impl.rs | 47 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 683 ++-- compiler/rustc_metadata/src/rmeta/mod.rs | 54 +- compiler/rustc_metadata/src/rmeta/table.rs | 19 +- compiler/rustc_middle/Cargo.toml | 31 +- compiler/rustc_middle/src/arena.rs | 4 +- compiler/rustc_middle/src/dep_graph/dep_node.rs | 43 +- compiler/rustc_middle/src/error.rs | 50 + compiler/rustc_middle/src/hir/map/mod.rs | 93 +- compiler/rustc_middle/src/infer/canonical.rs | 27 +- compiler/rustc_middle/src/lib.rs | 7 +- compiler/rustc_middle/src/metadata.rs | 3 +- compiler/rustc_middle/src/middle/lang_items.rs | 6 +- compiler/rustc_middle/src/middle/limits.rs | 8 +- .../rustc_middle/src/middle/resolve_lifetime.rs | 10 +- compiler/rustc_middle/src/middle/stability.rs | 77 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 +- compiler/rustc_middle/src/mir/generic_graph.rs | 4 +- .../rustc_middle/src/mir/interpret/allocation.rs | 331 +- compiler/rustc_middle/src/mir/interpret/error.rs | 13 +- compiler/rustc_middle/src/mir/interpret/mod.rs | 6 +- compiler/rustc_middle/src/mir/interpret/pointer.rs | 15 +- compiler/rustc_middle/src/mir/interpret/queries.rs | 4 +- compiler/rustc_middle/src/mir/interpret/value.rs | 163 +- compiler/rustc_middle/src/mir/mod.rs | 194 +- compiler/rustc_middle/src/mir/patch.rs | 36 +- compiler/rustc_middle/src/mir/pretty.rs | 60 +- compiler/rustc_middle/src/mir/query.rs | 26 +- compiler/rustc_middle/src/mir/spanview.rs | 4 +- compiler/rustc_middle/src/mir/syntax.rs | 207 +- compiler/rustc_middle/src/mir/terminator.rs | 4 +- compiler/rustc_middle/src/mir/traversal.rs | 4 +- compiler/rustc_middle/src/mir/type_foldable.rs | 207 +- compiler/rustc_middle/src/mir/type_visitable.rs | 170 +- compiler/rustc_middle/src/mir/visit.rs | 186 +- compiler/rustc_middle/src/query/mod.rs | 176 +- compiler/rustc_middle/src/thir.rs | 236 +- compiler/rustc_middle/src/thir/visit.rs | 29 +- compiler/rustc_middle/src/traits/mod.rs | 62 +- compiler/rustc_middle/src/traits/query.rs | 12 +- compiler/rustc_middle/src/traits/select.rs | 3 + .../src/traits/specialization_graph.rs | 2 +- .../rustc_middle/src/traits/structural_impls.rs | 2 + compiler/rustc_middle/src/ty/abstract_const.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 8 +- compiler/rustc_middle/src/ty/assoc.rs | 2 +- compiler/rustc_middle/src/ty/binding.rs | 14 +- compiler/rustc_middle/src/ty/cast.rs | 4 + compiler/rustc_middle/src/ty/consts.rs | 8 +- compiler/rustc_middle/src/ty/consts/kind.rs | 20 +- compiler/rustc_middle/src/ty/consts/valtree.rs | 5 +- compiler/rustc_middle/src/ty/context.rs | 54 +- compiler/rustc_middle/src/ty/diagnostics.rs | 18 +- compiler/rustc_middle/src/ty/error.rs | 45 +- compiler/rustc_middle/src/ty/flags.rs | 16 +- compiler/rustc_middle/src/ty/fold.rs | 43 +- compiler/rustc_middle/src/ty/generics.rs | 26 +- compiler/rustc_middle/src/ty/impls_ty.rs | 2 +- compiler/rustc_middle/src/ty/inhabitedness/mod.rs | 4 - compiler/rustc_middle/src/ty/instance.rs | 4 +- compiler/rustc_middle/src/ty/layout.rs | 720 ++-- .../rustc_middle/src/ty/layout_sanity_check.rs | 303 ++ compiler/rustc_middle/src/ty/list.rs | 4 + compiler/rustc_middle/src/ty/mod.rs | 324 +- .../src/ty/normalize_erasing_regions.rs | 4 +- compiler/rustc_middle/src/ty/parameterized.rs | 7 +- compiler/rustc_middle/src/ty/print/pretty.rs | 118 +- compiler/rustc_middle/src/ty/query.rs | 36 +- compiler/rustc_middle/src/ty/relate.rs | 39 +- compiler/rustc_middle/src/ty/structural_impls.rs | 496 +-- compiler/rustc_middle/src/ty/sty.rs | 57 +- compiler/rustc_middle/src/ty/subst.rs | 8 +- compiler/rustc_middle/src/ty/trait_def.rs | 1 - compiler/rustc_middle/src/ty/util.rs | 10 +- compiler/rustc_middle/src/ty/visit.rs | 14 +- compiler/rustc_middle/src/ty/vtable.rs | 8 +- compiler/rustc_middle/src/ty/walk.rs | 8 +- compiler/rustc_middle/src/values.rs | 54 + compiler/rustc_mir_build/src/build/block.rs | 213 +- .../rustc_mir_build/src/build/expr/as_constant.rs | 37 +- .../rustc_mir_build/src/build/expr/as_place.rs | 144 +- .../rustc_mir_build/src/build/expr/as_rvalue.rs | 31 +- compiler/rustc_mir_build/src/build/expr/as_temp.rs | 5 +- compiler/rustc_mir_build/src/build/expr/into.rs | 25 +- compiler/rustc_mir_build/src/build/expr/stmt.rs | 22 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 157 +- .../rustc_mir_build/src/build/matches/simplify.rs | 24 +- compiler/rustc_mir_build/src/build/matches/test.rs | 50 +- compiler/rustc_mir_build/src/build/matches/util.rs | 14 +- compiler/rustc_mir_build/src/build/mod.rs | 616 ++- compiler/rustc_mir_build/src/build/scope.rs | 38 +- compiler/rustc_mir_build/src/check_unsafety.rs | 19 +- compiler/rustc_mir_build/src/lib.rs | 2 +- compiler/rustc_mir_build/src/thir/constant.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 18 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 72 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 116 +- .../src/thir/pattern/check_match.rs | 32 +- .../src/thir/pattern/const_to_pat.rs | 48 +- .../src/thir/pattern/deconstruct_pat.rs | 47 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 127 +- .../rustc_mir_build/src/thir/pattern/usefulness.rs | 28 +- compiler/rustc_mir_dataflow/Cargo.toml | 3 + compiler/rustc_mir_dataflow/src/errors.rs | 71 + .../rustc_mir_dataflow/src/framework/engine.rs | 22 +- .../rustc_mir_dataflow/src/framework/graphviz.rs | 4 +- compiler/rustc_mir_dataflow/src/framework/mod.rs | 3 +- compiler/rustc_mir_dataflow/src/framework/tests.rs | 10 +- compiler/rustc_mir_dataflow/src/impls/liveness.rs | 107 +- .../src/impls/storage_liveness.rs | 2 +- compiler/rustc_mir_dataflow/src/lib.rs | 5 +- .../rustc_mir_dataflow/src/move_paths/builder.rs | 4 +- compiler/rustc_mir_dataflow/src/move_paths/mod.rs | 2 +- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 30 +- compiler/rustc_mir_dataflow/src/storage.rs | 2 +- .../src/abort_unwinding_calls.rs | 2 +- .../rustc_mir_transform/src/add_call_guards.rs | 2 +- .../src/add_moves_for_packed_drops.rs | 2 +- compiler/rustc_mir_transform/src/add_retag.rs | 19 +- compiler/rustc_mir_transform/src/check_unsafety.rs | 91 +- .../src/cleanup_post_borrowck.rs | 2 +- compiler/rustc_mir_transform/src/const_goto.rs | 4 +- compiler/rustc_mir_transform/src/const_prop.rs | 127 +- .../rustc_mir_transform/src/const_prop_lint.rs | 66 +- compiler/rustc_mir_transform/src/coverage/graph.rs | 4 +- compiler/rustc_mir_transform/src/coverage/mod.rs | 4 +- compiler/rustc_mir_transform/src/coverage/query.rs | 4 +- compiler/rustc_mir_transform/src/coverage/spans.rs | 2 +- compiler/rustc_mir_transform/src/coverage/tests.rs | 6 +- .../src/dead_store_elimination.rs | 2 +- compiler/rustc_mir_transform/src/deaggregator.rs | 4 - .../rustc_mir_transform/src/deduplicate_blocks.rs | 5 +- .../rustc_mir_transform/src/deref_separator.rs | 23 +- compiler/rustc_mir_transform/src/dest_prop.rs | 8 +- .../src/early_otherwise_branch.rs | 6 +- .../src/elaborate_box_derefs.rs | 40 +- .../rustc_mir_transform/src/elaborate_drops.rs | 16 +- .../rustc_mir_transform/src/ffi_unwind_calls.rs | 2 +- compiler/rustc_mir_transform/src/generator.rs | 108 +- compiler/rustc_mir_transform/src/inline.rs | 371 +- compiler/rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 180 +- .../rustc_mir_transform/src/lower_intrinsics.rs | 31 +- .../src/multiple_return_terminators.rs | 2 +- .../rustc_mir_transform/src/normalize_array_len.rs | 4 +- compiler/rustc_mir_transform/src/nrvo.rs | 8 +- compiler/rustc_mir_transform/src/pass_manager.rs | 73 +- .../src/remove_noop_landing_pads.rs | 4 +- .../rustc_mir_transform/src/remove_uninit_drops.rs | 2 +- .../rustc_mir_transform/src/required_consts.rs | 11 +- compiler/rustc_mir_transform/src/reveal_all.rs | 2 +- .../src/separate_const_switch.rs | 8 +- compiler/rustc_mir_transform/src/shim.rs | 131 +- compiler/rustc_mir_transform/src/simplify.rs | 10 +- .../src/simplify_comparison_integral.rs | 2 +- compiler/rustc_mir_transform/src/simplify_try.rs | 4 +- .../src/uninhabited_enum_branching.rs | 6 +- .../rustc_mir_transform/src/unreachable_prop.rs | 76 +- compiler/rustc_monomorphize/Cargo.toml | 4 +- compiler/rustc_monomorphize/src/collector.rs | 168 +- compiler/rustc_monomorphize/src/errors.rs | 85 + compiler/rustc_monomorphize/src/lib.rs | 7 +- .../rustc_monomorphize/src/partitioning/mod.rs | 15 +- compiler/rustc_monomorphize/src/polymorphize.rs | 55 +- compiler/rustc_monomorphize/src/util.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 2 - .../src/lexer/unescape_error_reporting.rs | 8 +- compiler/rustc_parse/src/lib.rs | 6 +- compiler/rustc_parse/src/parser/attr.rs | 31 +- compiler/rustc_parse/src/parser/attr_wrapper.rs | 78 +- compiler/rustc_parse/src/parser/diagnostics.rs | 476 ++- compiler/rustc_parse/src/parser/expr.rs | 837 ++-- compiler/rustc_parse/src/parser/generics.rs | 15 +- compiler/rustc_parse/src/parser/item.rs | 192 +- compiler/rustc_parse/src/parser/mod.rs | 45 +- compiler/rustc_parse/src/parser/nonterminal.rs | 24 +- compiler/rustc_parse/src/parser/pat.rs | 59 +- compiler/rustc_parse/src/parser/path.rs | 22 +- compiler/rustc_parse/src/parser/stmt.rs | 70 +- compiler/rustc_parse/src/parser/ty.rs | 39 +- compiler/rustc_parse_format/src/lib.rs | 87 +- compiler/rustc_parse_format/src/tests.rs | 43 +- compiler/rustc_passes/src/check_attr.rs | 82 +- compiler/rustc_passes/src/dead.rs | 22 +- compiler/rustc_passes/src/entry.rs | 56 +- compiler/rustc_passes/src/errors.rs | 201 +- compiler/rustc_passes/src/hir_id_validator.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 540 ++- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_passes/src/lib_features.rs | 25 +- compiler/rustc_passes/src/liveness.rs | 220 +- compiler/rustc_passes/src/naked_functions.rs | 96 +- compiler/rustc_passes/src/stability.rs | 176 +- compiler/rustc_plugin_impl/Cargo.toml | 1 + compiler/rustc_plugin_impl/src/errors.rs | 20 + compiler/rustc_plugin_impl/src/lib.rs | 3 + compiler/rustc_plugin_impl/src/load.rs | 16 +- compiler/rustc_privacy/src/errors.rs | 22 +- compiler/rustc_privacy/src/lib.rs | 168 +- compiler/rustc_query_impl/Cargo.toml | 4 +- compiler/rustc_query_impl/src/lib.rs | 10 +- compiler/rustc_query_impl/src/on_disk_cache.rs | 76 +- compiler/rustc_query_impl/src/plumbing.rs | 447 ++- compiler/rustc_query_impl/src/profiling_support.rs | 12 +- compiler/rustc_query_impl/src/values.rs | 45 - compiler/rustc_query_system/Cargo.toml | 8 +- compiler/rustc_query_system/src/error.rs | 80 + compiler/rustc_query_system/src/ich/hcx.rs | 25 +- compiler/rustc_query_system/src/ich/impls_hir.rs | 24 +- .../rustc_query_system/src/ich/impls_syntax.rs | 8 +- compiler/rustc_query_system/src/lib.rs | 9 +- compiler/rustc_query_system/src/query/config.rs | 20 +- compiler/rustc_query_system/src/query/job.rs | 69 +- compiler/rustc_query_system/src/query/mod.rs | 10 +- compiler/rustc_query_system/src/query/plumbing.rs | 88 +- compiler/rustc_query_system/src/values.rs | 14 + compiler/rustc_resolve/src/access_levels.rs | 160 +- compiler/rustc_resolve/src/build_reduced_graph.rs | 56 +- compiler/rustc_resolve/src/check_unused.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 3 +- compiler/rustc_resolve/src/diagnostics.rs | 61 +- compiler/rustc_resolve/src/ident.rs | 83 +- compiler/rustc_resolve/src/imports.rs | 109 +- compiler/rustc_resolve/src/late.rs | 234 +- compiler/rustc_resolve/src/late/diagnostics.rs | 133 +- compiler/rustc_resolve/src/late/lifetimes.rs | 511 +-- compiler/rustc_resolve/src/lib.rs | 87 +- compiler/rustc_resolve/src/macros.rs | 31 +- compiler/rustc_save_analysis/Cargo.toml | 2 + compiler/rustc_save_analysis/src/dump_visitor.rs | 19 +- compiler/rustc_save_analysis/src/errors.rs | 10 + compiler/rustc_save_analysis/src/lib.rs | 40 +- compiler/rustc_save_analysis/src/sig.rs | 10 +- compiler/rustc_serialize/Cargo.toml | 1 + compiler/rustc_serialize/src/collection_impls.rs | 20 +- compiler/rustc_serialize/src/lib.rs | 5 +- compiler/rustc_serialize/src/serialize.rs | 28 +- compiler/rustc_session/Cargo.toml | 1 - compiler/rustc_session/src/cgu_reuse_tracker.rs | 44 +- compiler/rustc_session/src/config.rs | 43 +- compiler/rustc_session/src/config/sigpipe.rs | 22 + compiler/rustc_session/src/cstore.rs | 35 +- compiler/rustc_session/src/errors.rs | 221 ++ compiler/rustc_session/src/filesearch.rs | 1 - compiler/rustc_session/src/lib.rs | 8 +- compiler/rustc_session/src/options.rs | 88 +- compiler/rustc_session/src/output.rs | 35 +- compiler/rustc_session/src/parse.rs | 112 +- compiler/rustc_session/src/session.rs | 178 +- compiler/rustc_smir/src/lib.rs | 2 + compiler/rustc_smir/src/mir.rs | 12 +- compiler/rustc_span/src/def_id.rs | 15 +- compiler/rustc_span/src/hygiene.rs | 29 +- compiler/rustc_span/src/lib.rs | 37 +- compiler/rustc_span/src/source_map.rs | 107 +- compiler/rustc_span/src/source_map/tests.rs | 2 +- compiler/rustc_span/src/symbol.rs | 51 +- compiler/rustc_symbol_mangling/Cargo.toml | 2 + compiler/rustc_symbol_mangling/src/errors.rs | 34 + compiler/rustc_symbol_mangling/src/legacy.rs | 2 - compiler/rustc_symbol_mangling/src/lib.rs | 8 +- compiler/rustc_symbol_mangling/src/test.rs | 26 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 24 +- compiler/rustc_symbol_mangling/src/v0.rs | 14 +- compiler/rustc_target/src/abi/call/aarch64.rs | 43 +- compiler/rustc_target/src/abi/call/amdgpu.rs | 2 +- compiler/rustc_target/src/abi/call/arm.rs | 2 +- compiler/rustc_target/src/abi/call/avr.rs | 2 +- compiler/rustc_target/src/abi/call/bpf.rs | 2 +- compiler/rustc_target/src/abi/call/hexagon.rs | 2 +- compiler/rustc_target/src/abi/call/m68k.rs | 2 +- compiler/rustc_target/src/abi/call/mips.rs | 8 +- compiler/rustc_target/src/abi/call/mips64.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 46 +- compiler/rustc_target/src/abi/call/msp430.rs | 2 +- compiler/rustc_target/src/abi/call/nvptx.rs | 33 - compiler/rustc_target/src/abi/call/nvptx64.rs | 4 +- compiler/rustc_target/src/abi/call/powerpc.rs | 2 +- compiler/rustc_target/src/abi/call/powerpc64.rs | 2 +- compiler/rustc_target/src/abi/call/riscv.rs | 2 +- compiler/rustc_target/src/abi/call/s390x.rs | 2 +- compiler/rustc_target/src/abi/call/sparc.rs | 8 +- compiler/rustc_target/src/abi/call/sparc64.rs | 2 +- compiler/rustc_target/src/abi/call/wasm.rs | 4 +- compiler/rustc_target/src/abi/call/x86.rs | 6 +- compiler/rustc_target/src/abi/call/x86_64.rs | 2 +- compiler/rustc_target/src/abi/call/x86_win64.rs | 2 +- compiler/rustc_target/src/abi/mod.rs | 67 +- compiler/rustc_target/src/lib.rs | 4 +- .../rustc_target/src/spec/aarch64_apple_darwin.rs | 8 +- .../spec/aarch64_nintendo_switch_freestanding.rs | 1 - .../src/spec/aarch64_pc_windows_gnullvm.rs | 2 +- .../src/spec/aarch64_pc_windows_msvc.rs | 2 +- .../rustc_target/src/spec/aarch64_unknown_uefi.rs | 2 +- .../src/spec/aarch64_uwp_windows_msvc.rs | 2 +- compiler/rustc_target/src/spec/android_base.rs | 3 +- compiler/rustc_target/src/spec/apple_base.rs | 58 +- compiler/rustc_target/src/spec/apple_sdk_base.rs | 45 +- .../src/spec/arm64_32_apple_watchos.rs | 2 +- .../src/spec/armeb_unknown_linux_gnueabi.rs | 19 + compiler/rustc_target/src/spec/armv4t_none_eabi.rs | 56 + .../src/spec/asmjs_unknown_emscripten.rs | 2 +- compiler/rustc_target/src/spec/avr_gnu_base.rs | 3 +- compiler/rustc_target/src/spec/bpf_base.rs | 2 +- compiler/rustc_target/src/spec/crt_objects.rs | 40 +- compiler/rustc_target/src/spec/fuchsia_base.rs | 5 + .../src/spec/hexagon_unknown_linux_musl.rs | 1 - .../rustc_target/src/spec/i686_apple_darwin.rs | 3 +- compiler/rustc_target/src/spec/l4re_base.rs | 5 +- compiler/rustc_target/src/spec/linux_base.rs | 8 +- compiler/rustc_target/src/spec/linux_musl_base.rs | 8 +- compiler/rustc_target/src/spec/mod.rs | 415 +- compiler/rustc_target/src/spec/msvc_base.rs | 5 +- .../rustc_target/src/spec/nvptx64_nvidia_cuda.rs | 2 +- .../src/spec/powerpc64_unknown_openbsd.rs | 17 + .../src/spec/powerpc_unknown_freebsd.rs | 3 +- .../src/spec/riscv64gc_unknown_openbsd.rs | 18 + compiler/rustc_target/src/spec/tests/tests_impl.rs | 86 +- .../rustc_target/src/spec/thumbv4t_none_eabi.rs | 4 +- .../rustc_target/src/spec/thumbv6m_none_eabi.rs | 4 +- compiler/rustc_target/src/spec/uefi_msvc_base.rs | 3 +- .../src/spec/wasm32_unknown_emscripten.rs | 4 +- compiler/rustc_target/src/spec/wasm32_wasi.rs | 4 +- compiler/rustc_target/src/spec/wasm_base.rs | 5 +- compiler/rustc_target/src/spec/windows_gnu_base.rs | 15 +- .../rustc_target/src/spec/windows_gnullvm_base.rs | 2 +- .../rustc_target/src/spec/x86_64_apple_darwin.rs | 6 +- .../src/spec/x86_64_unknown_l4re_uclibc.rs | 2 - .../rustc_target/src/spec/x86_64_unknown_none.rs | 7 +- compiler/rustc_trait_selection/src/autoderef.rs | 19 +- compiler/rustc_trait_selection/src/errors.rs | 102 + compiler/rustc_trait_selection/src/infer.rs | 17 + compiler/rustc_trait_selection/src/lib.rs | 6 +- .../rustc_trait_selection/src/traits/auto_trait.rs | 20 +- .../rustc_trait_selection/src/traits/codegen.rs | 4 +- .../rustc_trait_selection/src/traits/coherence.rs | 88 +- .../src/traits/const_evaluatable.rs | 4 +- .../rustc_trait_selection/src/traits/engine.rs | 47 +- .../src/traits/error_reporting/mod.rs | 206 +- .../src/traits/error_reporting/on_unimplemented.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 354 +- .../rustc_trait_selection/src/traits/fulfill.rs | 33 +- compiler/rustc_trait_selection/src/traits/misc.rs | 3 +- compiler/rustc_trait_selection/src/traits/mod.rs | 201 +- .../src/traits/object_safety.rs | 28 +- .../src/traits/on_unimplemented.rs | 71 +- .../src/traits/outlives_bounds.rs | 115 + .../rustc_trait_selection/src/traits/project.rs | 211 +- .../src/traits/query/normalize.rs | 57 +- .../src/traits/query/type_op/custom.rs | 15 +- .../src/traits/query/type_op/mod.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 95 +- .../src/traits/select/confirmation.rs | 56 +- .../rustc_trait_selection/src/traits/select/mod.rs | 120 +- .../src/traits/specialize/mod.rs | 51 +- compiler/rustc_trait_selection/src/traits/util.rs | 25 +- compiler/rustc_trait_selection/src/traits/wf.rs | 37 +- compiler/rustc_traits/src/chalk/lowering.rs | 13 +- .../rustc_traits/src/implied_outlives_bounds.rs | 69 +- compiler/rustc_traits/src/lib.rs | 4 +- compiler/rustc_traits/src/type_op.rs | 58 +- compiler/rustc_transmute/Cargo.toml | 5 +- compiler/rustc_transmute/src/layout/dfa.rs | 1 - compiler/rustc_transmute/src/layout/nfa.rs | 6 - compiler/rustc_transmute/src/layout/tree.rs | 36 +- compiler/rustc_transmute/src/lib.rs | 73 +- .../rustc_transmute/src/maybe_transmutable/mod.rs | 6 +- .../src/maybe_transmutable/query_context.rs | 2 +- .../src/maybe_transmutable/tests.rs | 4 +- compiler/rustc_ty_utils/Cargo.toml | 1 + compiler/rustc_ty_utils/src/consts.rs | 195 +- compiler/rustc_ty_utils/src/errors.rs | 69 + compiler/rustc_ty_utils/src/implied_bounds.rs | 61 + compiler/rustc_ty_utils/src/instance.rs | 123 +- compiler/rustc_ty_utils/src/lib.rs | 7 +- compiler/rustc_ty_utils/src/needs_drop.rs | 7 +- compiler/rustc_ty_utils/src/ty.rs | 6 +- compiler/rustc_type_ir/src/lib.rs | 51 +- compiler/rustc_type_ir/src/sty.rs | 105 +- compiler/rustc_typeck/Cargo.toml | 1 + compiler/rustc_typeck/src/astconv/errors.rs | 1 + compiler/rustc_typeck/src/astconv/generics.rs | 7 +- compiler/rustc_typeck/src/astconv/mod.rs | 341 +- compiler/rustc_typeck/src/check/_match.rs | 122 +- compiler/rustc_typeck/src/check/callee.rs | 25 +- compiler/rustc_typeck/src/check/cast.rs | 121 +- compiler/rustc_typeck/src/check/check.rs | 195 +- compiler/rustc_typeck/src/check/closure.rs | 90 +- compiler/rustc_typeck/src/check/coercion.rs | 89 +- compiler/rustc_typeck/src/check/compare_method.rs | 449 ++- compiler/rustc_typeck/src/check/demand.rs | 87 +- compiler/rustc_typeck/src/check/dropck.rs | 2 + compiler/rustc_typeck/src/check/expr.rs | 454 ++- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 90 +- .../rustc_typeck/src/check/fn_ctxt/arg_matrix.rs | 25 +- compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 752 ++-- compiler/rustc_typeck/src/check/fn_ctxt/mod.rs | 14 +- .../rustc_typeck/src/check/fn_ctxt/suggestions.rs | 383 +- .../rustc_typeck/src/check/generator_interior.rs | 26 +- .../generator_interior/drop_ranges/cfg_build.rs | 5 +- .../drop_ranges/record_consumed_borrow.rs | 4 +- compiler/rustc_typeck/src/check/inherited.rs | 30 +- compiler/rustc_typeck/src/check/intrinsic.rs | 28 +- compiler/rustc_typeck/src/check/intrinsicck.rs | 71 +- compiler/rustc_typeck/src/check/method/confirm.rs | 14 +- compiler/rustc_typeck/src/check/method/mod.rs | 62 +- .../rustc_typeck/src/check/method/prelude2021.rs | 1 - compiler/rustc_typeck/src/check/method/probe.rs | 19 +- compiler/rustc_typeck/src/check/method/suggest.rs | 277 +- compiler/rustc_typeck/src/check/mod.rs | 81 +- compiler/rustc_typeck/src/check/op.rs | 505 +-- compiler/rustc_typeck/src/check/pat.rs | 67 +- compiler/rustc_typeck/src/check/region.rs | 43 +- compiler/rustc_typeck/src/check/regionck.rs | 47 - compiler/rustc_typeck/src/check/upvar.rs | 6 +- compiler/rustc_typeck/src/check/wfcheck.rs | 196 +- compiler/rustc_typeck/src/check/writeback.rs | 39 +- compiler/rustc_typeck/src/check_unused.rs | 63 +- compiler/rustc_typeck/src/coherence/builtin.rs | 59 +- compiler/rustc_typeck/src/collect.rs | 178 +- compiler/rustc_typeck/src/collect/item_bounds.rs | 16 +- compiler/rustc_typeck/src/collect/type_of.rs | 149 +- compiler/rustc_typeck/src/errors.rs | 95 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 5 +- compiler/rustc_typeck/src/hir_wf_check.rs | 12 +- .../src/impl_wf_check/min_specialization.rs | 93 +- compiler/rustc_typeck/src/lib.rs | 54 +- compiler/rustc_typeck/src/outlives/mod.rs | 1 - .../rustc_typeck/src/outlives/outlives_bounds.rs | 90 - compiler/rustc_typeck/src/outlives/utils.rs | 6 - .../wrong_number_of_generic_args.rs | 255 +- compiler/rustc_typeck/src/variance/constraints.rs | 14 +- config.toml.example | 8 + debian/bin/rust-lld | 2 +- debian/changelog | 39 + debian/control | 30 +- debian/copyright | 122 +- debian/libstd-rust-1.64.install | 1 - debian/libstd-rust-1.64.lintian-overrides | 13 - debian/libstd-rust-1.65.install | 1 + debian/libstd-rust-1.65.lintian-overrides | 13 + .../patches/d-0000-ignore-removed-submodules.patch | 143 +- debian/patches/d-0004-clippy-feature-sync.patch | 8 +- debian/patches/d-0005-no-jemalloc.patch | 9 +- debian/patches/d-bootstrap-cargo-check-cfg.patch | 2 +- .../d-bootstrap-custom-debuginfo-path.patch | 2 +- debian/patches/d-bootstrap-disable-git.patch | 2 +- .../d-bootstrap-read-beta-version-from-file.patch | 2 +- debian/patches/d-bootstrap-rustflags.patch | 2 +- debian/patches/d-rust-lldb-paths | 2 +- debian/patches/d-rustc-add-soname.patch | 2 +- debian/patches/d-rustc-windows-ssp.patch | 2 +- debian/patches/series | 5 +- ...piler-builtins-add-sync-builtin-fallbacks.patch | 223 -- debian/patches/u-fix-backtrace-tests.patch | 54 + debian/patches/u-ignore-bpf-test.patch | 18 - .../u-make-compiletest-work-without-rpath.patch | 187 + debian/patches/u-rustc-llvm-cross-flags.patch | 2 +- ...constant-eval-to-do-strict-validity-check.patch | 569 --- .../patches/ubuntu-disable-ppc64el-asm-tests.patch | 6 +- debian/rules | 11 +- debian/rust-lldb.links | 2 +- debian/rustc.links | 6 +- debian/upstream-tarball-unsuspicious.txt | 308 +- git-commit-hash | 2 +- library/alloc/src/alloc.rs | 6 +- library/alloc/src/alloc/tests.rs | 2 +- library/alloc/src/boxed.rs | 310 +- library/alloc/src/boxed/thin.rs | 10 + library/alloc/src/collections/binary_heap.rs | 3 +- .../src/collections/btree/dedup_sorted_iter.rs | 4 +- library/alloc/src/collections/btree/map/entry.rs | 11 + library/alloc/src/collections/btree/node.rs | 16 +- library/alloc/src/collections/linked_list.rs | 2 +- library/alloc/src/collections/mod.rs | 4 + library/alloc/src/collections/vec_deque/drain.rs | 44 +- library/alloc/src/collections/vec_deque/mod.rs | 10 +- library/alloc/src/ffi/c_str.rs | 32 +- library/alloc/src/lib.rs | 16 +- library/alloc/src/macros.rs | 2 + library/alloc/src/rc.rs | 2 +- library/alloc/src/slice.rs | 86 +- library/alloc/src/str.rs | 24 +- library/alloc/src/string.rs | 39 +- library/alloc/src/sync.rs | 22 + library/alloc/src/sync/tests.rs | 19 + library/alloc/src/vec/drain.rs | 73 +- library/alloc/src/vec/drain_filter.rs | 60 +- library/alloc/src/vec/in_place_collect.rs | 2 +- library/alloc/src/vec/into_iter.rs | 21 +- library/alloc/src/vec/is_zero.rs | 16 + library/alloc/src/vec/mod.rs | 27 +- library/alloc/src/vec/spec_extend.rs | 2 +- library/alloc/tests/lib.rs | 2 + library/alloc/tests/str.rs | 10 +- library/alloc/tests/string.rs | 126 +- library/alloc/tests/thin_box.rs | 8 +- library/alloc/tests/vec.rs | 276 +- library/alloc/tests/vec_deque.rs | 161 +- library/backtrace/.github/workflows/main.yml | 4 +- library/backtrace/Cargo.toml | 4 +- library/backtrace/src/backtrace/miri.rs | 6 +- library/core/benches/num/int_log/mod.rs | 6 +- library/core/src/alloc/global.rs | 2 +- library/core/src/alloc/layout.rs | 113 +- library/core/src/alloc/mod.rs | 10 + library/core/src/any.rs | 244 +- library/core/src/array/equality.rs | 7 +- library/core/src/array/mod.rs | 13 +- library/core/src/bool.rs | 6 + library/core/src/borrow.rs | 2 +- library/core/src/char/decode.rs | 11 + library/core/src/char/methods.rs | 25 +- library/core/src/char/mod.rs | 10 +- library/core/src/cmp.rs | 34 +- library/core/src/convert/mod.rs | 11 + library/core/src/default.rs | 2 +- library/core/src/error.md | 137 + library/core/src/error.rs | 508 +++ library/core/src/ffi/c_double.md | 4 +- library/core/src/ffi/c_float.md | 4 +- library/core/src/ffi/c_str.rs | 29 +- library/core/src/fmt/builders.rs | 18 +- library/core/src/fmt/mod.rs | 9 +- library/core/src/future/poll_fn.rs | 11 +- library/core/src/hash/mod.rs | 2 +- library/core/src/hint.rs | 21 +- library/core/src/intrinsics.rs | 438 +-- library/core/src/iter/adapters/array_chunks.rs | 182 + library/core/src/iter/adapters/by_ref_sized.rs | 29 +- library/core/src/iter/adapters/flatten.rs | 375 +- library/core/src/iter/adapters/mod.rs | 4 + library/core/src/iter/adapters/skip.rs | 27 +- library/core/src/iter/mod.rs | 2 + library/core/src/iter/traits/iterator.rs | 45 +- library/core/src/lib.rs | 8 +- library/core/src/macros/mod.rs | 53 +- library/core/src/marker.rs | 11 +- library/core/src/mem/maybe_uninit.rs | 10 +- library/core/src/mem/mod.rs | 10 +- library/core/src/mem/transmutability.rs | 86 +- library/core/src/mem/valid_align.rs | 18 +- library/core/src/num/bignum.rs | 2 +- library/core/src/num/dec2flt/decimal.rs | 2 +- library/core/src/num/error.rs | 20 + library/core/src/num/f32.rs | 153 +- library/core/src/num/f64.rs | 153 +- library/core/src/num/int_macros.rs | 116 +- library/core/src/num/mod.rs | 14 +- library/core/src/num/nonzero.rs | 46 +- library/core/src/num/uint_macros.rs | 42 +- library/core/src/ops/drop.rs | 2 +- library/core/src/ops/function.rs | 25 +- library/core/src/ops/generator.rs | 2 +- library/core/src/ops/range.rs | 2 +- library/core/src/ops/try_trait.rs | 84 +- library/core/src/option.rs | 6 + library/core/src/panicking.rs | 4 +- library/core/src/primitive_docs.rs | 72 +- library/core/src/ptr/const_ptr.rs | 107 +- library/core/src/ptr/metadata.rs | 18 - library/core/src/ptr/mod.rs | 18 +- library/core/src/ptr/mut_ptr.rs | 98 +- library/core/src/result.rs | 39 +- library/core/src/slice/ascii.rs | 2 - library/core/src/slice/index.rs | 20 +- library/core/src/slice/iter.rs | 8 +- library/core/src/slice/iter/macros.rs | 18 +- library/core/src/slice/memchr.rs | 37 +- library/core/src/slice/mod.rs | 53 +- library/core/src/slice/raw.rs | 4 +- library/core/src/slice/sort.rs | 36 +- library/core/src/str/error.rs | 20 + library/core/src/str/lossy.rs | 244 +- library/core/src/str/mod.rs | 14 +- library/core/src/str/validations.rs | 4 +- library/core/src/sync/atomic.rs | 80 +- library/core/src/task/wake.rs | 50 +- library/core/src/time.rs | 24 +- library/core/src/tuple.rs | 2 +- library/core/src/unicode/unicode_data.rs | 65 +- library/core/tests/alloc.rs | 44 + library/core/tests/any.rs | 2 +- library/core/tests/atomic.rs | 2 +- library/core/tests/const_ptr.rs | 6 +- library/core/tests/iter/adapters/array_chunks.rs | 179 + library/core/tests/iter/adapters/by_ref_sized.rs | 20 + library/core/tests/iter/adapters/flatten.rs | 42 + library/core/tests/iter/adapters/mod.rs | 24 + library/core/tests/iter/adapters/skip.rs | 31 + library/core/tests/lib.rs | 6 +- library/core/tests/num/int_log.rs | 156 +- library/core/tests/num/int_macros.rs | 26 + library/core/tests/num/uint_macros.rs | 22 + library/core/tests/ptr.rs | 2 +- library/core/tests/result.rs | 9 - library/core/tests/slice.rs | 3 +- library/core/tests/str_lossy.rs | 138 +- library/panic_abort/src/android.rs | 2 +- library/panic_abort/src/lib.rs | 33 +- library/panic_unwind/src/dwarf/eh.rs | 192 - library/panic_unwind/src/dwarf/mod.rs | 73 - library/panic_unwind/src/dwarf/tests.rs | 19 - library/panic_unwind/src/emcc.rs | 16 - library/panic_unwind/src/gcc.rs | 262 -- library/panic_unwind/src/lib.rs | 5 - library/panic_unwind/src/seh.rs | 25 +- .../crates/core_simd/src/masks/to_bitmask.rs | 2 +- library/portable-simd/crates/std_float/src/lib.rs | 6 +- library/proc_macro/src/bridge/client.rs | 2 - library/proc_macro/src/bridge/mod.rs | 29 +- library/proc_macro/src/bridge/server.rs | 39 +- library/proc_macro/src/diagnostic.rs | 21 +- library/proc_macro/src/lib.rs | 7 +- library/rtstartup/rsbegin.rs | 19 +- library/std/Cargo.toml | 4 +- library/std/src/alloc.rs | 5 +- library/std/src/backtrace.rs | 21 +- library/std/src/collections/hash/map.rs | 11 + library/std/src/collections/hash/map/tests.rs | 24 +- library/std/src/collections/hash/set.rs | 2 +- library/std/src/error.rs | 379 +- library/std/src/f32.rs | 2 +- library/std/src/f32/tests.rs | 78 + library/std/src/f64.rs | 2 +- library/std/src/f64/tests.rs | 76 + library/std/src/ffi/os_str.rs | 3 +- library/std/src/fs.rs | 41 +- library/std/src/io/buffered/bufreader.rs | 22 +- library/std/src/io/buffered/bufreader/buffer.rs | 27 +- library/std/src/io/buffered/tests.rs | 58 +- library/std/src/io/copy.rs | 34 +- library/std/src/io/cursor.rs | 10 +- library/std/src/io/error.rs | 11 + library/std/src/io/error/repr_bitpacked.rs | 4 +- library/std/src/io/impls.rs | 22 +- library/std/src/io/mod.rs | 93 +- library/std/src/io/readbuf.rs | 307 +- library/std/src/io/readbuf/tests.rs | 220 +- library/std/src/io/stdio.rs | 51 +- library/std/src/io/tests.rs | 23 +- library/std/src/io/util.rs | 14 +- library/std/src/io/util/tests.rs | 48 +- library/std/src/keyword_docs.rs | 6 +- library/std/src/lib.rs | 34 +- library/std/src/macros.rs | 36 + library/std/src/net/addr.rs | 988 ----- library/std/src/net/addr/tests.rs | 237 -- library/std/src/net/display_buffer.rs | 40 + library/std/src/net/ip.rs | 2040 ---------- library/std/src/net/ip/tests.rs | 969 ----- library/std/src/net/ip_addr.rs | 2095 ++++++++++ library/std/src/net/ip_addr/tests.rs | 1039 +++++ library/std/src/net/mod.rs | 13 +- library/std/src/net/parser.rs | 138 +- library/std/src/net/socket_addr.rs | 974 +++++ library/std/src/net/socket_addr/tests.rs | 306 ++ library/std/src/os/android/mod.rs | 1 + library/std/src/os/android/net.rs | 4 + library/std/src/os/fd/owned.rs | 3 +- library/std/src/os/fd/raw.rs | 8 +- library/std/src/os/fortanix_sgx/mod.rs | 5 +- library/std/src/os/linux/mod.rs | 1 + library/std/src/os/linux/net.rs | 4 + library/std/src/os/mod.rs | 3 + library/std/src/os/net/mod.rs | 7 + library/std/src/os/net/tcp.rs | 70 + library/std/src/os/net/tests.rs | 29 + library/std/src/os/unix/net/addr.rs | 18 +- library/std/src/os/unix/net/datagram.rs | 25 + library/std/src/os/unix/net/listener.rs | 10 +- library/std/src/os/unix/net/stream.rs | 25 + library/std/src/os/wasi/io/fd.rs | 3 +- library/std/src/os/wasi/io/mod.rs | 6 +- library/std/src/os/wasi/io/raw.rs | 18 +- library/std/src/panic.rs | 33 +- library/std/src/path/tests.rs | 5 + library/std/src/personality.rs | 46 + library/std/src/personality/dwarf/eh.rs | 192 + library/std/src/personality/dwarf/mod.rs | 73 + library/std/src/personality/dwarf/tests.rs | 19 + library/std/src/personality/emcc.rs | 20 + library/std/src/personality/gcc.rs | 279 ++ library/std/src/primitive_docs.rs | 72 +- library/std/src/process.rs | 10 +- library/std/src/rt.rs | 31 +- library/std/src/sync/mpsc/mpsc_queue/tests.rs | 2 +- library/std/src/sync/mpsc/spsc_queue/tests.rs | 5 +- library/std/src/sync/mpsc/sync_tests.rs | 21 +- library/std/src/sync/mpsc/tests.rs | 12 +- library/std/src/sync/mutex.rs | 1 + library/std/src/sync/once_lock.rs | 55 - library/std/src/sync/rwlock.rs | 2 + library/std/src/sync/rwlock/tests.rs | 2 +- library/std/src/sys/hermit/condvar.rs | 90 - library/std/src/sys/hermit/fs.rs | 18 +- library/std/src/sys/hermit/futex.rs | 39 + library/std/src/sys/hermit/mod.rs | 17 +- library/std/src/sys/hermit/mutex.rs | 216 -- library/std/src/sys/hermit/net.rs | 2 - library/std/src/sys/hermit/rwlock.rs | 144 - library/std/src/sys/itron/mutex.rs | 6 - library/std/src/sys/sgx/abi/thread.rs | 8 +- library/std/src/sys/sgx/abi/usercalls/alloc.rs | 165 +- library/std/src/sys/sgx/abi/usercalls/mod.rs | 8 +- library/std/src/sys/sgx/abi/usercalls/raw.rs | 24 +- library/std/src/sys/sgx/abi/usercalls/tests.rs | 34 +- library/std/src/sys/sgx/mod.rs | 2 +- library/std/src/sys/sgx/mutex.rs | 3 - library/std/src/sys/solid/fs.rs | 24 +- library/std/src/sys/solid/mod.rs | 2 +- library/std/src/sys/unix/fd.rs | 11 +- library/std/src/sys/unix/fs.rs | 24 +- library/std/src/sys/unix/locks/fuchsia_mutex.rs | 5 +- library/std/src/sys/unix/locks/futex_mutex.rs | 5 +- library/std/src/sys/unix/locks/futex_rwlock.rs | 2 +- library/std/src/sys/unix/locks/pthread_condvar.rs | 2 +- library/std/src/sys/unix/locks/pthread_mutex.rs | 2 +- library/std/src/sys/unix/mod.rs | 42 +- library/std/src/sys/unix/net.rs | 22 + library/std/src/sys/unix/os_str.rs | 40 +- library/std/src/sys/unix/os_str/tests.rs | 8 + library/std/src/sys/unix/process/process_common.rs | 59 +- .../src/sys/unix/process/process_common/tests.rs | 24 + library/std/src/sys/unix/process/process_unix.rs | 4 +- library/std/src/sys/unix/rand.rs | 18 +- library/std/src/sys/unix/thread.rs | 32 +- library/std/src/sys/unix/thread_parker.rs | 281 -- library/std/src/sys/unix/thread_parker/mod.rs | 21 + library/std/src/sys/unix/thread_parker/netbsd.rs | 113 + library/std/src/sys/unix/thread_parker/pthread.rs | 271 ++ library/std/src/sys/unsupported/alloc.rs | 7 +- library/std/src/sys/unsupported/common.rs | 2 +- library/std/src/sys/unsupported/fs.rs | 4 +- library/std/src/sys/unsupported/locks/mutex.rs | 3 - library/std/src/sys/unsupported/process.rs | 3 + library/std/src/sys/wasi/fs.rs | 6 +- library/std/src/sys/wasi/stdio.rs | 23 +- library/std/src/sys/windows/alloc.rs | 5 +- library/std/src/sys/windows/c.rs | 35 +- library/std/src/sys/windows/cmath.rs | 2 +- library/std/src/sys/windows/compat.rs | 232 +- library/std/src/sys/windows/fs.rs | 119 +- library/std/src/sys/windows/handle.rs | 12 +- library/std/src/sys/windows/locks/mutex.rs | 2 - library/std/src/sys/windows/mod.rs | 28 +- library/std/src/sys/windows/os.rs | 6 +- library/std/src/sys/windows/os_str.rs | 4 +- library/std/src/sys/windows/path/tests.rs | 2 +- library/std/src/sys/windows/rand.rs | 121 +- library/std/src/sys/windows/stdio.rs | 41 +- library/std/src/sys/windows/thread_local_dtor.rs | 4 + library/std/src/sys/windows/thread_parker.rs | 22 +- library/std/src/sys_common/net.rs | 8 +- library/std/src/sys_common/remutex.rs | 46 +- library/std/src/sys_common/remutex/tests.rs | 37 +- library/std/src/sys_common/thread_local_key.rs | 2 + .../std/src/sys_common/thread_local_key/tests.rs | 9 +- library/std/src/sys_common/thread_parker/mod.rs | 1 + library/std/src/sys_common/wtf8.rs | 95 +- library/std/src/sys_common/wtf8/tests.rs | 295 +- library/std/src/thread/local.rs | 3 + library/std/src/thread/mod.rs | 85 +- library/std/src/thread/tests.rs | 50 + library/std/src/time/tests.rs | 3 +- library/stdarch/CONTRIBUTING.md | 2 +- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../armv7-unknown-linux-gnueabihf/Dockerfile | 2 +- .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 2 +- library/stdarch/ci/dox.sh | 9 +- library/stdarch/crates/core_arch/Cargo.toml | 1 - library/stdarch/crates/core_arch/build.rs | 3 - .../stdarch/crates/core_arch/src/aarch64/crc.rs | 4 + .../crates/core_arch/src/aarch64/neon/generated.rs | 2538 +++++++++++- .../crates/core_arch/src/aarch64/neon/mod.rs | 74 +- library/stdarch/crates/core_arch/src/arm/neon.rs | 21 + library/stdarch/crates/core_arch/src/arm/v7.rs | 1 - .../stdarch/crates/core_arch/src/arm_shared/crc.rs | 12 + .../crates/core_arch/src/arm_shared/crypto.rs | 28 + .../core_arch/src/arm_shared/neon/generated.rs | 4060 +++++++++++++++++++- .../crates/core_arch/src/arm_shared/neon/mod.rs | 352 +- .../crates/core_arch/src/powerpc/altivec.rs | 5 +- library/stdarch/crates/core_arch/src/x86/avx2.rs | 2 +- .../stdarch/crates/core_arch/src/x86/avx512bw.rs | 16 - .../stdarch/crates/core_arch/src/x86/avx512gfni.rs | 6 +- library/stdarch/crates/core_arch/src/x86/sse.rs | 32 +- library/stdarch/crates/core_arch/src/x86/sse2.rs | 4 +- .../crates/core_arch/src/x86_64/cmpxchg16b.rs | 34 +- .../crates/intrinsic-test/missing_aarch64.txt | 14 - .../stdarch/crates/intrinsic-test/src/argument.rs | 107 +- .../stdarch/crates/intrinsic-test/src/intrinsic.rs | 65 +- library/stdarch/crates/intrinsic-test/src/main.rs | 54 +- library/stdarch/crates/intrinsic-test/src/types.rs | 44 +- .../stdarch/crates/intrinsic-test/src/values.rs | 9 +- .../crates/std_detect/src/detect/arch/aarch64.rs | 3 +- .../stdarch/crates/std_detect/src/detect/macros.rs | 27 +- library/stdarch/crates/stdarch-gen/neon.spec | 24 +- library/stdarch/crates/stdarch-gen/src/main.rs | 55 +- library/stdarch/examples/hex.rs | 27 +- library/test/src/stats.rs | 2 +- library/test/src/term/terminfo/mod.rs | 20 + library/unwind/build.rs | 15 +- library/unwind/src/lib.rs | 20 + src/README.md | 2 +- src/bootstrap/Cargo.lock | 1 - src/bootstrap/Cargo.toml | 2 +- src/bootstrap/bin/rustc.rs | 21 +- src/bootstrap/bin/rustdoc.rs | 11 + src/bootstrap/bootstrap.py | 2 +- src/bootstrap/builder.rs | 44 +- src/bootstrap/builder/tests.rs | 2 - src/bootstrap/check.rs | 2 +- src/bootstrap/compile.rs | 11 +- src/bootstrap/config.rs | 72 +- src/bootstrap/dist.rs | 59 +- src/bootstrap/doc.rs | 2 +- src/bootstrap/flags.rs | 15 +- src/bootstrap/install.rs | 9 - src/bootstrap/lib.rs | 33 +- src/bootstrap/mk/Makefile.in | 11 +- src/bootstrap/native.rs | 107 +- src/bootstrap/run.rs | 22 + src/bootstrap/setup.rs | 2 +- src/bootstrap/tarball.rs | 8 +- src/bootstrap/test.rs | 119 +- src/bootstrap/tool.rs | 28 +- src/bootstrap/toolstate.rs | 1 - src/bootstrap/util.rs | 14 +- src/ci/docker/host-x86_64/arm-android/Dockerfile | 8 +- src/ci/docker/host-x86_64/armhf-gnu/Dockerfile | 2 + src/ci/docker/host-x86_64/dist-android/Dockerfile | 5 +- .../dist-i586-gnu-i586-i686-musl/Dockerfile | 3 +- .../docker/host-x86_64/dist-mips-linux/Dockerfile | 3 +- .../host-x86_64/dist-mips64-linux/Dockerfile | 3 +- .../host-x86_64/dist-mips64el-linux/Dockerfile | 3 +- .../host-x86_64/dist-mipsel-linux/Dockerfile | 3 +- .../docker/host-x86_64/dist-various-2/Dockerfile | 18 +- .../dist-various-2/build-fuchsia-toolchain.sh | 100 +- .../host-x86_64/dist-x86_64-linux/build-clang.sh | 2 +- .../host-x86_64/dist-x86_64-netbsd/Dockerfile | 3 +- src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile | 6 +- src/ci/docker/host-x86_64/i686-gnu/Dockerfile | 6 +- src/ci/docker/host-x86_64/mingw-check/Dockerfile | 12 +- .../host-x86_64/mingw-check/reuse-requirements.in | 22 + .../host-x86_64/mingw-check/reuse-requirements.txt | 145 + src/ci/docker/host-x86_64/test-various/Dockerfile | 4 + src/ci/docker/host-x86_64/wasm32/Dockerfile | 2 + .../docker/host-x86_64/x86_64-gnu-aux/Dockerfile | 6 +- .../docker/host-x86_64/x86_64-gnu-debug/Dockerfile | 3 + .../host-x86_64/x86_64-gnu-distcheck/Dockerfile | 7 +- .../x86_64-gnu-llvm-12-stage1/Dockerfile | 44 - .../host-x86_64/x86_64-gnu-llvm-12/Dockerfile | 53 - .../x86_64-gnu-llvm-13-stage1/Dockerfile | 48 + .../host-x86_64/x86_64-gnu-llvm-13/Dockerfile | 69 + .../docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 14 +- .../x86_64-gnu-tools/browser-ui-test.version | 2 +- .../host-x86_64/x86_64-gnu-tools/checktools.sh | 1 - src/ci/docker/run.sh | 11 +- src/ci/docker/scripts/android-base-apt-get.sh | 1 + src/ci/docker/static/gitconfig | 2 + src/ci/github-actions/ci.yml | 57 +- src/ci/run.sh | 22 + src/ci/scripts/install-clang.sh | 4 + src/doc/book/2018-edition/book.toml | 2 +- .../book/2018-edition/src/theme/2018-edition.css | 9 - src/doc/book/2018-edition/src/theme/index.hbs | 37 - .../ch20-web-server/listing-20-24/src/lib.rs | 4 +- src/doc/book/src/ch01-03-hello-cargo.md | 2 + src/doc/book/src/ch06-02-match.md | 2 +- .../src/ch09-02-recoverable-errors-with-result.md | 2 +- src/doc/book/src/ch20-02-multithreaded.md | 2 +- src/doc/book/src/title-page.md | 4 + src/doc/edition-guide/README.md | 4 +- src/doc/edition-guide/book.toml | 2 +- src/doc/edition-guide/src/SUMMARY.md | 2 +- .../src/editions/creating-a-new-project.md | 48 +- src/doc/edition-guide/src/editions/index.md | 10 +- src/doc/edition-guide/src/introduction.md | 2 +- src/doc/index.md | 2 +- src/doc/nomicon/src/lifetime-mismatch.md | 2 +- src/doc/nomicon/src/lifetimes.md | 2 +- src/doc/nomicon/src/other-reprs.md | 20 +- src/doc/reference/book.toml | 1 + src/doc/reference/src/attributes/testing.md | 3 +- src/doc/reference/src/attributes/type_system.md | 8 + src/doc/reference/src/crates-and-source-files.md | 6 +- src/doc/rust-by-example/book.toml | 1 + src/doc/rust-by-example/src/SUMMARY.md | 2 +- .../src/error/option_unwrap/defaults.md | 12 +- src/doc/rust-by-example/src/flow_control.md | 2 +- src/doc/rust-by-example/src/hello/print.md | 22 +- src/doc/rust-by-example/src/meta.md | 4 +- src/doc/rust-by-example/src/meta/doc.md | 2 +- src/doc/rust-by-example/src/meta/playground.md | 46 + src/doc/rust-by-example/src/meta/playpen.md | 46 - .../src/std_misc/threads/testcase_mapreduce.md | 8 +- src/doc/rustc-dev-guide/book.toml | 2 +- src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 180 +- .../src/backend/backend-agnostic.md | 5 +- src/doc/rustc-dev-guide/src/backend/codegen.md | 19 +- .../rustc-dev-guide/src/backend/updating-llvm.md | 18 +- .../region_inference/member_constraints.md | 2 +- .../rustc-dev-guide/src/building/bootstrapping.md | 29 +- .../rustc-dev-guide/src/building/prerequisites.md | 3 +- src/doc/rustc-dev-guide/src/building/suggested.md | 2 +- src/doc/rustc-dev-guide/src/compiler-debugging.md | 31 +- src/doc/rustc-dev-guide/src/contributing.md | 37 +- src/doc/rustc-dev-guide/src/conventions.md | 4 +- src/doc/rustc-dev-guide/src/crates-io.md | 16 +- .../src/diagnostics/diagnostic-items.md | 79 +- .../src/diagnostics/diagnostic-structs.md | 159 +- .../rustc-dev-guide/src/diagnostics/lintstore.md | 45 +- .../rustc-dev-guide/src/diagnostics/translation.md | 27 +- src/doc/rustc-dev-guide/src/git.md | 12 +- .../src/llvm-coverage-instrumentation.md | 7 +- .../src/opaque-types-type-alias-impl-trait.md | 6 +- src/doc/rustc-dev-guide/src/overview.md | 2 +- src/doc/rustc-dev-guide/src/parallel-rustc.md | 161 +- src/doc/rustc-dev-guide/src/part-5-intro.md | 65 +- src/doc/rustc-dev-guide/src/profiling.md | 2 +- .../queries/query-evaluation-model-in-detail.md | 2 +- src/doc/rustc-dev-guide/src/query.md | 2 +- .../src/rustc-driver-getting-diagnostics.md | 2 +- .../src/rustc-driver-interacting-with-the-ast.md | 2 +- src/doc/rustc-dev-guide/src/rustdoc-internals.md | 2 +- src/doc/rustc-dev-guide/src/salsa.md | 2 +- src/doc/rustc-dev-guide/src/stabilization_guide.md | 26 +- src/doc/rustc-dev-guide/src/test-implementation.md | 1 - src/doc/rustc-dev-guide/src/tests/compiletest.md | 2 +- src/doc/rustc-dev-guide/src/the-parser.md | 17 +- src/doc/rustc-dev-guide/src/thir.md | 163 +- src/doc/rustc-dev-guide/src/traits/chalk.md | 4 +- src/doc/rustc-dev-guide/src/traits/resolution.md | 2 +- src/doc/rustc-dev-guide/src/type-inference.md | 10 +- src/doc/rustc/src/SUMMARY.md | 2 + src/doc/rustc/src/instrument-coverage.md | 28 +- src/doc/rustc/src/linker-plugin-lto.md | 4 +- src/doc/rustc/src/platform-support.md | 10 +- .../armeb-unknown-linux-gnueabi.md | 74 + .../rustc/src/platform-support/armv4t-none-eabi.md | 70 + src/doc/rustc/src/platform-support/fuchsia.md | 689 +++- .../src/platform-support/m68k-unknown-linux-gnu.md | 2 +- src/doc/rustc/src/platform-support/openbsd.md | 2 + .../src/platform-support/pc-windows-gnullvm.md | 2 +- src/doc/rustc/src/platform-support/unknown-uefi.md | 2 +- .../src/platform-support/wasm64-unknown-unknown.md | 2 +- src/doc/rustdoc/book.toml | 4 + .../unstable-book/src/compiler-flags/check-cfg.md | 2 +- .../src/compiler-flags/remap-cwd-prefix.md | 2 +- .../unstable-book/src/compiler-flags/sanitizer.md | 36 +- .../src/language-features/raw-dylib.md | 10 +- .../src/language-features/unix-sigpipe.md | 54 + src/etc/check_missing_items.py | 189 - src/etc/cpu-usage-over-time-plot.sh | 2 +- src/etc/gdb_lookup.py | 3 + src/etc/gdb_providers.py | 11 + src/etc/htmldocck.py | 24 +- src/etc/installer/msi/rust.wxs | 14 - src/etc/installer/pkg/Distribution.xml | 17 - src/etc/lldb_commands | 1 + src/etc/lldb_lookup.py | 3 + src/etc/lldb_providers.py | 8 + src/etc/natvis/intrinsic.natvis | 249 +- src/etc/natvis/liballoc.natvis | 8 - src/etc/pre-push.sh | 2 +- src/etc/rust_types.py | 3 + src/librustdoc/Cargo.toml | 13 +- src/librustdoc/clean/auto_trait.rs | 20 +- src/librustdoc/clean/blanket_impl.rs | 4 +- src/librustdoc/clean/inline.rs | 55 +- src/librustdoc/clean/mod.rs | 1248 +++--- src/librustdoc/clean/types.rs | 142 +- src/librustdoc/clean/utils.rs | 83 +- src/librustdoc/config.rs | 16 +- src/librustdoc/doctest.rs | 9 +- src/librustdoc/fold.rs | 2 +- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/formats/item_type.rs | 1 + src/librustdoc/html/format.rs | 45 +- src/librustdoc/html/highlight.rs | 355 +- .../html/highlight/fixtures/decorations.html | 6 +- .../html/highlight/fixtures/dos_line.html | 2 +- .../html/highlight/fixtures/highlight.html | 8 +- src/librustdoc/html/highlight/fixtures/sample.html | 39 +- src/librustdoc/html/highlight/fixtures/sample.rs | 1 + src/librustdoc/html/highlight/fixtures/union.html | 10 +- src/librustdoc/html/highlight/tests.rs | 18 +- src/librustdoc/html/markdown.rs | 32 +- src/librustdoc/html/render/context.rs | 37 +- src/librustdoc/html/render/mod.rs | 399 +- src/librustdoc/html/render/print_item.rs | 95 +- src/librustdoc/html/render/search_index.rs | 13 +- src/librustdoc/html/render/span_map.rs | 34 +- src/librustdoc/html/render/write_shared.rs | 79 +- src/librustdoc/html/sources.rs | 22 +- src/librustdoc/html/static/css/rustdoc.css | 597 ++- src/librustdoc/html/static/css/themes/ayu.css | 279 +- src/librustdoc/html/static/css/themes/dark.css | 216 +- src/librustdoc/html/static/css/themes/light.css | 214 +- src/librustdoc/html/static/images/down-arrow.svg | 2 +- src/librustdoc/html/static/js/main.js | 89 +- src/librustdoc/html/static/js/search.js | 31 +- src/librustdoc/html/static/js/source-script.js | 20 +- src/librustdoc/html/templates/page.html | 8 +- src/librustdoc/json/conversions.rs | 295 +- src/librustdoc/json/import_finder.rs | 38 + src/librustdoc/json/mod.rs | 38 +- src/librustdoc/lib.rs | 4 +- src/librustdoc/lint.rs | 9 +- src/librustdoc/passes/calculate_doc_coverage.rs | 18 +- src/librustdoc/passes/check_code_block_syntax.rs | 21 +- src/librustdoc/passes/check_doc_test_visibility.rs | 2 +- src/librustdoc/passes/collect_intra_doc_links.rs | 26 +- src/librustdoc/passes/html_tags.rs | 85 +- src/librustdoc/passes/propagate_doc_cfg.rs | 62 +- src/librustdoc/passes/strip_hidden.rs | 8 +- src/librustdoc/passes/strip_private.rs | 10 +- src/librustdoc/passes/stripper.rs | 65 +- src/librustdoc/scrape_examples.rs | 2 +- src/librustdoc/theme.rs | 393 +- src/librustdoc/theme/tests.rs | 120 +- src/librustdoc/visit.rs | 2 +- src/librustdoc/visit_ast.rs | 12 + src/rustdoc-json-types/lib.rs | 160 +- src/rustdoc-json-types/tests.rs | 4 +- src/stage0.json | 568 +-- src/test/assembly/aarch64-pointer-auth.rs | 1 - src/test/assembly/asm/avr-modifiers.rs | 1 - src/test/assembly/asm/avr-types.rs | 1 - src/test/assembly/asm/bpf-types.rs | 1 - src/test/assembly/asm/msp430-types.rs | 1 - src/test/assembly/asm/powerpc-types.rs | 1 - .../stack-protector-target-support.rs | 1 - src/test/assembly/x86_64-floating-point-clamp.rs | 25 + src/test/auxiliary/rust_test_helpers.c | 12 + src/test/codegen/README.md | 22 + src/test/codegen/abi-repr-ext.rs | 46 +- src/test/codegen/asm-may_unwind.rs | 1 - src/test/codegen/async-fn-debug-awaitee-field.rs | 4 +- src/test/codegen/async-fn-debug-msvc.rs | 7 +- src/test/codegen/atomic-operations-llvm-12.rs | 84 - src/test/codegen/atomic-operations.rs | 1 - src/test/codegen/avr/avr-func-addrspace.rs | 2 +- src/test/codegen/branch-protection.rs | 1 - src/test/codegen/debug-vtable.rs | 2 +- src/test/codegen/external-no-mangle-statics.rs | 5 +- src/test/codegen/generator-debug-msvc.rs | 12 +- src/test/codegen/generator-debug.rs | 4 +- src/test/codegen/instrument-coverage.rs | 17 + src/test/codegen/intrinsics/mask.rs | 11 + src/test/codegen/issue-34634.rs | 2 +- src/test/codegen/issue-85872-multiple-reverse.rs | 20 + src/test/codegen/issue-96274.rs | 17 + .../issue-98294-get-mut-copy-from-slice-opt.rs | 19 + src/test/codegen/layout-size-checks.rs | 31 + src/test/codegen/mem-replace-direct-memcpy.rs | 12 - src/test/codegen/merge-functions.rs | 7 +- src/test/codegen/mir-inlined-line-numbers.rs | 25 + src/test/codegen/pic-relocation-model.rs | 7 +- src/test/codegen/pie-relocation-model.rs | 2 +- .../some-abis-do-extend-params-to-32-bits.rs | 204 + src/test/codegen/try_question_mark_nop.rs | 54 + src/test/codegen/unwind-abis/aapcs-unwind-abi.rs | 2 +- .../unwind-abis/c-unwind-abi-panic-abort.rs | 2 +- src/test/codegen/unwind-abis/c-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/cdecl-unwind-abi.rs | 2 +- .../codegen/unwind-abis/fastcall-unwind-abi.rs | 2 +- .../unwind-abis/nounwind-on-stable-panic-abort.rs | 2 +- .../unwind-abis/nounwind-on-stable-panic-unwind.rs | 2 +- src/test/codegen/unwind-abis/nounwind.rs | 2 +- src/test/codegen/unwind-abis/stdcall-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/system-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/sysv64-unwind-abi.rs | 2 +- .../codegen/unwind-abis/thiscall-unwind-abi.rs | 2 +- .../codegen/unwind-abis/vectorcall-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/win64-unwind-abi.rs | 2 +- src/test/codegen/unwind-extern-exports.rs | 2 +- .../debuginfo/collapse-debuginfo-no-attr-flag.rs | 61 + src/test/debuginfo/collapse-debuginfo-no-attr.rs | 60 + .../debuginfo/collapse-debuginfo-with-attr-flag.rs | 63 + src/test/debuginfo/collapse-debuginfo-with-attr.rs | 59 + src/test/debuginfo/generator-objects.rs | 13 +- src/test/debuginfo/msvc-pretty-enums.rs | 212 +- src/test/debuginfo/msvc-scalarpair-params.rs | 8 +- src/test/debuginfo/mutex.rs | 15 +- src/test/debuginfo/numeric-types.rs | 87 +- src/test/debuginfo/pretty-std.rs | 22 +- src/test/debuginfo/result-types.rs | 11 +- src/test/debuginfo/type-names.rs | 34 +- src/test/incremental/hashes/enum_defs.rs | 8 +- src/test/incremental/hashes/trait_defs.rs | 16 +- .../incremental/hygiene/load_cached_hygiene.rs | 2 +- .../issue-100521-change-struct-name-assocty.rs | 65 + src/test/incremental/issue-49043.rs | 2 +- src/test/incremental/split_debuginfo_cached.rs | 4 +- src/test/incremental/split_debuginfo_mode.rs | 8 +- .../thinlto/cgu_invalidated_when_export_added.rs | 2 +- .../thinlto/cgu_invalidated_when_export_removed.rs | 2 +- src/test/mir-opt/README.md | 12 + src/test/mir-opt/array-index-is-temporary.rs | 2 +- ...ain.SimplifyCfg-elaborate-drops.after.32bit.mir | 64 - ...ain.SimplifyCfg-elaborate-drops.after.64bit.mir | 64 - ...rary.main.SimplifyCfg-elaborate-drops.after.mir | 64 + src/test/mir-opt/asm_unwind_panic_abort.rs | 1 - src/test/mir-opt/bool_compare.rs | 2 + .../combine_array_len.norm2.InstCombine.32bit.diff | 77 - .../combine_array_len.norm2.InstCombine.64bit.diff | 77 - .../combine_array_len.norm2.InstCombine.diff | 77 + src/test/mir-opt/combine_array_len.rs | 2 +- ...e_of_primitives.{impl#0}-clone.InstCombine.diff | 74 +- src/test/mir-opt/const_goto.rs | 2 + ...nst_goto_storage.match_nested_if.ConstGoto.diff | 2 +- src/test/mir-opt/const_goto_storage.rs | 2 + ...t_promotion_extern_static.BAR.PromoteTemps.diff | 6 +- ...const_promotion_extern_static.BOP.mir_map.0.mir | 2 +- ...t_promotion_extern_static.FOO.PromoteTemps.diff | 6 +- .../const_prop/aggregate.main.ConstProp.diff | 2 +- src/test/mir-opt/const_prop/aggregate.rs | 1 + .../array_index.main.ConstProp.32bit.diff | 7 +- .../array_index.main.ConstProp.64bit.diff | 7 +- src/test/mir-opt/const_prop/array_index.rs | 1 + .../bad_op_div_by_zero.main.ConstProp.diff | 10 +- src/test/mir-opt/const_prop/bad_op_div_by_zero.rs | 1 + ...unsafe_oob_for_slices.main.ConstProp.32bit.diff | 2 +- ...unsafe_oob_for_slices.main.ConstProp.64bit.diff | 2 +- src/test/mir-opt/const_prop/boolean_identities.rs | 1 + .../mir-opt/const_prop/boxes.main.ConstProp.diff | 13 +- src/test/mir-opt/const_prop/boxes.rs | 1 + .../mir-opt/const_prop/cast.main.ConstProp.diff | 2 +- src/test/mir-opt/const_prop/cast.rs | 1 + .../const_prop/checked_add.main.ConstProp.diff | 2 +- src/test/mir-opt/const_prop/checked_add.rs | 1 + ...const_prop_fails_gracefully.main.ConstProp.diff | 8 +- .../const_prop/const_prop_fails_gracefully.rs | 1 + .../const_prop/control-flow-simplification.rs | 7 +- ...ontrol_flow_simplification.hello.ConstProp.diff | 3 +- .../discriminant.main.ConstProp.32bit.diff | 2 +- .../discriminant.main.ConstProp.64bit.diff | 2 +- src/test/mir-opt/const_prop/discriminant.rs | 1 + .../const_prop/indirect.main.ConstProp.diff | 4 +- src/test/mir-opt/const_prop/indirect.rs | 1 + src/test/mir-opt/const_prop/issue-66971.rs | 1 + src/test/mir-opt/const_prop/issue-67019.rs | 1 + .../const_prop/issue_66971.main.ConstProp.diff | 2 +- .../const_prop/issue_67019.main.ConstProp.diff | 2 +- src/test/mir-opt/const_prop/mult_by_zero.rs | 1 + src/test/mir-opt/const_prop/mutable_variable.rs | 1 + .../const_prop/mutable_variable_aggregate.rs | 1 + .../mutable_variable_aggregate_mut_ref.rs | 1 + ...able_aggregate_partial_read.main.ConstProp.diff | 2 +- .../mutable_variable_aggregate_partial_read.rs | 1 + .../mutable_variable_no_prop.main.ConstProp.diff | 2 +- .../mir-opt/const_prop/mutable_variable_no_prop.rs | 1 + ...able_variable_unprop_assign.main.ConstProp.diff | 5 +- .../const_prop/mutable_variable_unprop_assign.rs | 1 + .../mir-opt/const_prop/optimizes_into_variable.rs | 1 + .../read_immutable_static.main.ConstProp.diff | 4 +- .../mir-opt/const_prop/read_immutable_static.rs | 1 + .../const_prop/ref_deref.main.ConstProp.diff | 2 +- .../const_prop/ref_deref.main.PromoteTemps.diff | 2 +- .../ref_deref_project.main.ConstProp.diff | 4 +- .../ref_deref_project.main.PromoteTemps.diff | 4 +- src/test/mir-opt/const_prop/ref_deref_project.rs | 1 + .../const_prop/slice_len.main.ConstProp.32bit.diff | 2 +- .../const_prop/slice_len.main.ConstProp.64bit.diff | 2 +- ...ance_soundness.retags.DeadStoreElimination.diff | 2 +- src/test/mir-opt/deaggregator_test.rs | 2 + src/test/mir-opt/deaggregator_test_enum.rs | 2 + src/test/mir-opt/deaggregator_test_enum_2.rs | 1 + src/test/mir-opt/deaggregator_test_multiple.rs | 1 + ...ks.is_line_doc_comment_2.DeduplicateBlocks.diff | 89 +- src/test/mir-opt/deduplicate_blocks.rs | 2 + .../mir-opt/derefer_complex_case.main.Derefer.diff | 12 +- src/test/mir-opt/derefer_complex_case.rs | 1 + .../mir-opt/derefer_inline_test.main.Derefer.diff | 4 +- src/test/mir-opt/derefer_inline_test.rs | 1 + .../derefer_terminator_test.main.Derefer.diff | 11 +- src/test/mir-opt/derefer_terminator_test.rs | 1 + src/test/mir-opt/derefer_test.main.Derefer.diff | 4 - src/test/mir-opt/derefer_test.rs | 1 + .../derefer_test_multiple.main.Derefer.diff | 12 - src/test/mir-opt/derefer_test_multiple.rs | 1 + src/test/mir-opt/dest-prop/union.rs | 2 +- src/test/mir-opt/early_otherwise_branch_68867.rs | 5 +- ....before-SimplifyConstCondition-final.after.diff | 344 -- ..._branch_68867.try_sum.EarlyOtherwiseBranch.diff | 36 +- ...soundness.no_downcast.EarlyOtherwiseBranch.diff | 2 - src/test/mir-opt/enum_cast.bar.mir_map.0.mir | 10 +- src/test/mir-opt/enum_cast.boo.mir_map.0.mir | 10 +- src/test/mir-opt/enum_cast.droppy.mir_map.0.mir | 40 +- src/test/mir-opt/enum_cast.foo.mir_map.0.mir | 10 +- src/test/mir-opt/equal_true.rs | 2 + ...al_or.match_tuple.SimplifyCfg-initial.after.mir | 16 +- ...p_cleanup.main-{closure#0}.generator_drop.0.mir | 30 +- ...wind.main-{closure#0}.StateTransform.before.mir | 62 +- ...or_tiny.main-{closure#0}.generator_resume.0.mir | 28 +- src/test/mir-opt/inline/cycle.g.Inline.diff | 28 +- src/test/mir-opt/inline/cycle.main.Inline.diff | 50 +- .../mir-opt/inline/dyn_trait.get_query.Inline.diff | 30 +- .../inline/dyn_trait.try_execute_query.Inline.diff | 12 +- src/test/mir-opt/inline/inline-into-box-place.rs | 2 +- .../inline/inline_any_operand.bar.Inline.after.mir | 22 +- .../inline_closure_captures.foo.Inline.after.mir | 8 +- .../mir-opt/inline/inline_cycle.one.Inline.diff | 2 +- .../mir-opt/inline/inline_cycle.two.Inline.diff | 30 +- .../inline/inline_cycle_generic.main.Inline.diff | 2 +- .../mir-opt/inline/inline_diverging.f.Inline.diff | 2 +- .../mir-opt/inline/inline_diverging.h.Inline.diff | 34 +- .../inline/inline_generator.main.Inline.diff | 90 +- .../inline_into_box_place.main.Inline.32bit.diff | 86 - .../inline_into_box_place.main.Inline.64bit.diff | 86 - .../inline/inline_into_box_place.main.Inline.diff | 82 + .../inline/inline_options.main.Inline.after.mir | 24 +- .../inline/inline_retag.bar.Inline.after.mir | 30 +- .../inline/inline_specialization.main.Inline.diff | 2 +- .../inline_trait_method_2.test2.Inline.after.mir | 12 +- ...e_58867_inline_as_ref_as_mut.b.Inline.after.mir | 4 - ...e_58867_inline_as_ref_as_mut.d.Inline.after.mir | 4 - src/test/mir-opt/inline/polymorphic-recursion.rs | 25 + ...instrument_coverage.bar.InstrumentCoverage.diff | 2 +- ...nstrument_coverage.main.InstrumentCoverage.diff | 12 +- src/test/mir-opt/instrument_coverage.rs | 1 + src/test/mir-opt/issue-101867.rs | 9 + src/test/mir-opt/issue-101973.rs | 20 + src/test/mir-opt/issue-41697.rs | 2 +- src/test/mir-opt/issue-72181.rs | 4 +- src/test/mir-opt/issue-73223.rs | 3 +- src/test/mir-opt/issue-91633.rs | 31 + src/test/mir-opt/issue_101867.main.mir_map.0.mir | 75 + src/test/mir-opt/issue_101973.inner.ConstProp.diff | 100 + ...t#0}.SimplifyCfg-promote-consts.after.32bit.mir | 20 - ...t#0}.SimplifyCfg-promote-consts.after.64bit.mir | 20 - ...onstant#0}.SimplifyCfg-promote-consts.after.mir | 20 + .../mir-opt/issue_72181.bar.mir_map.0.32bit.mir | 17 - .../mir-opt/issue_72181.bar.mir_map.0.64bit.mir | 17 - src/test/mir-opt/issue_72181.bar.mir_map.0.mir | 17 + .../mir-opt/issue_72181.foo.mir_map.0.32bit.mir | 27 - .../mir-opt/issue_72181.foo.mir_map.0.64bit.mir | 27 - src/test/mir-opt/issue_72181.foo.mir_map.0.mir | 27 + .../mir-opt/issue_72181.main.mir_map.0.32bit.mir | 62 - .../mir-opt/issue_72181.main.mir_map.0.64bit.mir | 62 - src/test/mir-opt/issue_72181.main.mir_map.0.mir | 62 + .../mir-opt/issue_73223.main.PreCodegen.32bit.diff | 117 - .../mir-opt/issue_73223.main.PreCodegen.64bit.diff | 117 - ...issue_73223.main.SimplifyArmIdentity.32bit.diff | 157 - ...issue_73223.main.SimplifyArmIdentity.64bit.diff | 157 - .../issue_73223.main.SimplifyArmIdentity.diff | 161 + src/test/mir-opt/issue_91633.bar.mir_map.0.mir | 39 + src/test/mir-opt/issue_91633.foo.mir_map.0.mir | 57 + src/test/mir-opt/issue_91633.fun.mir_map.0.mir | 35 + src/test/mir-opt/issue_91633.hey.mir_map.0.mir | 35 + src/test/mir-opt/issue_99325.main.mir_map.0.mir | 2 +- .../issue_59352.num_to_digit.PreCodegen.after.mir | 4 - .../lower_array_len.array_bound.InstCombine.diff | 66 - ...lower_array_len.array_bound.SimplifyLocals.diff | 70 - ...ower_array_len.array_bound_mut.InstCombine.diff | 79 - ...r_array_len.array_bound_mut.SimplifyLocals.diff | 93 - .../lower_array_len.array_len.InstCombine.diff | 27 - .../lower_array_len.array_len.SimplifyLocals.diff | 22 - ...r_array_len.array_len_by_value.InstCombine.diff | 26 - ...rray_len.array_len_by_value.SimplifyLocals.diff | 22 - src/test/mir-opt/lower_array_len.rs | 11 +- ..._array_len_e2e.array_bound.PreCodegen.after.mir | 49 + ...ay_len_e2e.array_bound_mut.PreCodegen.after.mir | 62 + ...er_array_len_e2e.array_len.PreCodegen.after.mir | 11 + ...len_e2e.array_len_by_value.PreCodegen.after.mir | 11 + src/test/mir-opt/lower_array_len_e2e.rs | 39 + .../lower_intrinsics.align_of.LowerIntrinsics.diff | 2 +- .../lower_intrinsics.assume.LowerIntrinsics.diff | 26 + ...er_intrinsics.discriminant.LowerIntrinsics.diff | 26 +- ...sics.f_copy_nonoverlapping.LowerIntrinsics.diff | 72 + .../lower_intrinsics.f_u64.PreCodegen.before.mir | 32 - .../lower_intrinsics.f_unit.PreCodegen.before.mir | 30 - .../lower_intrinsics.forget.LowerIntrinsics.diff | 2 +- ...lower_intrinsics.non_const.LowerIntrinsics.diff | 2 +- src/test/mir-opt/lower_intrinsics.rs | 54 +- .../lower_intrinsics.size_of.LowerIntrinsics.diff | 2 +- ...wer_intrinsics.unreachable.LowerIntrinsics.diff | 2 +- .../lower_intrinsics.wrapping.LowerIntrinsics.diff | 6 +- ...lower_intrinsics_e2e.f_u64.PreCodegen.after.mir | 32 + ...ower_intrinsics_e2e.f_unit.PreCodegen.after.mir | 30 + src/test/mir-opt/lower_intrinsics_e2e.rs | 32 + ..._edges.full_tested_match.PromoteTemps.after.mir | 2 +- ...anches.bar.MatchBranchSimplification.32bit.diff | 88 - ...anches.bar.MatchBranchSimplification.64bit.diff | 88 - ...uce_branches.bar.MatchBranchSimplification.diff | 88 + ...anches.foo.MatchBranchSimplification.32bit.diff | 30 - ...anches.foo.MatchBranchSimplification.64bit.diff | 30 - ...uce_branches.foo.MatchBranchSimplification.diff | 55 + ...reduce_branches.foo.PreCodegen.before.32bit.mir | 10 - ...reduce_branches.foo.PreCodegen.before.64bit.mir | 10 - ..._nested_if.MatchBranchSimplification.32bit.diff | 42 - ..._nested_if.MatchBranchSimplification.64bit.diff | 42 - ....match_nested_if.MatchBranchSimplification.diff | 113 + src/test/mir-opt/matches_reduce_branches.rs | 5 +- ...tive_match.MatchBranchSimplification.32bit.diff | 28 - ...tive_match.MatchBranchSimplification.64bit.diff | 28 - ...exhaustive_match.MatchBranchSimplification.diff | 32 + ...e_match_i8.MatchBranchSimplification.32bit.diff | 28 - ...e_match_i8.MatchBranchSimplification.64bit.diff | 28 - ...austive_match_i8.MatchBranchSimplification.diff | 32 + src/test/mir-opt/matches_u8.rs | 4 +- .../nll/named_lifetimes_basic.use_x.nll.0.mir | 27 +- .../region_subtyping_basic.main.nll.0.32bit.mir | 23 +- .../region_subtyping_basic.main.nll.0.64bit.mir | 23 +- src/test/mir-opt/not_equal_false.rs | 1 + src/test/mir-opt/packed-struct-drop-aligned.rs | 2 +- ...ain.SimplifyCfg-elaborate-drops.after.32bit.mir | 55 - ...ain.SimplifyCfg-elaborate-drops.after.64bit.mir | 55 - ...gned.main.SimplifyCfg-elaborate-drops.after.mir | 60 + ..._storage_markers.main.RemoveStorageMarkers.diff | 50 +- src/test/mir-opt/remove_storage_markers.rs | 2 + src/test/mir-opt/remove_zsts_dont_touch_unions.rs | 2 +- ...ray_casts.SimplifyCfg-elaborate-drops.after.mir | 16 +- ...losure#0}.SimplifyCfg-elaborate-drops.after.mir | 8 +- ...etag.main.SimplifyCfg-elaborate-drops.after.mir | 25 +- src/test/mir-opt/retag.rs | 1 + ...pl#0}-foo.SimplifyCfg-elaborate-drops.after.mir | 8 +- ...}-foo_shr.SimplifyCfg-elaborate-drops.after.mir | 8 +- .../separate_const_switch.identity.ConstProp.diff | 145 - ...rate_const_switch.identity.PreCodegen.after.mir | 127 - ..._const_switch.identity.SeparateConstSwitch.diff | 35 +- src/test/mir-opt/separate_const_switch.rs | 4 - ...eparate_const_switch.too_complex.ConstProp.diff | 95 - ...e_const_switch.too_complex.PreCodegen.after.mir | 69 - ...nst_switch.too_complex.SeparateConstSwitch.diff | 43 +- src/test/mir-opt/simple-match.rs | 2 +- .../simple_match.match_bool.mir_map.0.32bit.mir | 29 - .../simple_match.match_bool.mir_map.0.64bit.mir | 29 - .../mir-opt/simple_match.match_bool.mir_map.0.mir | 29 + src/test/mir-opt/simplify-arm-identity.rs | 3 + src/test/mir-opt/simplify-arm.rs | 3 + .../simplify-locals-removes-unused-consts.rs | 1 + ...ify-locals-removes-unused-discriminant-reads.rs | 3 +- src/test/mir-opt/simplify-locals.rs | 2 +- .../simplify_arm.id.SimplifyArmIdentity.diff | 46 - .../simplify_arm.id.SimplifyBranchSame.diff | 46 - ...simplify_arm.id_result.SimplifyArmIdentity.diff | 58 - .../simplify_arm.id_result.SimplifyBranchSame.diff | 58 - .../simplify_arm.id_try.SimplifyArmIdentity.diff | 12 +- .../simplify_arm.id_try.SimplifyBranchSame.diff | 12 +- ...rm_identity.main.SimplifyArmIdentity.32bit.diff | 61 - ...rm_identity.main.SimplifyArmIdentity.64bit.diff | 61 - ..._removes_unused_consts.main.SimplifyLocals.diff | 54 +- ...iscriminant_reads.map.SimplifyLocals.32bit.diff | 39 - ...iscriminant_reads.map.SimplifyLocals.64bit.diff | 39 - ...used_discriminant_reads.map.SimplifyLocals.diff | 52 + src/test/mir-opt/simplify_try.rs | 30 - ...fy_try.try_identity.DestinationPropagation.diff | 22 +- ...plify_try.try_identity.SimplifyArmIdentity.diff | 18 +- ...y_try.try_identity.SimplifyBranchSame.after.mir | 18 +- ...plify_try.try_identity.SimplifyLocals.after.mir | 14 +- src/test/mir-opt/slice-drop-shim.rs | 2 +- ...String].AddMovesForPackedDrops.before.32bit.mir | 101 - ...String].AddMovesForPackedDrops.before.64bit.mir | 101 - ...lace.[String].AddMovesForPackedDrops.before.mir | 101 + .../storage_live_dead_in_statics.XXX.mir_map.0.mir | 2 +- src/test/mir-opt/storage_ranges.main.nll.0.mir | 11 +- .../try_identity_e2e.new.PreCodegen.after.mir | 96 + .../try_identity_e2e.old.PreCodegen.after.mir | 53 + src/test/mir-opt/try_identity_e2e.rs | 34 + ...ray_move_out.move_out_by_subslice.mir_map.0.mir | 8 +- ...ted_enum.process_never.SimplifyLocals.after.mir | 2 - ...yCfg-after-uninhabited-enum-branching.after.mir | 24 +- ...um_branching.main.UninhabitedEnumBranching.diff | 34 +- ...yCfg-after-uninhabited-enum-branching.after.mir | 28 +- ...m_branching2.main.UninhabitedEnumBranching.diff | 48 +- .../unreachable.main.UnreachablePropagation.diff | 9 +- ...able_diverging.main.UnreachablePropagation.diff | 25 +- src/test/mir-opt/unusual-item-types.rs | 2 +- ...item_types.E-V-{constant#0}.mir_map.0.32bit.mir | 10 - ...item_types.E-V-{constant#0}.mir_map.0.64bit.mir | 10 - ...usual_item_types.E-V-{constant#0}.mir_map.0.mir | 10 + ...ypes.Test-X-{constructor#0}.mir_map.0.32bit.mir | 12 - ...ypes.Test-X-{constructor#0}.mir_map.0.64bit.mir | 12 - ...item_types.Test-X-{constructor#0}.mir_map.0.mir | 12 + ...ec_i32_.AddMovesForPackedDrops.before.32bit.mir | 39 - ...ec_i32_.AddMovesForPackedDrops.before.64bit.mir | 39 - ...lace.Vec_i32_.AddMovesForPackedDrops.before.mir | 39 + ...impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir | 10 - ...impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir | 10 - ...ypes.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir | 10 + ...let_loops.change_loop_body.ConstProp.32bit.diff | 55 - ...let_loops.change_loop_body.ConstProp.64bit.diff | 55 - ...while_let_loops.change_loop_body.ConstProp.diff | 55 + ...ops.change_loop_body.PreCodegen.after.32bit.mir | 17 - ...ops.change_loop_body.PreCodegen.after.64bit.mir | 17 - ...let_loops.change_loop_body.PreCodegen.after.mir | 17 + src/test/mir-opt/while_let_loops.rs | 1 - src/test/pretty/gat-bounds.rs | 2 - .../run-make-fulldeps/a-b-a-linker-guard/Makefile | 2 +- .../alloc-no-oom-handling/Makefile | 2 +- .../allow-non-lint-warnings-cmdline/Makefile | 2 +- .../allow-warnings-cmdline-stability/Makefile | 2 +- .../archive-duplicate-names/Makefile | 2 +- .../arguments-non-c-like-enum/Makefile | 2 +- .../run-make-fulldeps/atomic-lock-free/Makefile | 2 +- src/test/run-make-fulldeps/bare-outfile/Makefile | 2 +- .../run-make-fulldeps/c-dynamic-dylib/Makefile | 2 +- src/test/run-make-fulldeps/c-dynamic-rlib/Makefile | 2 +- .../c-link-to-rust-dylib/Makefile | 2 +- .../c-link-to-rust-staticlib/Makefile | 2 +- .../c-link-to-rust-va-list-fn/Makefile | 2 +- src/test/run-make-fulldeps/c-static-dylib/Makefile | 2 +- src/test/run-make-fulldeps/c-static-rlib/Makefile | 2 +- .../c-unwind-abi-catch-lib-panic/Makefile | 2 +- .../c-unwind-abi-catch-panic/Makefile | 2 +- .../cat-and-grep-sanity-check/Makefile | 2 +- .../cdylib-fewer-symbols/Makefile | 2 +- .../codegen-options-parsing/Makefile | 2 +- src/test/run-make-fulldeps/compile-stdin/Makefile | 2 +- .../compiler-lookup-paths-2/Makefile | 2 +- .../compiler-lookup-paths/Makefile | 2 +- .../compiler-rt-works-on-mingw/Makefile | 2 +- .../core-no-fp-fmt-parse/Makefile | 2 +- .../run-make-fulldeps/crate-data-smoke/Makefile | 2 +- .../crate-hash-rustc-version/Makefile | 2 +- .../run-make-fulldeps/crate-name-priority/Makefile | 2 +- .../cross-lang-lto-clang/Makefile | 2 +- .../cross-lang-lto-pgo-smoketest/Makefile | 2 +- .../cross-lang-lto-upstream-rlibs/Makefile | 2 +- src/test/run-make-fulldeps/cross-lang-lto/Makefile | 2 +- .../run-make-fulldeps/debug-assertions/Makefile | 2 +- .../dep-info-doesnt-run-much/Makefile | 2 +- .../run-make-fulldeps/dep-info-spaces/Makefile | 2 +- src/test/run-make-fulldeps/dep-info/Makefile | 2 +- src/test/run-make-fulldeps/dylib-chain/Makefile | 2 +- .../run-make-fulldeps/emit-stack-sizes/Makefile | 2 +- src/test/run-make-fulldeps/emit/Makefile | 2 +- .../error-found-staticlib-instead-crate/Makefile | 2 +- .../error-writing-dependencies/Makefile | 2 +- src/test/run-make-fulldeps/exit-code/Makefile | 2 +- .../extern-diff-internal-name/Makefile | 2 +- .../extern-flag-disambiguates/Makefile | 2 +- .../run-make-fulldeps/extern-flag-fun/Makefile | 2 +- .../extern-flag-pathless/Makefile | 2 +- .../extern-flag-rename-transitive/Makefile | 2 +- .../run-make-fulldeps/extern-fn-generic/Makefile | 2 +- .../run-make-fulldeps/extern-fn-mangle/Makefile | 2 +- .../run-make-fulldeps/extern-fn-reachable/Makefile | 2 +- .../extern-fn-struct-passing-abi/Makefile | 2 +- .../extern-fn-with-extern-types/Makefile | 2 +- .../extern-fn-with-packed-struct/Makefile | 2 +- .../extern-fn-with-union/Makefile | 2 +- .../extern-multiple-copies/Makefile | 2 +- .../extern-multiple-copies2/Makefile | 2 +- .../extern-overrides-distribution/Makefile | 2 +- .../extra-filename-with-temp-outputs/Makefile | 2 +- .../foreign-double-unwind/Makefile | 2 +- .../run-make-fulldeps/foreign-exceptions/Makefile | 2 +- src/test/run-make-fulldeps/fpic/Makefile | 2 +- .../glibc-staticlib-args/Makefile | 2 +- src/test/run-make-fulldeps/hir-tree/Makefile | 2 +- .../run-make-fulldeps/include_bytes_deps/Makefile | 2 +- .../incr-add-rust-src-component/Makefile | 2 +- .../inline-always-many-cgu/Makefile | 2 +- .../interdependent-c-libraries/Makefile | 2 +- .../intrinsic-unreachable/Makefile | 2 +- .../run-make-fulldeps/invalid-library/Makefile | 2 +- .../run-make-fulldeps/invalid-staticlib/Makefile | 2 +- src/test/run-make-fulldeps/issue-11908/Makefile | 2 +- src/test/run-make-fulldeps/issue-14500/Makefile | 2 +- src/test/run-make-fulldeps/issue-14698/Makefile | 2 +- src/test/run-make-fulldeps/issue-15460/Makefile | 2 +- src/test/run-make-fulldeps/issue-18943/Makefile | 2 +- src/test/run-make-fulldeps/issue-19371/Makefile | 2 +- src/test/run-make-fulldeps/issue-20626/Makefile | 2 +- src/test/run-make-fulldeps/issue-22131/Makefile | 2 +- src/test/run-make-fulldeps/issue-24445/Makefile | 2 +- src/test/run-make-fulldeps/issue-25581/Makefile | 2 +- src/test/run-make-fulldeps/issue-26006/Makefile | 2 +- src/test/run-make-fulldeps/issue-26092/Makefile | 2 +- src/test/run-make-fulldeps/issue-28595/Makefile | 2 +- src/test/run-make-fulldeps/issue-28766/Makefile | 2 +- src/test/run-make-fulldeps/issue-30063/Makefile | 2 +- src/test/run-make-fulldeps/issue-33329/Makefile | 2 +- src/test/run-make-fulldeps/issue-35164/Makefile | 2 +- src/test/run-make-fulldeps/issue-37839/Makefile | 2 +- src/test/run-make-fulldeps/issue-37893/Makefile | 2 +- src/test/run-make-fulldeps/issue-38237/Makefile | 2 +- src/test/run-make-fulldeps/issue-40535/Makefile | 2 +- src/test/run-make-fulldeps/issue-46239/Makefile | 2 +- src/test/run-make-fulldeps/issue-47551/Makefile | 2 +- .../issue-47551/eh_frame-terminator.rs | 1 - src/test/run-make-fulldeps/issue-51671/Makefile | 2 +- src/test/run-make-fulldeps/issue-53964/Makefile | 2 +- src/test/run-make-fulldeps/issue-64153/Makefile | 4 +- .../issue-68794-textrel-on-minimal-lib/Makefile | 2 +- src/test/run-make-fulldeps/issue-69368/Makefile | 2 +- src/test/run-make-fulldeps/issue-69368/a.rs | 5 + src/test/run-make-fulldeps/issue-7349/Makefile | 2 +- .../issue-84395-lto-embed-bitcode/Makefile | 2 +- .../issue-97463-abi-param-passing/Makefile | 14 + .../issue-97463-abi-param-passing/bad.c | 24 + .../issue-97463-abi-param-passing/param_passing.rs | 38 + src/test/run-make-fulldeps/issue64319/Makefile | 2 +- .../run-make-fulldeps/issues-41478-43796/Makefile | 2 +- .../libs-through-symlinks/Makefile | 2 +- src/test/run-make-fulldeps/libtest-json/Makefile | 2 +- src/test/run-make-fulldeps/link-arg/Makefile | 2 +- .../run-make-fulldeps/link-args-order/Makefile | 2 +- src/test/run-make-fulldeps/link-cfg/Makefile | 2 +- src/test/run-make-fulldeps/link-dedup/Makefile | 2 +- .../run-make-fulldeps/link-path-order/Makefile | 2 +- .../linkage-attr-on-static/Makefile | 2 +- .../long-linker-command-lines-cmd-exe/Makefile | 2 +- .../long-linker-command-lines/Makefile | 2 +- .../run-make-fulldeps/longjmp-across-rust/Makefile | 2 +- src/test/run-make-fulldeps/ls-metadata/Makefile | 2 +- src/test/run-make-fulldeps/lto-dylib-dep/Makefile | 2 +- src/test/run-make-fulldeps/lto-empty/Makefile | 2 +- .../lto-no-link-whole-rlib/Makefile | 2 +- .../run-make-fulldeps/lto-readonly-lib/Makefile | 2 +- src/test/run-make-fulldeps/lto-smoke-c/Makefile | 2 +- src/test/run-make-fulldeps/lto-smoke/Makefile | 2 +- .../run-make-fulldeps/manual-crate-name/Makefile | 2 +- src/test/run-make-fulldeps/manual-link/Makefile | 2 +- .../many-crates-but-no-match/Makefile | 2 +- .../metadata-flag-frobs-symbols/Makefile | 2 +- .../run-make-fulldeps/min-global-align/Makefile | 2 +- .../mismatching-target-triples/Makefile | 2 +- .../missing-crate-dependency/Makefile | 2 +- src/test/run-make-fulldeps/mixing-deps/Makefile | 2 +- src/test/run-make-fulldeps/mixing-formats/Makefile | 2 +- src/test/run-make-fulldeps/mixing-libs/Makefile | 2 +- .../run-make-fulldeps/msvc-opt-minsize/Makefile | 2 +- src/test/run-make-fulldeps/multiple-emits/Makefile | 2 +- .../run-make-fulldeps/no-builtins-lto/Makefile | 2 +- .../run-make-fulldeps/no-duplicate-libs/Makefile | 2 +- .../no-intermediate-extras/Makefile | 2 +- .../obey-crate-type-flag/Makefile | 2 +- .../Makefile | 2 +- .../output-filename-overwrites-input/Makefile | 2 +- .../output-type-permutations/Makefile | 2 +- .../run-make-fulldeps/output-with-hyphens/Makefile | 2 +- .../override-aliased-flags/Makefile | 2 +- .../panic-impl-transitive/Makefile | 2 +- .../pass-non-c-like-enum-to-c/Makefile | 2 +- .../run-make-fulldeps/pgo-branch-weights/Makefile | 2 +- src/test/run-make-fulldeps/pgo-gen-lto/Makefile | 2 +- .../pgo-gen-no-imp-symbols/Makefile | 2 +- src/test/run-make-fulldeps/pgo-gen/Makefile | 2 +- .../pgo-indirect-call-promotion/Makefile | 2 +- src/test/run-make-fulldeps/pgo-use/Makefile | 2 +- .../pointer-auth-link-with-c/Makefile | 2 +- src/test/run-make-fulldeps/prefer-dylib/Makefile | 2 +- src/test/run-make-fulldeps/prefer-rlib/Makefile | 2 +- .../run-make-fulldeps/pretty-expanded/Makefile | 2 +- .../pretty-print-to-file/Makefile | 2 +- src/test/run-make-fulldeps/print-cfg/Makefile | 2 +- .../run-make-fulldeps/print-target-list/Makefile | 2 +- src/test/run-make-fulldeps/profile/Makefile | 2 +- .../run-make-fulldeps/prune-link-args/Makefile | 2 +- src/test/run-make-fulldeps/redundant-libs/Makefile | 2 +- .../run-make-fulldeps/relocation-model/Makefile | 2 +- src/test/run-make-fulldeps/relro-levels/Makefile | 2 +- .../run-make-fulldeps/remap-path-prefix/Makefile | 2 +- .../reproducible-build-2/Makefile | 2 +- .../run-make-fulldeps/reproducible-build/Makefile | 2 +- src/test/run-make-fulldeps/resolve-rename/Makefile | 2 +- .../return-non-c-like-enum-from-c/Makefile | 2 +- .../return-non-c-like-enum/Makefile | 2 +- src/test/run-make-fulldeps/rlib-chain/Makefile | 2 +- .../run-make-fulldeps/rustdoc-determinism/Makefile | 2 +- .../run-make-fulldeps/rustdoc-error-lines/Makefile | 2 +- .../run-make-fulldeps/rustdoc-io-error/Makefile | 2 +- .../run-make-fulldeps/rustdoc-map-file/Makefile | 2 +- .../run-make-fulldeps/rustdoc-output-path/Makefile | 2 +- .../rustdoc-scrape-examples-macros/Makefile | 2 +- src/test/run-make-fulldeps/rustdoc-themes/Makefile | 2 +- .../sanitizer-cdylib-link/Makefile | 2 +- .../sanitizer-dylib-link/Makefile | 2 +- .../sanitizer-staticlib-link/Makefile | 2 +- .../run-make-fulldeps/save-analysis-fail/Makefile | 2 +- .../run-make-fulldeps/save-analysis-fail/foo.rs | 15 +- .../save-analysis-rfc2126/Makefile | 2 +- src/test/run-make-fulldeps/save-analysis/Makefile | 2 +- src/test/run-make-fulldeps/save-analysis/foo.rs | 15 +- .../run-make-fulldeps/separate-link-fail/Makefile | 2 +- src/test/run-make-fulldeps/separate-link/Makefile | 2 +- .../run-make-fulldeps/sepcomp-cci-copies/Makefile | 2 +- .../run-make-fulldeps/sepcomp-inlining/Makefile | 2 +- .../run-make-fulldeps/sepcomp-separate/Makefile | 2 +- .../share-generics-dylib/Makefile | 2 +- src/test/run-make-fulldeps/simd-ffi/Makefile | 2 +- src/test/run-make-fulldeps/simple-dylib/Makefile | 2 +- src/test/run-make-fulldeps/simple-rlib/Makefile | 2 +- .../run-make-fulldeps/split-debuginfo/Makefile | 41 +- .../run-make-fulldeps/stable-symbol-names/Makefile | 2 +- .../static-dylib-by-default/Makefile | 2 +- .../run-make-fulldeps/static-extern-type/Makefile | 2 +- .../run-make-fulldeps/static-unwinding/Makefile | 2 +- .../run-make-fulldeps/staticlib-blank-lib/Makefile | 2 +- src/test/run-make-fulldeps/std-core-cycle/Makefile | 2 +- src/test/run-make-fulldeps/stdin-non-utf8/Makefile | 2 +- .../run-make-fulldeps/suspicious-library/Makefile | 2 +- .../symbols-include-type-name/Makefile | 2 +- .../run-make-fulldeps/symlinked-extern/Makefile | 2 +- .../run-make-fulldeps/symlinked-libraries/Makefile | 2 +- src/test/run-make-fulldeps/symlinked-rlib/Makefile | 2 +- .../run-make-fulldeps/target-cpu-native/Makefile | 2 +- src/test/run-make-fulldeps/target-specs/Makefile | 2 +- .../target-without-atomic-cas/Makefile | 2 +- src/test/run-make-fulldeps/test-harness/Makefile | 2 +- .../type-mismatch-same-crate-name/Makefile | 2 +- .../use-extern-for-plugins/Makefile | 2 +- .../use-suggestions-rust-2018/Makefile | 2 +- .../run-make-fulldeps/used-cdylib-macos/Makefile | 2 +- src/test/run-make-fulldeps/used/Makefile | 2 +- src/test/run-make-fulldeps/version/Makefile | 2 +- .../run-make-fulldeps/volatile-intrinsics/Makefile | 2 +- .../weird-output-filenames/Makefile | 2 +- .../windows-binary-no-external-deps/Makefile | 2 +- src/test/run-make-fulldeps/windows-spawn/Makefile | 2 +- .../run-make-fulldeps/windows-subsystem/Makefile | 2 +- src/test/run-make/const_fn_mir/Makefile | 2 +- .../coverage-llvmir/filecheck.testprog.txt | 2 +- src/test/run-make/coverage-reports/Makefile | 6 +- .../expected_show_coverage.async.txt | 2 +- .../expected_show_coverage.closure.txt | 16 +- .../expected_show_coverage.doctest.txt | 6 - .../expected_show_coverage.generator.txt | 2 +- .../expected_show_coverage.inline-dead.txt | 2 +- .../expected_show_coverage.issue-83601.txt | 6 - .../expected_show_coverage.issue-84561.txt | 6 - .../expected_show_coverage.partial_eq.txt | 5 - .../expected_show_coverage.uses_inline_crate.txt | 4 +- .../expected_show_coverage.yield.txt | 4 +- src/test/run-make/coverage/async.rs | 2 +- src/test/run-make/dep-graph/Makefile | 2 +- src/test/run-make/emit-named-files/Makefile | 2 +- src/test/run-make/emit-path-unhashed/Makefile | 2 +- src/test/run-make/emit-shared-files/Makefile | 2 +- src/test/run-make/env-dep-info/Makefile | 2 +- .../run-make/export-executable-symbols/Makefile | 2 +- src/test/run-make/fmt-write-bloat/Makefile | 2 +- src/test/run-make/issue-10971-temps-dir/Makefile | 2 +- src/test/run-make/issue-47384/Makefile | 2 +- src/test/run-make/issue-71519/Makefile | 3 +- src/test/run-make/issue-85401-static-mir/Makefile | 16 + src/test/run-make/issue-85401-static-mir/bar.rs | 4 + src/test/run-make/issue-85401-static-mir/baz.rs | 3 + src/test/run-make/issue-85401-static-mir/foo.rs | 5 + src/test/run-make/issue-85441/Makefile | 2 +- .../run-make/issue-88756-default-output/Makefile | 2 +- src/test/run-make/issue-96498/Makefile | 2 +- src/test/run-make/libtest-thread-limit/Makefile | 2 +- src/test/run-make/llvm-outputs/Makefile | 2 +- .../run-make/native-link-modifier-bundle/Makefile | 2 +- .../native-link-modifier-whole-archive/Makefile | 2 +- .../run-make/pass-linker-flags-from-dep/Makefile | 2 +- src/test/run-make/pass-linker-flags/Makefile | 2 +- .../raw-dylib-alt-calling-convention/Makefile | 2 +- .../raw-dylib-alt-calling-convention/extern.c | 15 + .../raw-dylib-alt-calling-convention/lib.rs | 11 +- .../output.msvc.txt | 1 + .../raw-dylib-alt-calling-convention/output.txt | 2 + src/test/run-make/raw-dylib-c/Makefile | 2 +- src/test/run-make/raw-dylib-c/extern_1.c | 12 + src/test/run-make/raw-dylib-c/lib.rs | 13 +- src/test/run-make/raw-dylib-c/output.txt | 3 + .../run-make/raw-dylib-import-name-type/Makefile | 22 + .../run-make/raw-dylib-import-name-type/driver.rs | 125 + .../run-make/raw-dylib-import-name-type/extern.c | 103 + .../raw-dylib-import-name-type/extern.gnu.def | 21 + .../raw-dylib-import-name-type/extern.msvc.def | 25 + .../run-make/raw-dylib-import-name-type/output.txt | 19 + .../run-make/raw-dylib-inline-cross-dylib/Makefile | 31 + .../raw-dylib-inline-cross-dylib/driver.rs | 21 + .../raw-dylib-inline-cross-dylib/extern_1.c | 11 + .../raw-dylib-inline-cross-dylib/extern_2.c | 6 + .../run-make/raw-dylib-inline-cross-dylib/lib.rs | 21 + .../raw-dylib-inline-cross-dylib/lib_wrapper.rs | 6 + .../raw-dylib-inline-cross-dylib/output.txt | 6 + src/test/run-make/raw-dylib-link-ordinal/Makefile | 2 +- .../run-make/raw-dylib-link-ordinal/exporter.c | 7 + .../run-make/raw-dylib-link-ordinal/exporter.def | 2 + src/test/run-make/raw-dylib-link-ordinal/lib.rs | 10 +- .../run-make/raw-dylib-link-ordinal/output.txt | 2 + .../run-make/raw-dylib-stdcall-ordinal/Makefile | 2 +- src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs | 2 +- src/test/run-make/remap-path-prefix-dwarf/Makefile | 2 +- .../rlib-format-packed-bundled-libs-2/Makefile | 22 + .../rlib-format-packed-bundled-libs-2/main.rs | 5 + .../native_dep.rs | 4 + .../rlib-format-packed-bundled-libs-2/rust_dep.rs | 11 + .../rlib-format-packed-bundled-libs/Makefile | 34 + .../rlib-format-packed-bundled-libs/main.rs | 4 + .../rlib-format-packed-bundled-libs/native_dep_1.c | 1 + .../rlib-format-packed-bundled-libs/native_dep_2.c | 1 + .../rlib-format-packed-bundled-libs/native_dep_3.c | 1 + .../rust_dep_local.rs | 13 + .../rlib-format-packed-bundled-libs/rust_dep_up.rs | 13 + src/test/run-make/rustc-macro-dep-files/Makefile | 2 +- .../rustdoc-scrape-examples-invalid-expr/Makefile | 2 +- .../rustdoc-scrape-examples-multiple/Makefile | 2 +- .../rustdoc-scrape-examples-multiple/scrape.mk | 2 +- .../rustdoc-scrape-examples-ordering/Makefile | 2 +- .../rustdoc-scrape-examples-remap/Makefile | 2 +- .../run-make/rustdoc-scrape-examples-test/Makefile | 2 +- .../rustdoc-scrape-examples-whitespace/Makefile | 2 +- .../run-make/rustdoc-with-out-dir-option/Makefile | 2 +- .../run-make/rustdoc-with-output-option/Makefile | 2 +- .../rustdoc-with-short-out-dir-option/Makefile | 2 +- src/test/run-make/static-pie/Makefile | 2 +- src/test/run-make/thumb-none-cortex-m/Makefile | 2 +- src/test/run-make/thumb-none-qemu/Makefile | 2 +- src/test/run-make/track-path-dep-info/Makefile | 2 +- src/test/run-make/track-pgo-dep-info/Makefile | 26 + src/test/run-make/track-pgo-dep-info/main.rs | 1 + src/test/run-make/translation/Makefile | 25 +- .../run-make/translation/basic-translation.ftl | 2 - src/test/run-make/translation/basic-translation.rs | 18 - src/test/run-make/translation/broken.ftl | 3 + src/test/run-make/translation/missing.ftl | 3 + src/test/run-make/translation/test.rs | 18 + src/test/run-make/translation/working.ftl | 2 + src/test/run-make/unstable-flag-required/Makefile | 2 +- src/test/run-make/wasm-abi/Makefile | 2 +- src/test/run-make/wasm-custom-section/Makefile | 2 +- .../run-make/wasm-custom-sections-opt/Makefile | 2 +- src/test/run-make/wasm-export-all-symbols/Makefile | 2 +- src/test/run-make/wasm-import-module/Makefile | 2 +- src/test/run-make/wasm-panic-small/Makefile | 2 +- src/test/run-make/wasm-spurious-import/Makefile | 2 +- .../run-make/wasm-stringify-ints-small/Makefile | 2 +- .../wasm-symbols-different-module/Makefile | 2 +- .../run-make/wasm-symbols-not-exported/Makefile | 2 +- .../run-make/wasm-symbols-not-imported/Makefile | 2 +- .../x86_64-fortanix-unknown-sgx-lvi/Makefile | 2 +- .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 2 +- src/test/run-pass-valgrind/cast-enum-with-dtor.rs | 2 +- .../run-pass-valgrind/cleanup-auto-borrow-obj.rs | 4 +- src/test/run-pass-valgrind/coerce-match.rs | 15 +- src/test/rustdoc-gui/anchors.goml | 128 +- src/test/rustdoc-gui/check_info_sign_position.goml | 8 +- src/test/rustdoc-gui/code-tags.goml | 4 +- src/test/rustdoc-gui/codeblock-tooltip.goml | 96 + src/test/rustdoc-gui/docblock-table-overflow.goml | 4 +- src/test/rustdoc-gui/docblock-table.goml | 4 + src/test/rustdoc-gui/headings.goml | 6 +- src/test/rustdoc-gui/item-info-alignment.goml | 10 + src/test/rustdoc-gui/item-summary-table.goml | 2 +- src/test/rustdoc-gui/label-next-to-symbol.goml | 26 +- src/test/rustdoc-gui/links-color.goml | 85 + .../rustdoc-gui/overflow-tooltip-information.goml | 2 +- src/test/rustdoc-gui/pocket-menu.goml | 4 +- src/test/rustdoc-gui/search-filter.goml | 18 +- src/test/rustdoc-gui/search-form-elements.goml | 243 ++ src/test/rustdoc-gui/search-input.goml | 23 - src/test/rustdoc-gui/search-result-color.goml | 204 +- src/test/rustdoc-gui/search-result-display.goml | 31 +- src/test/rustdoc-gui/sidebar-mobile-scroll.goml | 31 + .../rustdoc-gui/sidebar-source-code-display.goml | 15 +- src/test/rustdoc-gui/src/lib2/lib.rs | 40 + src/test/rustdoc-gui/src/staged_api/Cargo.toml | 3 +- src/test/rustdoc-gui/src/staged_api/lib.rs | 2 + src/test/rustdoc-gui/src/test_docs/lib.rs | 32 + src/test/rustdoc-gui/toggle-click-deadspace.goml | 5 +- src/test/rustdoc-gui/type-declation-overflow.goml | 4 +- src/test/rustdoc-gui/where-whitespace.goml | 27 + src/test/rustdoc-json/assoc_items.rs | 32 +- src/test/rustdoc-json/assoc_type.rs | 9 +- src/test/rustdoc-json/blanket_impls.rs | 7 +- src/test/rustdoc-json/doc_hidden_failure.rs | 2 +- src/test/rustdoc-json/enums/discriminant/basic.rs | 12 + src/test/rustdoc-json/enums/discriminant/expr.rs | 39 + src/test/rustdoc-json/enums/discriminant/limits.rs | 43 + .../discriminant/num_underscore_and_suffix.rs | 15 + .../discriminant/only_some_have_discriminant.rs | 10 + src/test/rustdoc-json/enums/field_hidden.rs | 13 + src/test/rustdoc-json/enums/kind.rs | 37 + src/test/rustdoc-json/enums/struct_field_hidden.rs | 17 + src/test/rustdoc-json/enums/tuple_fields_hidden.rs | 94 + src/test/rustdoc-json/enums/variant_struct.rs | 10 +- .../rustdoc-json/enums/variant_tuple_struct.rs | 10 +- src/test/rustdoc-json/fn_pointer/abi.rs | 14 +- src/test/rustdoc-json/fn_pointer/generics.rs | 16 +- src/test/rustdoc-json/fn_pointer/qualifiers.rs | 12 +- src/test/rustdoc-json/fns/abi.rs | 14 +- src/test/rustdoc-json/fns/async_return.rs | 36 + src/test/rustdoc-json/fns/generic_args.rs | 96 +- src/test/rustdoc-json/fns/generic_returns.rs | 12 +- src/test/rustdoc-json/fns/generics.rs | 32 +- src/test/rustdoc-json/fns/qualifiers.rs | 36 +- .../rustdoc-json/generic-associated-types/gats.rs | 42 +- src/test/rustdoc-json/generic_impl.rs | 7 +- src/test/rustdoc-json/glob_import.rs | 5 +- src/test/rustdoc-json/impls/auto.rs | 18 + .../rustdoc-json/impls/auxiliary/foreign_struct.rs | 1 + .../rustdoc-json/impls/auxiliary/foreign_trait.rs | 1 + src/test/rustdoc-json/impls/blanket_with_local.rs | 8 +- src/test/rustdoc-json/impls/foreign_for_local.rs | 18 + src/test/rustdoc-json/impls/import_from_private.rs | 22 + src/test/rustdoc-json/impls/local_for_foreign.rs | 18 + src/test/rustdoc-json/impls/local_for_local.rs | 15 + .../impls/local_for_local_primitive.rs | 21 + src/test/rustdoc-json/impls/local_for_primitive.rs | 7 + src/test/rustdoc-json/intra-doc-links/non_page.rs | 34 + .../rustdoc-json/intra-doc-links/user_written.rs | 8 + src/test/rustdoc-json/keyword.rs | 9 +- src/test/rustdoc-json/lifetime/longest.rs | 40 +- src/test/rustdoc-json/lifetime/outlives.rs | 34 +- src/test/rustdoc-json/methods/abi.rs | 30 +- src/test/rustdoc-json/methods/qualifiers.rs | 36 +- src/test/rustdoc-json/nested.rs | 39 +- src/test/rustdoc-json/output_generics.rs | 11 +- src/test/rustdoc-json/primitive.rs | 18 +- src/test/rustdoc-json/primitive_overloading.rs | 5 +- src/test/rustdoc-json/primitives.rs | 22 +- .../reexport/export_extern_crate_as_self.rs | 11 + src/test/rustdoc-json/reexport/glob_collision.rs | 28 + src/test/rustdoc-json/reexport/glob_empty_mod.rs | 8 + src/test/rustdoc-json/reexport/glob_extern.rs | 15 +- src/test/rustdoc-json/reexport/glob_private.rs | 25 +- src/test/rustdoc-json/reexport/in_root_and_mod.rs | 9 +- .../rustdoc-json/reexport/in_root_and_mod_pub.rs | 16 +- src/test/rustdoc-json/reexport/macro.rs | 10 +- src/test/rustdoc-json/reexport/mod_not_included.rs | 14 + .../reexport/private_twice_one_inline.rs | 18 +- .../rustdoc-json/reexport/private_two_names.rs | 17 +- src/test/rustdoc-json/reexport/rename_private.rs | 7 +- src/test/rustdoc-json/reexport/rename_public.rs | 16 +- .../same_type_reexported_more_than_once.rs | 18 +- src/test/rustdoc-json/reexport/simple_private.rs | 11 +- src/test/rustdoc-json/reexport/simple_public.rs | 14 +- src/test/rustdoc-json/return_private.rs | 4 +- src/test/rustdoc-json/stripped_modules.rs | 10 +- src/test/rustdoc-json/structs/plain_all_pub.rs | 11 + src/test/rustdoc-json/structs/plain_doc_hidden.rs | 11 + src/test/rustdoc-json/structs/plain_empty.rs | 9 +- src/test/rustdoc-json/structs/plain_pub_priv.rs | 9 + src/test/rustdoc-json/structs/tuple.rs | 7 +- src/test/rustdoc-json/structs/tuple_empty.rs | 2 + src/test/rustdoc-json/structs/tuple_pub_priv.rs | 13 + src/test/rustdoc-json/structs/unit.rs | 7 +- src/test/rustdoc-json/structs/with_generics.rs | 16 +- src/test/rustdoc-json/structs/with_primitives.rs | 12 +- src/test/rustdoc-json/traits/has_body.rs | 16 +- src/test/rustdoc-json/traits/implementors.rs | 14 +- src/test/rustdoc-json/traits/supertrait.rs | 22 +- src/test/rustdoc-json/traits/uses_extern_trait.rs | 7 + src/test/rustdoc-json/type/dyn.rs | 59 +- src/test/rustdoc-json/type/extern.rs | 10 + src/test/rustdoc-json/type/fn_lifetime.rs | 41 +- src/test/rustdoc-json/type/generic_default.rs | 46 +- src/test/rustdoc-json/type/hrtb.rs | 24 + src/test/rustdoc-json/unions/impl.rs | 10 +- src/test/rustdoc-json/unions/union.rs | 14 +- src/test/rustdoc-ui/check-fail.rs | 1 + src/test/rustdoc-ui/check-fail.stderr | 12 +- src/test/rustdoc-ui/check.rs | 4 +- src/test/rustdoc-ui/check.stderr | 18 +- src/test/rustdoc-ui/doc-without-codeblock.rs | 3 +- src/test/rustdoc-ui/doc-without-codeblock.stderr | 12 +- ...ature-gate-rustdoc_missing_doc_code_examples.rs | 10 + ...e-gate-rustdoc_missing_doc_code_examples.stderr | 29 + .../intra-doc/unknown-disambiguator.stderr | 12 +- src/test/rustdoc-ui/invalid-html-tags.rs | 7 + src/test/rustdoc-ui/invalid-html-tags.stderr | 8 +- src/test/rustdoc-ui/issue-101076.rs | 14 + src/test/rustdoc-ui/lint-group.rs | 2 + src/test/rustdoc-ui/lint-group.stderr | 12 +- .../rustdoc-ui/lint-missing-doc-code-example.rs | 1 + .../lint-missing-doc-code-example.stderr | 12 +- src/test/rustdoc-ui/normalize-cycle.rs | 2 +- src/test/rustdoc-ui/rustc-check-passes.rs | 4 +- src/test/rustdoc-ui/rustc-check-passes.stderr | 6 +- .../suggestions/html-as-generics-no-suggestions.rs | 42 + .../html-as-generics-no-suggestions.stderr | 48 +- .../rustdoc-ui/suggestions/html-as-generics.fixed | 40 + .../rustdoc-ui/suggestions/html-as-generics.rs | 40 + .../rustdoc-ui/suggestions/html-as-generics.stderr | 90 +- src/test/rustdoc-ui/z-help.stdout | 3 + src/test/rustdoc/all.rs | 2 +- src/test/rustdoc/anchors.no_const_anchor.html | 2 +- src/test/rustdoc/anchors.no_const_anchor2.html | 2 +- src/test/rustdoc/anchors.no_method_anchor.html | 2 +- .../rustdoc/anchors.no_trait_method_anchor.html | 2 +- src/test/rustdoc/anchors.no_tymethod_anchor.html | 2 +- src/test/rustdoc/anchors.no_type_anchor.html | 2 +- src/test/rustdoc/assoc-consts.rs | 8 +- .../rustdoc/auxiliary/incoherent-impl-types.rs | 7 + src/test/rustdoc/cfg_doc_reexport.rs | 33 + .../rustdoc/check-source-code-urls-to-def-std.rs | 8 +- src/test/rustdoc/check-source-code-urls-to-def.rs | 22 +- src/test/rustdoc/codeblock-title.rs | 6 +- src/test/rustdoc/const-display.rs | 6 +- .../rustdoc/const-generics/const-generics-docs.rs | 8 +- src/test/rustdoc/deprecated-impls.rs | 36 +- src/test/rustdoc/doc_auto_cfg_nested_impl.rs | 24 + src/test/rustdoc/elided-lifetime.rs | 14 +- .../rustdoc/empty-impl-block-private-with-doc.rs | 44 + src/test/rustdoc/empty-impl-block-private.rs | 40 + src/test/rustdoc/empty-mod-private.rs | 6 +- src/test/rustdoc/empty-mod-public.rs | 6 +- src/test/rustdoc/empty-section.rs | 2 +- src/test/rustdoc/ensure-src-link.rs | 2 +- src/test/rustdoc/generic-associated-types/gats.rs | 5 +- .../generic-associated-types/issue-94683.rs | 5 +- src/test/rustdoc/glob-shadowing-const.rs | 20 + src/test/rustdoc/glob-shadowing.rs | 86 + src/test/rustdoc/hidden-impls.rs | 4 +- src/test/rustdoc/hidden-line.rs | 2 +- src/test/rustdoc/hidden-methods.rs | 8 +- src/test/rustdoc/hide-unstable-trait.rs | 4 +- src/test/rustdoc/higher-ranked-trait-bounds.rs | 8 +- src/test/rustdoc/impl-parts-crosscrate.rs | 8 +- src/test/rustdoc/impl-parts.rs | 4 +- src/test/rustdoc/impl-trait-alias.rs | 4 +- src/test/rustdoc/impossible-default.rs | 20 + src/test/rustdoc/infinite-redirection.rs | 2 +- src/test/rustdoc/inline_cross/add-docs.rs | 2 +- src/test/rustdoc/inline_cross/assoc-items.rs | 4 +- src/test/rustdoc/inline_cross/hidden-use.rs | 4 +- src/test/rustdoc/inline_cross/proc_macro.rs | 12 +- .../glob-extern-document-private-items.rs | 10 +- src/test/rustdoc/inline_local/glob-extern.rs | 6 +- .../glob-private-document-private-items.rs | 26 +- src/test/rustdoc/inline_local/glob-private.rs | 12 +- src/test/rustdoc/inline_local/hidden-use.rs | 4 +- src/test/rustdoc/inline_local/macro_by_example.rs | 2 +- src/test/rustdoc/inline_local/please_inline.rs | 4 +- src/test/rustdoc/internal.rs | 10 +- src/test/rustdoc/intra-doc/assoc-reexport-super.rs | 20 + src/test/rustdoc/intra-doc/extern-type.rs | 6 +- src/test/rustdoc/issue-100620.rs | 19 + .../rustdoc/issue-100679-sidebar-links-deref.rs | 30 + src/test/rustdoc/issue-101743-bold-tag.rs | 19 + src/test/rustdoc/issue-16265-1.rs | 2 +- src/test/rustdoc/issue-16265-2.rs | 2 +- src/test/rustdoc/issue-20727-4.rs | 4 +- src/test/rustdoc/issue-21801.rs | 2 +- src/test/rustdoc/issue-23511.rs | 2 +- src/test/rustdoc/issue-23812.rs | 16 +- src/test/rustdoc/issue-27104.rs | 6 +- src/test/rustdoc/issue-27759.rs | 4 +- src/test/rustdoc/issue-29503.rs | 2 +- src/test/rustdoc/issue-29584.rs | 2 +- src/test/rustdoc/issue-31899.rs | 8 +- src/test/rustdoc/issue-32374.rs | 16 +- src/test/rustdoc/issue-32395.rs | 12 +- src/test/rustdoc/issue-34473.rs | 2 +- src/test/rustdoc/issue-34928.rs | 2 +- src/test/rustdoc/issue-41783.codeblock.html | 5 + src/test/rustdoc/issue-41783.rs | 14 +- src/test/rustdoc/issue-50159.rs | 4 +- src/test/rustdoc/issue-51236.rs | 2 +- src/test/rustdoc/issue-53689.rs | 2 +- src/test/rustdoc/issue-54705.rs | 6 +- src/test/rustdoc/issue-61592.rs | 4 +- ...ltiple-mods-w-same-name-doc-inline-last-item.rs | 16 + ...e-83375-multiple-mods-w-same-name-doc-inline.rs | 16 + src/test/rustdoc/issue-89852.rs | 4 +- src/test/rustdoc/issue-98697.rs | 2 +- src/test/rustdoc/link-title-escape.rs | 2 +- .../rustdoc/macro-document-private-duplicate.rs | 10 +- src/test/rustdoc/macro-private-not-documented.rs | 4 +- src/test/rustdoc/macro_rules-matchers.rs | 29 +- src/test/rustdoc/markdown-summaries.rs | 12 +- src/test/rustdoc/masked.rs | 14 +- src/test/rustdoc/module-impls.rs | 2 +- src/test/rustdoc/nested-modules.rs | 14 +- src/test/rustdoc/no-crate-filter.rs | 2 +- src/test/rustdoc/primitive-reference.rs | 37 + src/test/rustdoc/primitive-slice-auto-trait.rs | 4 +- src/test/rustdoc/recursive-deref.rs | 8 +- src/test/rustdoc/remove-url-from-headings.rs | 2 +- src/test/rustdoc/rustc-incoherent-impls.rs | 28 + src/test/rustdoc/search-index-summaries.rs | 6 +- src/test/rustdoc/search-index.rs | 10 +- src/test/rustdoc/short-docblock-codeblock.rs | 4 +- src/test/rustdoc/short-docblock.rs | 10 +- src/test/rustdoc/show-const-contents.rs | 48 +- src/test/rustdoc/sized_trait.rs | 4 +- src/test/rustdoc/sort-modules-by-appearance.rs | 4 +- src/test/rustdoc/source-file.rs | 2 +- src/test/rustdoc/src-links-auto-impls.rs | 2 +- src/test/rustdoc/static-root-path.rs | 20 +- src/test/rustdoc/synthetic_auto/basic.rs | 4 +- src/test/rustdoc/synthetic_auto/complex.rs | 2 +- src/test/rustdoc/synthetic_auto/lifetimes.rs | 4 +- src/test/rustdoc/synthetic_auto/manual.rs | 2 +- src/test/rustdoc/synthetic_auto/nested.rs | 4 +- src/test/rustdoc/synthetic_auto/no-redundancy.rs | 2 +- src/test/rustdoc/synthetic_auto/project.rs | 4 +- .../rustdoc/synthetic_auto/self-referential.rs | 2 +- src/test/rustdoc/synthetic_auto/static-region.rs | 2 +- src/test/rustdoc/table-in-docblock.rs | 2 +- src/test/rustdoc/toggle-item-contents.rs | 4 +- .../rustdoc/trait-impl-items-links-and-anchors.rs | 2 +- src/test/rustdoc/trait-impl.rs | 24 +- src/test/rustdoc/tuple-struct-fields-doc.rs | 2 +- src/test/rustdoc/type-layout-flag-required.rs | 2 +- src/test/rustdoc/type-layout.rs | 64 +- src/test/rustdoc/typedef.rs | 2 +- src/test/rustdoc/universal-impl-trait.rs | 30 +- .../rustdoc/version-separator-without-source.rs | 2 +- src/test/rustdoc/where-clause-order.rs | 2 +- .../rustdoc/where.SWhere_TraitWhere_item-decl.html | 7 +- src/test/rustdoc/where.rs | 35 +- .../ui-fulldeps/auxiliary/issue-40001-plugin.rs | 2 +- .../ui-fulldeps/auxiliary/lint-for-crate-rpass.rs | 6 +- src/test/ui-fulldeps/auxiliary/lint-for-crate.rs | 2 +- .../auxiliary/lint-group-plugin-test.rs | 2 +- .../ui-fulldeps/fluent-messages/duplicate-a-b.ftl | 1 + .../ui-fulldeps/fluent-messages/duplicate-a.ftl | 2 +- .../ui-fulldeps/fluent-messages/duplicate-b.ftl | 1 - .../fluent-messages/label-with-hyphens.ftl | 2 + .../fluent-messages/missing-crate-name.ftl | 2 + .../fluent-messages/missing-message.ftl | 2 +- .../fluent-messages/slug-with-hyphens.ftl | 1 + src/test/ui-fulldeps/fluent-messages/test.rs | 37 +- src/test/ui-fulldeps/fluent-messages/test.stderr | 60 +- src/test/ui-fulldeps/fluent-messages/valid.ftl | 2 +- src/test/ui-fulldeps/internal-lints/diagnostics.rs | 30 +- .../ui-fulldeps/internal-lints/diagnostics.stderr | 30 +- src/test/ui-fulldeps/issue-15778-pass.rs | 23 - src/test/ui-fulldeps/issue-15778-pass.stderr | 10 - src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 5 +- .../session-diagnostic/diagnostic-derive.rs | 215 +- .../session-diagnostic/diagnostic-derive.stderr | 338 +- .../session-diagnostic/subdiagnostic-derive.rs | 165 +- .../session-diagnostic/subdiagnostic-derive.stderr | 246 +- .../issue-97463-broken-abi-leaked-uninit-data.rs | 39 + .../allocator/no_std-alloc-error-handler-custom.rs | 2 +- .../no_std-alloc-error-handler-default.rs | 2 +- src/test/ui/argument-suggestions/basic.stderr | 10 +- src/test/ui/argument-suggestions/complex.stderr | 4 +- .../ui/argument-suggestions/exotic-calls.stderr | 8 +- .../ui/argument-suggestions/extra_arguments.stderr | 28 +- .../argument-suggestions/invalid_arguments.stderr | 20 +- src/test/ui/argument-suggestions/issue-100478.rs | 52 + .../ui/argument-suggestions/issue-100478.stderr | 81 + src/test/ui/argument-suggestions/issue-101097.rs | 21 + .../ui/argument-suggestions/issue-101097.stderr | 160 + .../ui/argument-suggestions/issue-96638.stderr | 6 +- .../ui/argument-suggestions/issue-97197.stderr | 2 +- .../ui/argument-suggestions/issue-97484.stderr | 7 +- .../ui/argument-suggestions/issue-98894.stderr | 2 +- .../ui/argument-suggestions/issue-98897.stderr | 2 +- .../ui/argument-suggestions/issue-99482.stderr | 2 +- .../argument-suggestions/missing_arguments.stderr | 38 +- .../ui/argument-suggestions/mixed_cases.stderr | 12 +- .../argument-suggestions/permuted_arguments.stderr | 4 +- .../argument-suggestions/swapped_arguments.stderr | 10 +- src/test/ui/argument-suggestions/too-long.rs | 41 + src/test/ui/argument-suggestions/too-long.stderr | 24 + .../ui/argument-suggestions/two-mismatch-notes.rs | 11 + .../argument-suggestions/two-mismatch-notes.stderr | 29 + .../ui/array-slice-vec/suggest-array-length.fixed | 26 + .../ui/array-slice-vec/suggest-array-length.rs | 26 + .../ui/array-slice-vec/suggest-array-length.stderr | 108 + src/test/ui/asm/aarch64/may_unwind.rs | 1 - src/test/ui/asm/aarch64/type-check-3.stderr | 40 +- .../ui/asm/bad-template.aarch64_mirunsafeck.stderr | 4 +- .../asm/bad-template.aarch64_thirunsafeck.stderr | 4 +- .../ui/asm/bad-template.x86_64_mirunsafeck.stderr | 4 +- .../ui/asm/bad-template.x86_64_thirunsafeck.stderr | 4 +- src/test/ui/asm/may_unwind.rs | 1 - src/test/ui/asm/naked-functions.stderr | 103 +- src/test/ui/asm/type-check-1.stderr | 4 +- src/test/ui/asm/unpretty-expanded.rs | 3 + src/test/ui/asm/unpretty-expanded.stdout | 9 + src/test/ui/asm/x86_64/may_unwind.rs | 2 +- src/test/ui/asm/x86_64/sym.rs | 1 - src/test/ui/asm/x86_64/type-check-3.stderr | 16 +- .../associated-consts/defaults-cyclic-fail.stderr | 4 +- .../ui/associated-consts/issue-102335-const.rs | 12 + .../ui/associated-consts/issue-102335-const.stderr | 9 + ...-24949-assoc-const-static-recursion-impl.stderr | 2 +- ...soc-const-static-recursion-trait-default.stderr | 2 +- ...24949-assoc-const-static-recursion-trait.stderr | 2 +- .../ui/associated-type-bounds/binder-on-bound.rs | 2 - .../associated-type-bounds/binder-on-bound.stderr | 2 +- src/test/ui/associated-type-bounds/elision.rs | 2 +- .../ui/associated-type-bounds/issue-102335-ty.rs | 12 + .../associated-type-bounds/issue-102335-ty.stderr | 9 + src/test/ui/associated-type-bounds/issue-79949.rs | 1 - ...sociated-type-projection-from-supertrait.stderr | 8 +- ...es-binding-to-type-defined-in-supertrait.stderr | 12 +- .../associated-types/associated-types-eq-3.stderr | 6 +- .../associated-types/associated-types-eq-hr.stderr | 8 +- .../associated-types-for-unimpl-trait.stderr | 4 +- .../associated-types-issue-20346.stderr | 6 +- ...ssociated-types-multiple-types-one-trait.stderr | 12 +- .../associated-types-no-suitable-bound.stderr | 4 +- ...ssociated-types-no-suitable-supertrait-2.stderr | 4 +- .../associated-types-no-suitable-supertrait.stderr | 8 +- .../associated-types-overridden-binding-2.rs | 2 +- .../associated-types-overridden-binding-2.stderr | 2 +- .../ui/associated-types/associated-types-path-2.rs | 2 + .../associated-types-path-2.stderr | 32 +- ...nrelated-trait-in-method-without-default.stderr | 4 +- .../associated-types/defaults-suitability.stderr | 6 +- .../higher-ranked-projection.badbase.stderr | 17 - .../higher-ranked-projection.badnll.stderr | 2 - .../hr-associated-type-bound-2.stderr | 4 +- .../ui/associated-types/impl-wf-cycle-1.stderr | 4 +- .../ui/associated-types/impl-wf-cycle-2.stderr | 2 +- src/test/ui/associated-types/issue-22560.stderr | 46 +- .../issue-27675-unchecked-bounds.stderr | 6 +- src/test/ui/associated-types/issue-44153.stderr | 2 +- src/test/ui/associated-types/issue-59324.rs | 2 +- src/test/ui/associated-types/issue-59324.stderr | 17 +- src/test/ui/associated-types/issue-62200.rs | 3 +- src/test/ui/associated-types/issue-62200.stderr | 3 +- src/test/ui/associated-types/issue-65774-1.stderr | 2 +- src/test/ui/associated-types/issue-87261.stderr | 84 +- .../ui/associated-types/substs-ppaux.normal.stderr | 8 +- .../associated-types/substs-ppaux.verbose.stderr | 8 +- .../async-await-let-else.drop-tracking.stderr | 110 + .../async-await-let-else.no-drop-tracking.stderr | 94 + src/test/ui/async-await/async-await-let-else.rs | 13 +- .../ui/async-await/async-await-let-else.stderr | 94 - .../async-block-control-flow-static-semantics.rs | 8 +- ...sync-block-control-flow-static-semantics.stderr | 8 +- src/test/ui/async-await/async-trait-fn.rs | 3 + src/test/ui/async-await/async-trait-fn.stderr | 75 +- .../ui/async-await/edition-deny-async-fns-2015.rs | 3 +- .../async-await/edition-deny-async-fns-2015.stderr | 30 +- src/test/ui/async-await/generator-desc.stderr | 4 +- src/test/ui/async-await/issue-101715.rs | 17 + src/test/ui/async-await/issue-101715.stderr | 16 + .../issue-64130-4-async-move.drop-tracking.stderr | 26 + ...ssue-64130-4-async-move.no_drop_tracking.stderr | 26 + .../ui/async-await/issue-64130-4-async-move.rs | 10 +- .../ui/async-await/issue-64130-4-async-move.stderr | 26 - .../async-await/issue-67252-unnamed-future.stderr | 10 +- .../async-await/issue-68112.drop_tracking.stderr | 79 + .../issue-68112.no_drop_tracking.stderr | 79 + src/test/ui/async-await/issue-68112.rs | 11 +- src/test/ui/async-await/issue-68112.stderr | 74 - src/test/ui/async-await/issue-70594.stderr | 12 +- .../issue-70935-complex-spans.drop_tracking.stderr | 10 +- ...sue-70935-complex-spans.no_drop_tracking.stderr | 25 + .../issue-70935-complex-spans.normal.stderr | 25 - .../ui/async-await/issue-70935-complex-spans.rs | 5 +- src/test/ui/async-await/issue-73137.rs | 3 + .../ui/async-await/issues/issue-62009-1.stderr | 14 +- ...-65436-raw-ptr-not-send.no_drop_tracking.stderr | 36 + .../issues/issue-65436-raw-ptr-not-send.rs | 6 +- .../issues/issue-65436-raw-ptr-not-send.stderr | 32 - src/test/ui/async-await/issues/issue-95307.stderr | 14 +- ...artial-drop-partial-reinit.drop_tracking.stderr | 35 + ...ial-drop-partial-reinit.no_drop_tracking.stderr | 35 + .../ui/async-await/partial-drop-partial-reinit.rs | 11 +- .../async-await/partial-drop-partial-reinit.stderr | 35 - src/test/ui/async-await/unnecessary-await.stderr | 2 +- src/test/ui/attempted-access-non-fatal.rs | 4 + src/test/ui/attempted-access-non-fatal.stderr | 46 +- .../ui/attributes/collapse-debuginfo-invalid.rs | 110 + .../attributes/collapse-debuginfo-invalid.stderr | 222 ++ src/test/ui/attributes/issue-100631.rs | 8 + src/test/ui/attributes/issue-100631.stderr | 12 + src/test/ui/attributes/issue-90873.stderr | 4 +- src/test/ui/attributes/register-attr-tool-fail.rs | 13 - .../ui/attributes/register-attr-tool-fail.stderr | 42 - .../ui/attributes/register-attr-tool-import.rs | 17 - .../ui/attributes/register-attr-tool-import.stderr | 38 - .../ui/attributes/register-attr-tool-prelude.rs | 14 - .../attributes/register-attr-tool-prelude.stderr | 15 - .../ui/attributes/register-attr-tool-unused.rs | 8 - .../ui/attributes/register-attr-tool-unused.stderr | 21 - src/test/ui/attributes/register-attr-tool.rs | 19 - .../unix_sigpipe/auxiliary/sigpipe-utils.rs | 31 + .../attributes/unix_sigpipe/unix_sigpipe-crate.rs | 4 + .../unix_sigpipe/unix_sigpipe-crate.stderr | 13 + .../unix_sigpipe/unix_sigpipe-duplicates.rs | 5 + .../unix_sigpipe/unix_sigpipe-duplicates.stderr | 14 + .../attributes/unix_sigpipe/unix_sigpipe-error.rs | 13 + .../unix_sigpipe/unix_sigpipe-inherit.rs | 14 + .../attributes/unix_sigpipe/unix_sigpipe-list.rs | 4 + .../unix_sigpipe/unix_sigpipe-list.stderr | 15 + .../unix_sigpipe/unix_sigpipe-non-main-fn.rs | 6 + .../unix_sigpipe/unix_sigpipe-non-main-fn.stderr | 8 + .../unix_sigpipe/unix_sigpipe-non-root-main.rs | 8 + .../unix_sigpipe/unix_sigpipe-non-root-main.stderr | 8 + .../unix_sigpipe/unix_sigpipe-not-used.rs | 9 + .../unix_sigpipe/unix_sigpipe-only-feature.rs | 13 + .../unix_sigpipe/unix_sigpipe-rustc_main.rs | 15 + .../unix_sigpipe/unix_sigpipe-sig_dfl.rs | 13 + .../attributes/unix_sigpipe/unix_sigpipe-start.rs | 6 + .../unix_sigpipe/unix_sigpipe-start.stderr | 8 + .../attributes/unix_sigpipe/unix_sigpipe-struct.rs | 6 + .../unix_sigpipe/unix_sigpipe-struct.stderr | 8 + .../attributes/unix_sigpipe/unix_sigpipe-wrong.rs | 4 + .../unix_sigpipe/unix_sigpipe-wrong.stderr | 8 + .../ui/attributes/unix_sigpipe/unix_sigpipe.rs | 4 + .../ui/attributes/unix_sigpipe/unix_sigpipe.stderr | 8 + src/test/ui/auto-ref-slice-plus-ref.stderr | 2 +- ...k-default-trait-impl-constituent-types-2.stderr | 4 +- .../typeck-default-trait-impl-precedence.stderr | 6 +- src/test/ui/backtrace-apple-no-dsymutil.rs | 2 - src/test/ui/binop/binary-op-on-double-ref.stderr | 2 +- src/test/ui/binop/issue-77910-1.stderr | 2 +- src/test/ui/binop/issue-77910-2.stderr | 5 + src/test/ui/block-result/issue-22645.stderr | 2 +- src/test/ui/block-result/issue-3563.stderr | 2 +- ...-or-patterns-slice-patterns-box-patterns.stderr | 30 +- .../ui/borrowck/borrowck-describe-lvalue.stderr | 12 +- .../borrowck-move-out-from-array-match.stderr | 6 +- ...wck-move-out-from-array-no-overlap-match.stderr | 6 +- .../borrowck-move-out-from-array-use-match.stderr | 10 +- ...move-out-from-array-use-no-overlap-match.stderr | 6 +- .../borrowck-move-out-from-array-use.stderr | 20 +- .../borrowck/borrowck-move-out-from-array.stderr | 16 +- ...orrowck-slice-pattern-element-loan-array.stderr | 8 +- ...orrowck-slice-pattern-element-loan-slice.stderr | 8 +- .../borrowck/borrowck-vec-pattern-move-tail.stderr | 2 +- .../borrowck/borrowck-vec-pattern-nesting.stderr | 2 +- ...-move-when-closure-is-already-marked-as-move.rs | 8 + ...e-when-closure-is-already-marked-as-move.stderr | 18 + src/test/ui/borrowck/index-mut-help.rs | 3 +- src/test/ui/borrowck/index-mut-help.stderr | 19 +- src/test/ui/borrowck/issue-101119.rs | 16 + src/test/ui/borrowck/issue-101119.stderr | 15 + ...2-nested-closure-outlives-borrowed-value.stderr | 4 + src/test/ui/borrowck/issue-64453.stderr | 1 + .../issue-95079-missing-move-in-nested-closure.rs | 14 + ...sue-95079-missing-move-in-nested-closure.stderr | 37 + .../borrowck/suggest-as-ref-on-mut-closure.stderr | 5 +- src/test/ui/borrowck/two-phase-nonrecv-autoref.rs | 4 +- .../two-phase-reservation-sharing-interference.rs | 2 +- src/test/ui/btreemap/btreemap-index-mut.rs | 6 + src/test/ui/btreemap/btreemap-index-mut.stderr | 19 + src/test/ui/c-variadic/issue-86053-1.stderr | 6 +- src/test/ui/c-variadic/variadic-ffi-1.stderr | 4 +- ...uture-compat-crate-attributes-using-cfg_attr.rs | 1 - ...e-compat-crate-attributes-using-cfg_attr.stderr | 15 +- src/test/ui/chalkify/type_wf.rs | 4 +- src/test/ui/chalkify/type_wf.stderr | 6 +- src/test/ui/check-cfg/allow-at-crate-level.rs | 8 + .../invalid-arguments.names_simple_ident.stderr | 2 +- .../invalid-arguments.values_simple_ident.stderr | 2 +- src/test/ui/check-cfg/invalid-cfg-value.stderr | 6 +- src/test/ui/check-cfg/mix.rs | 2 +- src/test/ui/check-cfg/mix.stderr | 10 +- src/test/ui/check-static-values-constraints.stderr | 1 + .../expect-fn-supply-fn.stderr | 12 +- ...o-infer-vars-supply-ty-with-bound-region.stderr | 2 +- .../ui/closure_context/issue-26046-fn-mut.stderr | 2 + .../ui/closure_context/issue-26046-fn-once.stderr | 2 + .../2229_closure_analysis/diagnostics/arrays.rs | 2 +- .../closure-origin-array-diagnostics.stderr | 10 +- .../closure-origin-tuple-diagnostics.stderr | 10 +- .../match/non-exhaustive-match.rs | 2 +- .../match/non-exhaustive-match.stderr | 8 +- .../closures/2229_closure_analysis/repr_packed.rs | 2 +- .../2229_closure_analysis/run_pass/by_value.rs | 4 +- ...structure-pattern-closure-within-closure.stderr | 16 +- .../run_pass/disjoint-capture-in-same-closure.rs | 2 +- .../run_pass/multilevel-path-1.rs | 4 +- .../run_pass/multilevel-path-2.rs | 2 +- .../run_pass/mut_ref_struct_mem.rs | 2 +- src/test/ui/closures/binder/disallow-const.rs | 6 + src/test/ui/closures/binder/disallow-const.stderr | 8 + src/test/ui/closures/binder/disallow-ty.rs | 6 + src/test/ui/closures/binder/disallow-ty.stderr | 8 + src/test/ui/closures/closure-move-sync.stderr | 22 +- src/test/ui/closures/closure-wrong-kind.stderr | 10 +- .../ui/closures/coerce-unsafe-to-closure.stderr | 2 +- src/test/ui/closures/issue-10398.rs | 4 +- src/test/ui/closures/issue-10398.stderr | 2 +- src/test/ui/closures/issue-52437.rs | 1 - src/test/ui/closures/issue-52437.stderr | 13 +- src/test/ui/closures/issue-6801.rs | 4 +- src/test/ui/closures/issue-84128.rs | 2 +- src/test/ui/closures/issue-84128.stderr | 5 - .../print/closure-print-generic-verbose-1.stderr | 2 +- src/test/ui/codegen/issue-101585-128bit-repeat.rs | 14 + src/test/ui/codegen/issue-99551.rs | 21 + .../coercion/coerce-reborrow-multi-arg-fail.stderr | 2 +- src/test/ui/coercion/coerce-to-bang.stderr | 10 +- src/test/ui/coercion/issue-101066.rs | 16 + .../coherence/auxiliary/trait-with-const-param.rs | 1 + .../coherence-negative-outlives-lifetimes.rs | 13 +- .../coherence-negative-outlives-lifetimes.stderr | 11 - ...erence-negative-outlives-lifetimes.stock.stderr | 11 + .../ui/coherence/const-generics-orphan-check-ok.rs | 28 + src/test/ui/coherence/issue-100191-2.rs | 12 + src/test/ui/coherence/issue-100191-2.stderr | 14 + src/test/ui/coherence/issue-100191.rs | 21 + src/test/ui/coherence/issue-100191.stderr | 12 + src/test/ui/command/command-current-dir.rs | 2 +- .../cfg-attr-syntax-validation.stderr | 4 +- src/test/ui/const-generics/argument_order.stderr | 4 +- .../const-param-before-other-params.rs | 2 +- .../const-param-before-other-params.stderr | 2 +- .../defaults/generic-expr-default-concrete.stderr | 4 +- .../generic-expr-default-mismatched-types.stderr | 4 +- .../const-generics/defaults/intermixed-lifetime.rs | 4 +- .../defaults/intermixed-lifetime.stderr | 4 +- .../param-order-err-pretty-prints-default.rs | 2 +- .../param-order-err-pretty-prints-default.stderr | 2 +- .../defaults/trait_objects_fail.stderr | 8 +- .../early/const-param-from-outer-fn.stderr | 2 +- .../abstract-const-as-cast-3.stderr | 96 +- .../generic_const_exprs/different-fn.stderr | 4 +- .../generic_const_exprs/issue-100217.rs | 42 + .../generic_const_exprs/issue-100360.rs | 13 + .../generic_const_exprs/issue-62504.full.stderr | 4 +- .../generic_const_exprs/issue-69654.stderr | 4 +- .../issue-72819-generic-in-const-eval.full.stderr | 22 +- .../generic_const_exprs/issue-73298.rs | 23 + .../generic_const_exprs/issue-82268.rs | 73 + .../generic_const_exprs/issue-83765.stderr | 8 +- .../generic_const_exprs/issue-83972.rs | 38 + .../generic_const_exprs/issue-84669.rs | 30 + .../generic_const_exprs/issue-85848.stderr | 12 +- .../generic_const_exprs/issue-86710.rs | 73 + .../generic_const_exprs/issue-89851.rs | 12 + .../generic_const_exprs/obligation-cause.rs | 24 + .../generic_const_exprs/obligation-cause.stderr | 20 + .../invalid-const-arg-for-type-param.stderr | 13 +- src/test/ui/const-generics/issue-103243.rs | 37 + src/test/ui/const-generics/issues/issue-100313.rs | 21 + .../ui/const-generics/issues/issue-100313.stderr | 15 + .../ui/const-generics/issues/issue-73260.stderr | 24 +- .../ui/const-generics/issues/issue-79674.stderr | 12 +- src/test/ui/const-generics/issues/issue-83466.rs | 2 +- .../ui/const-generics/issues/issue-83765.stderr | 4 +- .../ui/const-generics/issues/issue-87493.stderr | 8 +- .../invalid-patterns.32bit.stderr | 26 +- .../invalid-patterns.64bit.stderr | 26 +- .../min_const_generics/invalid-patterns.rs | 6 +- .../types-mismatch-const-args.full.stderr | 4 +- src/test/ui/consts/assert-type-intrinsics.rs | 4 +- src/test/ui/consts/assert-type-intrinsics.stderr | 8 +- src/test/ui/consts/const-block-const-bound.stderr | 4 +- .../const-blocks/fn-call-in-non-const.stderr | 2 +- .../ui/consts/const-blocks/migrate-fail.stderr | 4 +- src/test/ui/consts/const-blocks/nll-fail.stderr | 4 +- src/test/ui/consts/const-blocks/trait-error.stderr | 2 +- src/test/ui/consts/const-err4.32bit.stderr | 11 +- src/test/ui/consts/const-err4.64bit.stderr | 11 +- src/test/ui/consts/const-err4.rs | 3 +- ...st-pointer-values-in-various-types.64bit.stderr | 110 +- .../const-pointer-values-in-various-types.rs | 6 +- .../heap/alloc_intrinsic_uninit.32bit.stderr | 2 +- .../heap/alloc_intrinsic_uninit.64bit.stderr | 2 +- .../consts/const-eval/issue-91827-extern-types.rs | 1 - src/test/ui/consts/const-eval/ub-enum-overwrite.rs | 3 +- .../ui/consts/const-eval/ub-enum-overwrite.stderr | 13 +- src/test/ui/consts/const-eval/ub-enum.32bit.stderr | 25 +- src/test/ui/consts/const-eval/ub-enum.64bit.stderr | 25 +- src/test/ui/consts/const-eval/ub-enum.rs | 5 +- .../ui/consts/const-eval/ub-int-array.32bit.stderr | 39 +- .../ui/consts/const-eval/ub-int-array.64bit.stderr | 39 +- src/test/ui/consts/const-eval/ub-int-array.rs | 12 +- .../ui/consts/const-eval/ub-nonnull.32bit.stderr | 15 +- .../ui/consts/const-eval/ub-nonnull.64bit.stderr | 15 +- src/test/ui/consts/const-eval/ub-nonnull.rs | 3 +- .../ui/consts/const-eval/ub-ref-ptr.32bit.stderr | 28 +- .../ui/consts/const-eval/ub-ref-ptr.64bit.stderr | 28 +- src/test/ui/consts/const-eval/ub-ref-ptr.rs | 6 +- .../ui/consts/const-eval/ub-wide-ptr.32bit.stderr | 90 +- .../ui/consts/const-eval/ub-wide-ptr.64bit.stderr | 90 +- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 12 +- .../ui/consts/const-eval/union-const-eval-field.rs | 3 +- .../const-eval/union-const-eval-field.stderr | 13 +- src/test/ui/consts/const-eval/union-ice.rs | 12 +- src/test/ui/consts/const-eval/union-ice.stderr | 39 +- .../ui/consts/const-eval/union-ub.32bit.stderr | 11 +- .../ui/consts/const-eval/union-ub.64bit.stderr | 11 +- src/test/ui/consts/const-eval/union-ub.rs | 3 +- .../ui/consts/const-float-bits-reject-conv.stderr | 40 - .../ui/consts/const-points-to-static.32bit.stderr | 2 +- .../ui/consts/const-points-to-static.64bit.stderr | 2 +- .../ui/consts/const_in_pattern/incomplete-slice.rs | 15 + .../const_in_pattern/incomplete-slice.stderr | 26 + .../ui/consts/extra-const-ub/detect-extra-ub.rs | 45 + .../detect-extra-ub.with_flag.stderr | 117 + src/test/ui/consts/extra-const-ub/issue-100771.rs | 20 + src/test/ui/consts/extra-const-ub/issue-101034.rs | 17 + src/test/ui/consts/issue-32829-2.stderr | 2 + src/test/ui/consts/issue-36163.stderr | 2 +- src/test/ui/consts/issue-miri-1910.rs | 1 + src/test/ui/consts/issue-miri-1910.stderr | 12 +- src/test/ui/consts/mir_check_nonconst.stderr | 1 + .../const_refers_to_static2.32bit.stderr | 4 +- .../const_refers_to_static2.64bit.stderr | 4 +- ...const_refers_to_static_cross_crate.32bit.stderr | 4 +- ...const_refers_to_static_cross_crate.64bit.stderr | 4 +- src/test/ui/consts/miri_unleashed/ptr_arith.rs | 5 +- src/test/ui/consts/miri_unleashed/ptr_arith.stderr | 2 +- src/test/ui/consts/miri_unleashed/slice_eq.rs | 12 +- src/test/ui/consts/offset.rs | 1 - src/test/ui/consts/offset_from.rs | 1 - src/test/ui/consts/offset_from_ub.rs | 2 +- src/test/ui/consts/ptr_comparisons.rs | 24 +- src/test/ui/consts/ptr_comparisons.stderr | 14 +- src/test/ui/consts/unnormalized-param-env.rs | 31 + .../cycle-trait/cycle-trait-default-type-trait.rs | 1 - .../cycle-trait-default-type-trait.stderr | 21 +- .../debuginfo-emit-llvm-ir-and-split-debuginfo.rs | 3 +- src/test/ui/deprecation/deprecation-sanity.stderr | 4 +- .../derives-span-PartialEq-enum-struct-variant.rs | 1 - ...rives-span-PartialEq-enum-struct-variant.stderr | 22 +- src/test/ui/derives/derives-span-PartialEq-enum.rs | 3 +- .../ui/derives/derives-span-PartialEq-enum.stderr | 22 +- .../ui/derives/derives-span-PartialEq-struct.rs | 1 - .../derives/derives-span-PartialEq-struct.stderr | 22 +- .../derives/derives-span-PartialEq-tuple-struct.rs | 1 - .../derives-span-PartialEq-tuple-struct.stderr | 22 +- src/test/ui/derives/deriving-copyclone.stderr | 12 +- .../deriving-no-inner-impl-error-message.rs | 1 - .../deriving-no-inner-impl-error-message.stderr | 24 +- src/test/ui/deriving/deriving-all-codegen.rs | 2 +- src/test/ui/deriving/deriving-all-codegen.stdout | 65 +- src/test/ui/deriving/issue-103157.rs | 12 + src/test/ui/deriving/issue-103157.stderr | 30 + src/test/ui/deriving/issue-89188-gat-hrtb.rs | 2 - .../issue-21659-show-relevant-trait-impls-1.stderr | 6 +- .../issue-21659-show-relevant-trait-impls-2.stderr | 6 +- .../ui/did_you_mean/use_instead_of_import.fixed | 8 + src/test/ui/did_you_mean/use_instead_of_import.rs | 8 + .../ui/did_you_mean/use_instead_of_import.stderr | 16 +- src/test/ui/drop/drop-foreign-fundamental.rs | 23 + src/test/ui/drop/drop-foreign-fundamental.stderr | 9 + src/test/ui/drop/drop_order.rs | 145 + src/test/ui/dropck/drop-on-non-struct.rs | 7 +- src/test/ui/dropck/drop-on-non-struct.stderr | 4 +- src/test/ui/dst/dst-bad-coercions.stderr | 8 +- src/test/ui/dst/dst-rvalue.rs | 6 +- src/test/ui/dst/dst-rvalue.stderr | 28 +- .../ui/dyn-keyword/dyn-2018-edition-lint.stderr | 35 +- .../ui/dyn-keyword/dyn-2021-edition-error.stderr | 10 +- src/test/ui/dyn-keyword/dyn-angle-brackets.stderr | 5 +- src/test/ui/dyn-star/const.rs | 14 + src/test/ui/dyn-star/drop.rs | 23 + src/test/ui/dyn-star/drop.run.stdout | 1 + src/test/ui/dyn-star/error.rs | 13 + src/test/ui/dyn-star/error.stderr | 9 + src/test/ui/dyn-star/feature-gate-dyn_star.rs | 9 + src/test/ui/dyn-star/feature-gate-dyn_star.stderr | 12 + src/test/ui/dyn-star/make-dyn-star.rs | 13 + src/test/ui/dyn-star/method.rs | 26 + src/test/ui/dyn-star/syntax.rs | 11 + src/test/ui/dynamically-sized-types/dst-struct.rs | 3 +- src/test/ui/dynamically-sized-types/dst-trait.rs | 1 - src/test/ui/empty/empty-never-array.rs | 2 +- src/test/ui/empty/empty-never-array.stderr | 6 +- src/test/ui/enum/enum-discrim-autosizing.rs | 4 +- src/test/ui/enum/enum-discrim-autosizing.stderr | 4 +- src/test/ui/env-funky-keys.rs | 1 + src/test/ui/error-codes/E0004.stderr | 6 +- src/test/ui/error-codes/E0005.stderr | 2 +- src/test/ui/error-codes/E0057.stderr | 4 +- src/test/ui/error-codes/E0060.stderr | 2 +- src/test/ui/error-codes/E0061.stderr | 4 +- src/test/ui/error-codes/E0081.rs | 37 +- src/test/ui/error-codes/E0081.stderr | 52 +- src/test/ui/error-codes/E0107.stderr | 2 +- src/test/ui/error-codes/E0117.rs | 2 +- src/test/ui/error-codes/E0117.stderr | 4 +- src/test/ui/error-codes/E0120.stderr | 4 +- src/test/ui/error-codes/E0271.stderr | 6 +- src/test/ui/error-codes/E0275.stderr | 4 +- src/test/ui/error-codes/E0277-2.stderr | 4 +- src/test/ui/error-codes/E0401.stderr | 8 +- src/test/ui/error-codes/E0565-2.stderr | 4 +- src/test/ui/explore-issue-38412.stderr | 6 +- src/test/ui/expr/if/if-branch-types.stderr | 5 + src/test/ui/expr/if/if-else-type-mismatch.stderr | 10 + src/test/ui/extern/extern-types-unsized.stderr | 12 +- src/test/ui/extern/extern-wrong-value-type.stderr | 2 +- .../feature-gate-collapse_debuginfo.rs | 7 + .../feature-gate-collapse_debuginfo.stderr | 12 + .../feature-gate-exhaustive-patterns.stderr | 2 +- .../feature-gate-generic_arg_infer.normal.stderr | 30 +- .../feature-gate-generic_associated_types.rs | 31 - .../feature-gate-generic_associated_types.stderr | 78 - ...ature-gate-generic_associated_types_extended.rs | 2 - ...e-gate-generic_associated_types_extended.stderr | 2 +- .../feature-gate-label_break_value.rs | 5 - .../feature-gate-label_break_value.stderr | 12 - src/test/ui/feature-gates/feature-gate-let_else.rs | 5 - .../ui/feature-gates/feature-gate-let_else.stderr | 14 - ...re-gate-non_exhaustive_omitted_patterns_lint.rs | 2 +- ...ate-non_exhaustive_omitted_patterns_lint.stderr | 6 +- .../feature-gate-object_safe_for_dispatch.stderr | 8 +- .../ui/feature-gates/feature-gate-raw-dylib-2.rs | 6 +- .../feature-gates/feature-gate-raw-dylib-2.stderr | 15 +- .../feature-gate-raw-dylib-import-name-type.rs | 8 + .../feature-gate-raw-dylib-import-name-type.stderr | 21 + .../ui/feature-gates/feature-gate-raw-dylib.rs | 3 +- .../ui/feature-gates/feature-gate-raw-dylib.stderr | 4 +- .../ui/feature-gates/feature-gate-register_attr.rs | 3 - .../feature-gate-register_attr.stderr | 12 - ...ure-gate-return_position_impl_trait_in_trait.rs | 5 + ...gate-return_position_impl_trait_in_trait.stderr | 12 + .../ui/feature-gates/feature-gate-unix_sigpipe.rs | 4 + .../feature-gates/feature-gate-unix_sigpipe.stderr | 12 + .../feature-gates/soft-syntax-gates-with-errors.rs | 30 + .../soft-syntax-gates-with-errors.stderr | 21 + .../soft-syntax-gates-without-errors.rs | 26 + .../soft-syntax-gates-without-errors.stderr | 24 + src/test/ui/fmt/ifmt-bad-arg.rs | 2 + src/test/ui/fmt/ifmt-bad-arg.stderr | 13 +- src/test/ui/fmt/ifmt-unimpl.stderr | 2 +- src/test/ui/fmt/send-sync.stderr | 14 +- src/test/ui/fn/fn-compare-mismatch.stderr | 10 +- src/test/ui/fn/fn-item-type.stderr | 10 +- src/test/ui/fn/fn-trait-formatting.stderr | 8 + .../fn/implied-bounds-unnorm-associated-type-2.rs | 3 +- .../implied-bounds-unnorm-associated-type-2.stderr | 17 + .../fn/implied-bounds-unnorm-associated-type-3.rs | 5 +- .../implied-bounds-unnorm-associated-type-3.stderr | 14 - .../fn/implied-bounds-unnorm-associated-type-4.rs | 24 + .../implied-bounds-unnorm-associated-type-4.stderr | 14 + .../fn/implied-bounds-unnorm-associated-type-5.rs | 23 + .../implied-bounds-unnorm-associated-type-5.stderr | 19 + .../ui/fn/implied-bounds-unnorm-associated-type.rs | 6 +- .../implied-bounds-unnorm-associated-type.stderr | 20 +- .../ui/for-loop-while/break-while-condition.stderr | 8 + src/test/ui/for-loop-while/label_break_value.rs | 1 - .../ui/for-loop-while/label_break_value_invalid.rs | 1 - .../label_break_value_invalid.stderr | 6 +- src/test/ui/for/for-c-in-str.rs | 2 +- src/test/ui/for/for-c-in-str.stderr | 2 +- src/test/ui/for/for-loop-bogosity.stderr | 2 +- src/test/ui/functions-closures/fn-help-with-err.rs | 28 +- .../ui/functions-closures/fn-help-with-err.stderr | 38 +- src/test/ui/generator/clone-impl-async.rs | 71 + src/test/ui/generator/clone-impl-async.stderr | 171 + src/test/ui/generator/clone-impl-static.rs | 17 + src/test/ui/generator/clone-impl-static.stderr | 31 + src/test/ui/generator/clone-impl.rs | 73 + src/test/ui/generator/clone-impl.stderr | 142 + .../drop-tracking-parent-expression.stderr | 12 +- src/test/ui/generator/drop-yield-twice.stderr | 12 +- .../generator-yielding-or-returning-itself.stderr | 26 +- src/test/ui/generator/issue-68112.rs | 3 +- src/test/ui/generator/issue-68112.stderr | 12 +- src/test/ui/generator/not-send-sync.stderr | 28 +- src/test/ui/generator/partial-drop.stderr | 39 +- .../print/generator-print-verbose-1.stderr | 12 +- .../print/generator-print-verbose-2.stderr | 28 +- .../type-mismatch-signature-deduction.stderr | 6 + .../yield-outside-generator-issue-78653.stderr | 2 +- .../anonymize-bound-vars.rs | 1 - .../generic-associated-types/auxiliary/foo_defn.rs | 2 - .../bugs/hrtb-implied-1.rs | 35 + .../bugs/hrtb-implied-1.stderr | 20 + .../bugs/hrtb-implied-2.rs | 40 + .../bugs/hrtb-implied-2.stderr | 22 + .../bugs/hrtb-implied-3.rs | 23 + .../bugs/hrtb-implied-3.stderr | 22 + .../generic-associated-types/bugs/issue-80626.rs | 2 - .../bugs/issue-80626.stderr | 4 +- .../generic-associated-types/bugs/issue-86218.rs | 1 - .../bugs/issue-86218.stderr | 6 +- .../generic-associated-types/bugs/issue-87735.rs | 2 - .../bugs/issue-87735.stderr | 2 +- .../generic-associated-types/bugs/issue-87748.rs | 23 - .../bugs/issue-87748.stderr | 20 - .../generic-associated-types/bugs/issue-87755.rs | 2 - .../bugs/issue-87755.stderr | 2 +- .../generic-associated-types/bugs/issue-87803.rs | 2 - .../bugs/issue-87803.stderr | 2 +- .../generic-associated-types/bugs/issue-88382.rs | 2 - .../bugs/issue-88382.stderr | 4 +- .../generic-associated-types/bugs/issue-88460.rs | 2 - .../bugs/issue-88460.stderr | 8 +- .../generic-associated-types/bugs/issue-88526.rs | 2 - .../bugs/issue-88526.stderr | 2 +- .../generic-associated-types/bugs/issue-89008.rs | 1 - .../bugs/issue-89008.stderr | 4 +- .../generic-associated-types/bugs/issue-91762.rs | 29 + .../bugs/issue-91762.stderr | 14 + .../collections-project-default.rs | 1 - .../collections-project-default.stderr | 2 +- .../ui/generic-associated-types/collections.rs | 1 - .../collectivity-regression.rs | 2 - .../collectivity-regression.stderr | 2 +- .../const-generics-gat-in-trait-return-type-1.rs | 1 - .../const-generics-gat-in-trait-return-type-2.rs | 1 - .../const-generics-gat-in-trait-return-type-3.rs | 1 - .../const_params_have_right_type.rs | 2 - .../const_params_have_right_type.stderr | 2 +- .../constraint-assoc-type-suggestion.rs | 2 - .../constraint-assoc-type-suggestion.stderr | 2 +- .../construct_with_other_type.rs | 2 - .../cross-crate-bounds.stderr | 2 +- .../elided-in-expr-position.rs | 1 - .../elided-in-expr-position.stderr | 8 +- .../ui/generic-associated-types/empty_generics.rs | 2 - .../generic-associated-types/empty_generics.stderr | 2 +- .../extended/lending_iterator.base.stderr | 2 +- .../extended/lending_iterator.rs | 1 - .../extended/lending_iterator_2.base.stderr | 2 +- .../extended/lending_iterator_2.rs | 1 - .../gat-dont-ice-on-absent-feature-2.rs | 16 - .../gat-dont-ice-on-absent-feature-2.stderr | 21 - .../gat-dont-ice-on-absent-feature.rs | 16 - .../gat-dont-ice-on-absent-feature.stderr | 19 - .../gat-in-trait-path-undeclared-lifetime.rs | 2 - .../gat-in-trait-path-undeclared-lifetime.stderr | 4 +- .../gat-in-trait-path.base.stderr | 4 +- .../generic-associated-types/gat-in-trait-path.rs | 1 - .../gat-incomplete-warning.rs | 5 - .../gat-trait-path-generic-type-arg.rs | 2 - .../gat-trait-path-generic-type-arg.stderr | 6 +- .../gat-trait-path-missing-lifetime.rs | 2 - .../gat-trait-path-missing-lifetime.stderr | 8 +- .../gat-trait-path-parenthesised-args.rs | 2 - .../gat-trait-path-parenthesised-args.stderr | 18 +- .../generic-associated-type-bounds.rs | 2 - .../generic-associated-types-where.rs | 2 - .../generic-associated-types-where.stderr | 4 +- ...generic_associated_type_undeclared_lifetimes.rs | 2 - ...ric_associated_type_undeclared_lifetimes.stderr | 4 +- .../ui/generic-associated-types/impl_bounds.rs | 1 - .../ui/generic-associated-types/impl_bounds.stderr | 26 +- .../ui/generic-associated-types/impl_bounds_ok.rs | 1 - .../ui/generic-associated-types/issue-101020.rs | 35 + .../generic-associated-types/issue-101020.stderr | 25 + .../ui/generic-associated-types/issue-102333.rs | 15 + .../generic-associated-types/issue-102335-gat.rs | 12 + .../issue-102335-gat.stderr | 9 + .../issue-47206-where-clause.rs | 2 - .../issue-47206-where-clause.stderr | 2 +- .../issue-58694-parameter-out-of-range.rs | 2 - .../issue-62326-parameter-out-of-range.rs | 2 - .../ui/generic-associated-types/issue-67424.rs | 2 +- .../ui/generic-associated-types/issue-67424.stderr | 12 - .../issue-67510-pass.base.stderr | 4 +- .../generic-associated-types/issue-67510-pass.rs | 1 - .../ui/generic-associated-types/issue-67510.rs | 2 - .../ui/generic-associated-types/issue-67510.stderr | 8 +- .../issue-68641-check-gat-bounds.rs | 2 - .../issue-68641-check-gat-bounds.stderr | 4 +- .../issue-68642-broken-llvm-ir.rs | 2 - .../issue-68642-broken-llvm-ir.stderr | 4 +- .../issue-68643-broken-mir.rs | 2 - .../issue-68643-broken-mir.stderr | 4 +- .../issue-68644-codegen-selection.rs | 2 - .../issue-68644-codegen-selection.stderr | 4 +- .../issue-68645-codegen-fulfillment.rs | 2 - .../issue-68645-codegen-fulfillment.stderr | 4 +- .../ui/generic-associated-types/issue-68648-1.rs | 3 - .../ui/generic-associated-types/issue-68648-2.rs | 2 - .../generic-associated-types/issue-68648-2.stderr | 4 +- .../generic-associated-types/issue-68649-pass.rs | 2 - .../ui/generic-associated-types/issue-68653.rs | 2 - .../issue-68656-unsized-values.rs | 2 - .../issue-68656-unsized-values.stderr | 4 +- .../ui/generic-associated-types/issue-70303.rs | 2 - .../ui/generic-associated-types/issue-70304.rs | 2 - .../ui/generic-associated-types/issue-70304.stderr | 6 +- .../ui/generic-associated-types/issue-71176.rs | 2 - .../ui/generic-associated-types/issue-71176.stderr | 4 +- .../ui/generic-associated-types/issue-74684-1.rs | 2 - .../generic-associated-types/issue-74684-1.stderr | 2 +- .../ui/generic-associated-types/issue-74684-2.rs | 2 - .../generic-associated-types/issue-74684-2.stderr | 10 +- .../ui/generic-associated-types/issue-74816.rs | 1 - .../ui/generic-associated-types/issue-74816.stderr | 8 +- .../ui/generic-associated-types/issue-74824.rs | 1 - .../ui/generic-associated-types/issue-74824.stderr | 10 +- .../ui/generic-associated-types/issue-76407.rs | 2 - .../issue-76535.base.stderr | 14 +- .../issue-76535.extended.stderr | 4 +- .../ui/generic-associated-types/issue-76535.rs | 1 - .../ui/generic-associated-types/issue-76826.rs | 2 - .../issue-78113-lifetime-mismatch-dyn-trait-box.rs | 4 +- ...ue-78113-lifetime-mismatch-dyn-trait-box.stderr | 26 +- .../issue-78671.base.stderr | 8 +- .../issue-78671.extended.stderr | 4 +- .../ui/generic-associated-types/issue-78671.rs | 1 - .../issue-79422.base.stderr | 14 +- .../issue-79422.extended.stderr | 8 +- .../ui/generic-associated-types/issue-79422.rs | 1 - .../ui/generic-associated-types/issue-79636-1.rs | 2 - .../generic-associated-types/issue-79636-1.stderr | 4 +- .../ui/generic-associated-types/issue-79636-2.rs | 2 - .../generic-associated-types/issue-79636-2.stderr | 4 +- .../issue-80433-reduced.rs | 2 - .../ui/generic-associated-types/issue-80433.rs | 2 - .../ui/generic-associated-types/issue-80433.stderr | 4 +- .../ui/generic-associated-types/issue-81487.rs | 2 - .../issue-81712-cyclic-traits.rs | 2 - .../issue-81712-cyclic-traits.stderr | 4 +- .../ui/generic-associated-types/issue-81862.rs | 2 - .../ui/generic-associated-types/issue-81862.stderr | 4 +- .../ui/generic-associated-types/issue-84931.rs | 1 - .../ui/generic-associated-types/issue-84931.stderr | 2 +- .../ui/generic-associated-types/issue-85921.rs | 2 - .../ui/generic-associated-types/issue-86483.rs | 2 - .../ui/generic-associated-types/issue-86787.rs | 1 - .../ui/generic-associated-types/issue-86787.stderr | 2 +- .../ui/generic-associated-types/issue-87258_a.rs | 1 - .../generic-associated-types/issue-87258_a.stderr | 2 +- .../ui/generic-associated-types/issue-87258_b.rs | 1 - .../generic-associated-types/issue-87258_b.stderr | 2 +- .../ui/generic-associated-types/issue-87429-2.rs | 2 - .../issue-87429-associated-type-default.rs | 1 - .../issue-87429-associated-type-default.stderr | 4 +- .../issue-87429-specialization.rs | 1 - .../issue-87429-specialization.stderr | 4 +- .../ui/generic-associated-types/issue-87429.rs | 2 - .../ui/generic-associated-types/issue-87748.rs | 21 + .../ui/generic-associated-types/issue-87750.rs | 2 - .../ui/generic-associated-types/issue-87750.stderr | 2 +- .../ui/generic-associated-types/issue-88287.rs | 1 - .../ui/generic-associated-types/issue-88287.stderr | 4 +- .../ui/generic-associated-types/issue-88360.rs | 2 - .../ui/generic-associated-types/issue-88360.stderr | 2 +- .../ui/generic-associated-types/issue-88405.rs | 2 - .../ui/generic-associated-types/issue-88459.rs | 2 - .../ui/generic-associated-types/issue-88595.rs | 1 - .../ui/generic-associated-types/issue-88595.stderr | 4 +- .../ui/generic-associated-types/issue-89352.rs | 2 - .../ui/generic-associated-types/issue-90014.rs | 1 - .../ui/generic-associated-types/issue-90014.stderr | 4 +- .../ui/generic-associated-types/issue-90729.rs | 2 - .../issue-91139.migrate.stderr | 13 +- .../ui/generic-associated-types/issue-91139.rs | 2 - .../ui/generic-associated-types/issue-91139.stderr | 18 +- .../ui/generic-associated-types/issue-91762.rs | 30 - .../ui/generic-associated-types/issue-91762.stderr | 14 - .../ui/generic-associated-types/issue-91883.rs | 2 - .../ui/generic-associated-types/issue-91883.stderr | 6 +- .../ui/generic-associated-types/issue-92033.rs | 2 - .../ui/generic-associated-types/issue-92033.stderr | 4 +- .../issue-92096.migrate.stderr | 4 +- .../ui/generic-associated-types/issue-92096.rs | 2 - .../ui/generic-associated-types/issue-92096.stderr | 2 +- .../ui/generic-associated-types/issue-92280.rs | 1 - .../ui/generic-associated-types/issue-92954.rs | 2 - .../ui/generic-associated-types/issue-93141.rs | 2 - .../ui/generic-associated-types/issue-93262.rs | 2 - .../ui/generic-associated-types/issue-93340.rs | 2 - .../ui/generic-associated-types/issue-93341.rs | 1 - .../ui/generic-associated-types/issue-93342.rs | 2 - .../ui/generic-associated-types/issue-93874.rs | 2 - .../ui/generic-associated-types/issue-95305.rs | 1 - .../ui/generic-associated-types/issue-95305.stderr | 2 +- src/test/ui/generic-associated-types/iterable.rs | 2 - .../method-unsatified-assoc-type-predicate.rs | 2 - .../method-unsatified-assoc-type-predicate.stderr | 4 +- .../generic-associated-types/missing-bounds.fixed | 2 +- .../generic-associated-types/missing-bounds.stderr | 4 +- .../missing-where-clause-on-trait.rs | 2 - .../missing-where-clause-on-trait.stderr | 2 +- .../missing_lifetime_args.rs | 2 - .../missing_lifetime_args.stderr | 12 +- .../missing_lifetime_const.rs | 2 - .../missing_lifetime_const.stderr | 4 +- .../parameter_number_and_kind.rs | 1 - .../parameter_number_and_kind.stderr | 12 +- .../parameter_number_and_kind_impl.rs | 1 - .../parameter_number_and_kind_impl.stderr | 12 +- .../parse/in-trait-impl.rs | 2 - .../ui/generic-associated-types/parse/in-trait.rs | 2 - .../parse/trait-path-expected-token.rs | 2 - .../parse/trait-path-expected-token.stderr | 2 +- .../parse/trait-path-expressions.rs | 2 - .../parse/trait-path-expressions.stderr | 4 +- .../parse/trait-path-missing-gen_arg.rs | 2 - .../parse/trait-path-missing-gen_arg.stderr | 10 +- .../parse/trait-path-segments.rs | 2 - .../parse/trait-path-segments.stderr | 6 +- .../trait-path-type-error-once-implemented.rs | 2 - .../trait-path-type-error-once-implemented.stderr | 8 +- .../parse/trait-path-types.rs | 2 - .../parse/trait-path-types.stderr | 6 +- .../ui/generic-associated-types/pointer_family.rs | 2 - .../projection-bound-cycle-generic.rs | 2 - .../projection-bound-cycle-generic.stderr | 4 +- .../projection-bound-cycle.rs | 1 - .../projection-bound-cycle.stderr | 4 +- .../projection-type-lifetime-mismatch.rs | 2 - .../projection-type-lifetime-mismatch.stderr | 6 +- .../generic-associated-types/self-outlives-lint.rs | 15 +- .../self-outlives-lint.stderr | 43 +- src/test/ui/generic-associated-types/shadowing.rs | 2 - .../ui/generic-associated-types/shadowing.stderr | 8 +- .../generic-associated-types/streaming_iterator.rs | 2 - .../trait-objects.base.stderr | 4 +- .../trait-objects.extended.stderr | 4 +- .../ui/generic-associated-types/trait-objects.rs | 1 - .../type-param-defaults.rs | 34 + .../type-param-defaults.stderr | 20 + .../unsatified-item-lifetime-bound.rs | 2 - .../unsatified-item-lifetime-bound.stderr | 14 +- .../unsatisfied-outlives-bound.rs | 2 - .../unsatisfied-outlives-bound.stderr | 8 +- .../variance_constraints.rs | 1 - src/test/ui/generics/issue-59508-1.rs | 2 +- src/test/ui/generics/issue-59508-1.stderr | 2 +- src/test/ui/generics/issue-59508.fixed | 2 +- src/test/ui/generics/issue-59508.rs | 2 +- src/test/ui/generics/issue-59508.stderr | 2 +- .../issue-80512-param-reordering-with-defaults.rs | 2 +- ...sue-80512-param-reordering-with-defaults.stderr | 2 +- src/test/ui/generics/issue-98432.stderr | 6 +- .../ui/generics/lifetime-before-type-params.rs | 8 +- .../ui/generics/lifetime-before-type-params.stderr | 8 +- src/test/ui/hashmap/hashmap-index-mut.rs | 6 + src/test/ui/hashmap/hashmap-index-mut.stderr | 19 + src/test/ui/higher-rank-trait-bounds/complex.rs | 28 + .../due-to-where-clause.rs | 13 + .../due-to-where-clause.stderr | 11 + .../hrtb-cache-issue-54302.rs | 24 + .../hrtb-cache-issue-54302.stderr | 11 + .../hrtb-conflate-regions.rs | 31 + .../hrtb-conflate-regions.stderr | 20 + .../hrtb-debruijn-in-receiver.rs | 18 + .../hrtb-debruijn-in-receiver.stderr | 14 + .../hrtb-exists-forall-fn.rs | 18 + .../hrtb-exists-forall-fn.stderr | 12 + .../hrtb-exists-forall-trait-contravariant.rs | 36 + .../hrtb-exists-forall-trait-contravariant.stderr | 11 + .../hrtb-exists-forall-trait-covariant.rs | 37 + .../hrtb-exists-forall-trait-invariant.rs | 29 + .../hrtb-exists-forall-trait-invariant.stderr | 11 + .../hrtb-higher-ranker-supertraits-transitive.rs | 50 + ...rtb-higher-ranker-supertraits-transitive.stderr | 23 + .../hrtb-higher-ranker-supertraits.rs | 48 + .../hrtb-higher-ranker-supertraits.stderr | 43 + .../hrtb-identity-fn-borrows.rs | 26 + .../hrtb-identity-fn-borrows.stderr | 14 + .../hrtb-just-for-static.rs | 35 + .../hrtb-just-for-static.stderr | 34 + .../hrtb-perfect-forwarding.polonius.stderr | 71 + .../hrtb-perfect-forwarding.rs | 56 + .../hrtb-perfect-forwarding.stderr | 79 + .../ui/higher-rank-trait-bounds/issue-30786.rs | 134 + .../ui/higher-rank-trait-bounds/issue-30786.stderr | 45 + .../ui/higher-rank-trait-bounds/issue-46989.rs | 40 + .../ui/higher-rank-trait-bounds/issue-46989.stderr | 11 + .../ui/higher-rank-trait-bounds/issue-57639.rs | 29 + .../ui/higher-rank-trait-bounds/issue-58451.rs | 13 + .../ui/higher-rank-trait-bounds/issue-58451.stderr | 19 + .../issue-62203-hrtb-ice.rs | 54 + .../issue-62203-hrtb-ice.stderr | 63 + .../ui/higher-rank-trait-bounds/issue-88446.rs | 35 + .../ui/higher-rank-trait-bounds/issue-90177.rs | 32 + .../ui/higher-rank-trait-bounds/issue-95034.rs | 98 + .../ui/higher-rank-trait-bounds/issue-95034.stderr | 1 + .../ui/higher-rank-trait-bounds/issue-95230.rs | 7 + .../normalize-under-binder/issue-62529-3.stderr | 6 +- .../normalize-under-binder/issue-85455.rs | 1 - .../normalize-under-binder/issue-85455.stderr | 13 +- .../normalize-under-binder/issue-89118.stderr | 6 +- .../normalize-under-binder/issue-90612.rs | 2 - .../normalize-under-binder/issue-90638.rs | 2 - src/test/ui/hrtb/complex.rs | 28 - src/test/ui/hrtb/due-to-where-clause.rs | 13 - src/test/ui/hrtb/due-to-where-clause.stderr | 11 - src/test/ui/hrtb/hrtb-cache-issue-54302.rs | 24 - src/test/ui/hrtb/hrtb-cache-issue-54302.stderr | 11 - src/test/ui/hrtb/hrtb-conflate-regions.rs | 31 - src/test/ui/hrtb/hrtb-conflate-regions.stderr | 20 - src/test/ui/hrtb/hrtb-debruijn-in-receiver.rs | 18 - src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr | 14 - src/test/ui/hrtb/hrtb-exists-forall-fn.rs | 18 - src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 12 - .../hrtb/hrtb-exists-forall-trait-contravariant.rs | 36 - .../hrtb-exists-forall-trait-contravariant.stderr | 11 - .../ui/hrtb/hrtb-exists-forall-trait-covariant.rs | 37 - .../ui/hrtb/hrtb-exists-forall-trait-invariant.rs | 29 - .../hrtb/hrtb-exists-forall-trait-invariant.stderr | 11 - .../hrtb-higher-ranker-supertraits-transitive.rs | 50 - ...rtb-higher-ranker-supertraits-transitive.stderr | 23 - src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs | 48 - .../ui/hrtb/hrtb-higher-ranker-supertraits.stderr | 43 - src/test/ui/hrtb/hrtb-identity-fn-borrows.rs | 26 - src/test/ui/hrtb/hrtb-identity-fn-borrows.stderr | 14 - src/test/ui/hrtb/hrtb-just-for-static.rs | 35 - src/test/ui/hrtb/hrtb-just-for-static.stderr | 28 - .../hrtb/hrtb-perfect-forwarding.polonius.stderr | 71 - src/test/ui/hrtb/hrtb-perfect-forwarding.rs | 56 - src/test/ui/hrtb/hrtb-perfect-forwarding.stderr | 73 - src/test/ui/hrtb/issue-30786.rs | 134 - src/test/ui/hrtb/issue-30786.stderr | 53 - src/test/ui/hrtb/issue-46989.rs | 40 - src/test/ui/hrtb/issue-46989.stderr | 11 - src/test/ui/hrtb/issue-57639.rs | 29 - src/test/ui/hrtb/issue-58451.rs | 13 - src/test/ui/hrtb/issue-58451.stderr | 19 - src/test/ui/hrtb/issue-62203-hrtb-ice.rs | 50 - src/test/ui/hrtb/issue-62203-hrtb-ice.stderr | 53 - src/test/ui/hrtb/issue-88446.rs | 35 - src/test/ui/hrtb/issue-90177.rs | 32 - src/test/ui/hrtb/issue-95034.rs | 98 - src/test/ui/hrtb/issue-95034.stderr | 1 - src/test/ui/hrtb/issue-95230.rs | 7 - src/test/ui/impl-trait/auto-trait-leak.stderr | 10 + src/test/ui/impl-trait/equality.stderr | 7 +- ...th-implicit-hrtb-without-dyn.edition2021.stderr | 5 +- src/test/ui/impl-trait/impl-generic-mismatch.rs | 9 + .../ui/impl-trait/impl-generic-mismatch.stderr | 18 +- .../ui/impl-trait/in-trait/deep-match-works.rs | 16 + src/test/ui/impl-trait/in-trait/deep-match.rs | 15 + src/test/ui/impl-trait/in-trait/deep-match.stderr | 15 + src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs | 13 + .../ui/impl-trait/in-trait/doesnt-satisfy.stderr | 17 + src/test/ui/impl-trait/in-trait/encode.rs | 9 + src/test/ui/impl-trait/in-trait/nested-rpitit.rs | 32 + src/test/ui/impl-trait/in-trait/object-safety.rs | 22 + .../ui/impl-trait/in-trait/object-safety.stderr | 50 + .../in-trait/opaque-in-impl-is-opaque.rs | 19 + .../in-trait/opaque-in-impl-is-opaque.stderr | 17 + src/test/ui/impl-trait/in-trait/opaque-in-impl.rs | 48 + src/test/ui/impl-trait/in-trait/reveal.rs | 18 + src/test/ui/impl-trait/in-trait/success.rs | 40 + src/test/ui/impl-trait/in-trait/wf-bounds.rs | 16 + src/test/ui/impl-trait/in-trait/wf-bounds.stderr | 33 + src/test/ui/impl-trait/issue-100075-2.rs | 8 + src/test/ui/impl-trait/issue-100075-2.stderr | 24 + src/test/ui/impl-trait/issue-100075.rs | 21 + src/test/ui/impl-trait/issue-100075.stderr | 12 + src/test/ui/impl-trait/issue-103599.rs | 10 + src/test/ui/impl-trait/issue-103599.stderr | 14 + src/test/ui/impl-trait/issue-99914.rs | 13 + src/test/ui/impl-trait/issue-99914.stderr | 21 + src/test/ui/impl-trait/issues/issue-78722.rs | 2 +- src/test/ui/impl-trait/issues/issue-78722.stderr | 2 +- .../ui/impl-trait/nested-return-type2-tait2.stderr | 2 +- .../ui/impl-trait/nested-return-type2-tait3.stderr | 2 +- .../nested-rpit-with-anonymous-lifetimes.rs | 23 + src/test/ui/impl-trait/nested_impl_trait.stderr | 4 +- ...nsafe-trait-in-return-position-dyn-trait.stderr | 4 +- ...safe-trait-in-return-position-impl-trait.stderr | 4 +- ...t-to-type-err-cause-on-impl-trait-return.stderr | 96 +- ...projection-mismatch-in-impl-where-clause.stderr | 2 +- .../impl-trait/suggest-calling-rpit-closure.stderr | 2 +- src/test/ui/impl-trait/where-allowed.stderr | 6 + .../assoc-ty-wf-used-to-get-assoc-ty.rs | 27 + .../assoc-ty-wf-used-to-get-assoc-ty.stderr | 15 + .../impl-header-unnormalized-types.rs | 28 + .../impl-header-unnormalized-types.stderr | 20 + src/test/ui/implied-bounds/issue-100690.rs | 45 + src/test/ui/implied-bounds/issue-100690.stderr | 22 + src/test/ui/implied-bounds/issue-101951.rs | 50 + src/test/ui/index-help.stderr | 2 +- src/test/ui/indexing-requires-a-uint.stderr | 2 +- src/test/ui/inference/issue-71732.stderr | 6 +- src/test/ui/inference/issue-86162-1.stderr | 2 +- src/test/ui/inference/issue-86162-2.stderr | 2 +- .../expr-struct-type-relative-gat.rs | 2 - .../expr-struct-type-relative-gat.stderr | 2 +- src/test/ui/integral-indexing.stderr | 16 +- .../interior-mutability/interior-mutability.stderr | 8 +- .../intrinsics/const-eval-select-backtrace-std.rs | 6 + .../const-eval-select-backtrace-std.run.stderr | 2 + .../ui/intrinsics/const-eval-select-backtrace.rs | 18 + .../const-eval-select-backtrace.run.stderr | 2 + src/test/ui/intrinsics/const-eval-select-bad.rs | 14 +- .../ui/intrinsics/const-eval-select-bad.stderr | 85 +- src/test/ui/issue-94866.stderr | 6 +- src/test/ui/issues/auxiliary/issue-2380.rs | 4 +- ...50-normalization-ice-exposed-by-mir-inlining.rs | 39 - src/test/ui/issues/issue-100605.rs | 9 + src/test/ui/issues/issue-100605.stderr | 46 + src/test/ui/issues/issue-10682.rs | 4 +- src/test/ui/issues/issue-10767.rs | 4 +- src/test/ui/issues/issue-10802.rs | 9 +- src/test/ui/issues/issue-11192.rs | 8 +- src/test/ui/issues/issue-11192.stderr | 2 +- src/test/ui/issues/issue-11374.stderr | 2 +- src/test/ui/issues/issue-11515.rs | 6 +- src/test/ui/issues/issue-11515.stderr | 6 +- src/test/ui/issues/issue-11552.rs | 6 +- src/test/ui/issues/issue-11844.rs | 4 +- src/test/ui/issues/issue-11844.stderr | 2 +- src/test/ui/issues/issue-12127.rs | 4 +- src/test/ui/issues/issue-13323.rs | 3 +- src/test/ui/issues/issue-14399.rs | 4 +- src/test/ui/issues/issue-14915.rs | 4 +- src/test/ui/issues/issue-14915.stderr | 2 +- src/test/ui/issues/issue-15524.rs | 16 - src/test/ui/issues/issue-15524.stderr | 40 - src/test/ui/issues/issue-15571.rs | 7 +- src/test/ui/issues/issue-15763.rs | 9 +- src/test/ui/issues/issue-16538.mir.stderr | 1 + src/test/ui/issues/issue-16538.thir.stderr | 1 + src/test/ui/issues/issue-16739.rs | 7 +- src/test/ui/issues/issue-16774.rs | 3 +- src/test/ui/issues/issue-16939.stderr | 2 +- src/test/ui/issues/issue-17252.stderr | 2 +- src/test/ui/issues/issue-17322.rs | 4 +- src/test/ui/issues/issue-18611.stderr | 8 +- src/test/ui/issues/issue-18819.stderr | 12 +- src/test/ui/issues/issue-20162.stderr | 6 +- src/test/ui/issues/issue-20413.stderr | 16 +- src/test/ui/issues/issue-20605.stderr | 4 +- src/test/ui/issues/issue-20831-debruijn.stderr | 24 +- src/test/ui/issues/issue-21033.rs | 5 +- src/test/ui/issues/issue-21763.stderr | 6 +- src/test/ui/issues/issue-21950.stderr | 18 +- src/test/ui/issues/issue-22872.stderr | 2 +- src/test/ui/issues/issue-2288.rs | 4 +- src/test/ui/issues/issue-23024.rs | 3 +- src/test/ui/issues/issue-23024.stderr | 6 +- src/test/ui/issues/issue-23122-2.stderr | 7 +- src/test/ui/issues/issue-23302-3.stderr | 4 +- src/test/ui/issues/issue-23491.rs | 3 +- .../ui/issues/issue-23611-enum-swap-in-drop.rs | 2 +- src/test/ui/issues/issue-25901.stderr | 1 + src/test/ui/issues/issue-26217.stderr | 6 + src/test/ui/issues/issue-2708.rs | 4 +- src/test/ui/issues/issue-2734.rs | 8 +- src/test/ui/issues/issue-2735.rs | 8 +- src/test/ui/issues/issue-28344.stderr | 4 +- src/test/ui/issues/issue-2935.rs | 3 +- src/test/ui/issues/issue-3026.rs | 4 +- src/test/ui/issues/issue-31173.rs | 11 +- src/test/ui/issues/issue-31173.stderr | 42 +- src/test/ui/issues/issue-3121.rs | 3 +- src/test/ui/issues/issue-3214.stderr | 5 +- src/test/ui/issues/issue-32709.stderr | 2 +- src/test/ui/issues/issue-3290.rs | 3 +- src/test/ui/issues/issue-33941.rs | 6 +- src/test/ui/issues/issue-33941.stderr | 18 +- src/test/ui/issues/issue-34334.stderr | 6 +- src/test/ui/issues/issue-34349.stderr | 10 +- src/test/ui/issues/issue-3447.rs | 3 +- src/test/ui/issues/issue-35241.stderr | 4 +- src/test/ui/issues/issue-35570.rs | 3 +- src/test/ui/issues/issue-35570.stderr | 12 +- src/test/ui/issues/issue-3794.rs | 3 +- src/test/ui/issues/issue-3878.rs | 3 +- src/test/ui/issues/issue-38821.stderr | 2 +- src/test/ui/issues/issue-39970.stderr | 2 +- src/test/ui/issues/issue-40510-3.stderr | 4 + src/test/ui/issues/issue-40827.stderr | 4 +- src/test/ui/issues/issue-41139.stderr | 4 +- src/test/ui/issues/issue-41726.stderr | 4 + src/test/ui/issues/issue-41974.stderr | 4 +- src/test/ui/issues/issue-43988.stderr | 4 + src/test/ui/issues/issue-47511.stderr | 3 +- src/test/ui/issues/issue-4759.rs | 4 +- src/test/ui/issues/issue-4935.stderr | 2 +- src/test/ui/issues/issue-4972.rs | 1 - src/test/ui/issues/issue-4972.stderr | 2 +- src/test/ui/issues/issue-49824.stderr | 4 + src/test/ui/issues/issue-5100.rs | 2 +- src/test/ui/issues/issue-5192.rs | 4 +- src/test/ui/issues/issue-5439.rs | 4 +- src/test/ui/issues/issue-5439.stderr | 6 +- src/test/ui/issues/issue-5666.rs | 5 +- src/test/ui/issues/issue-5718.rs | 4 +- src/test/ui/issues/issue-57362-1.stderr | 4 +- src/test/ui/issues/issue-5884.rs | 4 +- src/test/ui/issues/issue-59488.rs | 1 + src/test/ui/issues/issue-59488.stderr | 41 +- src/test/ui/issues/issue-5997-enum.stderr | 8 +- src/test/ui/issues/issue-5997-struct.stderr | 8 +- src/test/ui/issues/issue-60218.stderr | 4 +- src/test/ui/issues/issue-62480.rs | 2 - src/test/ui/issues/issue-62480.stderr | 4 +- src/test/ui/issues/issue-6318.rs | 4 +- src/test/ui/issues/issue-6557.rs | 1 - src/test/ui/issues/issue-66706.rs | 3 - src/test/ui/issues/issue-66706.stderr | 35 +- .../issue-66923-show-error-for-correct-call.stderr | 12 +- .../issue-67039-unsound-pin-partialeq.stderr | 2 +- .../issue-69396-const-no-type-in-macro.stderr | 14 +- src/test/ui/issues/issue-69455.stderr | 2 +- src/test/ui/issues/issue-7013.rs | 4 +- src/test/ui/issues/issue-7013.stderr | 8 +- ...ssue-70724-add_type_neq_err_label-unwrap.stderr | 9 +- src/test/ui/issues/issue-7364.rs | 4 +- src/test/ui/issues/issue-7364.stderr | 6 +- ...ssue-7673-cast-generically-implemented-trait.rs | 4 +- src/test/ui/issues/issue-86756.stderr | 5 +- src/test/ui/issues/issue-9129.rs | 4 +- src/test/ui/issues/issue-9382.rs | 5 +- src/test/ui/issues/issue-99875.rs | 16 + src/test/ui/issues/issue-99875.stderr | 33 + src/test/ui/iterators/collect-into-array.rs | 1 + src/test/ui/iterators/collect-into-array.stderr | 6 +- src/test/ui/iterators/collect-into-slice.rs | 5 + src/test/ui/iterators/collect-into-slice.stderr | 23 +- src/test/ui/iterators/integral.stderr | 24 +- src/test/ui/iterators/issue-28098.rs | 4 + src/test/ui/iterators/issue-28098.stderr | 50 +- .../ui/iterators/issue-58952-filter-type-length.rs | 2 +- src/test/ui/iterators/ranges.stderr | 4 +- src/test/ui/iterators/string.stderr | 4 +- src/test/ui/json-and-color.rs | 3 - src/test/ui/json-and-color.stderr | 2 - src/test/ui/json-and-error-format.rs | 3 - src/test/ui/json-and-error-format.stderr | 2 - src/test/ui/json-bom-plus-crlf-multifile-aux.rs | 27 - src/test/ui/json-bom-plus-crlf-multifile.rs | 11 - src/test/ui/json-bom-plus-crlf-multifile.stderr | 114 - src/test/ui/json-bom-plus-crlf.rs | 26 - src/test/ui/json-bom-plus-crlf.stderr | 114 - src/test/ui/json-invalid.rs | 3 - src/test/ui/json-invalid.stderr | 2 - src/test/ui/json-multiple.polonius.stderr | 1 - src/test/ui/json-multiple.rs | 5 - src/test/ui/json-multiple.stderr | 1 - src/test/ui/json-options.polonius.stderr | 1 - src/test/ui/json-options.rs | 5 - src/test/ui/json-options.stderr | 1 - src/test/ui/json-short.rs | 1 - src/test/ui/json-short.stderr | 19 - src/test/ui/json/json-and-color.rs | 3 + src/test/ui/json/json-and-color.stderr | 2 + src/test/ui/json/json-and-error-format.rs | 3 + src/test/ui/json/json-and-error-format.stderr | 2 + .../ui/json/json-bom-plus-crlf-multifile-aux.rs | 27 + src/test/ui/json/json-bom-plus-crlf-multifile.rs | 11 + .../ui/json/json-bom-plus-crlf-multifile.stderr | 114 + src/test/ui/json/json-bom-plus-crlf.rs | 26 + src/test/ui/json/json-bom-plus-crlf.stderr | 114 + src/test/ui/json/json-invalid.rs | 3 + src/test/ui/json/json-invalid.stderr | 2 + src/test/ui/json/json-multiple.polonius.stderr | 1 + src/test/ui/json/json-multiple.rs | 5 + src/test/ui/json/json-multiple.stderr | 1 + src/test/ui/json/json-options.polonius.stderr | 1 + src/test/ui/json/json-options.rs | 5 + src/test/ui/json/json-options.stderr | 1 + src/test/ui/json/json-short.rs | 1 + src/test/ui/json/json-short.stderr | 19 + src/test/ui/kindck/kindck-impl-type-params-2.rs | 2 +- .../ui/kindck/kindck-impl-type-params-2.stderr | 4 +- src/test/ui/kindck/kindck-impl-type-params.stderr | 12 +- .../kindck/kindck-inherited-copy-bound.curr.stderr | 6 +- ...ited-copy-bound.object_safe_for_dispatch.stderr | 6 +- src/test/ui/kindck/kindck-nonsendable-1.stderr | 10 +- src/test/ui/kindck/kindck-send-object.stderr | 12 +- src/test/ui/kindck/kindck-send-object1.stderr | 12 +- src/test/ui/kindck/kindck-send-object2.stderr | 12 +- src/test/ui/kindck/kindck-send-owned.stderr | 6 +- src/test/ui/label/label_break_value_continue.rs | 1 - .../ui/label/label_break_value_continue.stderr | 6 +- .../ui/label/label_break_value_desugared_break.rs | 9 +- .../ui/label/label_break_value_illegal_uses.fixed | 1 - .../ui/label/label_break_value_illegal_uses.rs | 1 - .../ui/label/label_break_value_illegal_uses.stderr | 8 +- .../ui/label/label_break_value_unlabeled_break.rs | 1 - .../label/label_break_value_unlabeled_break.stderr | 4 +- ...96158-scalarpair-payload-might-be-uninit.stderr | 4 +- .../ui/layout/zero-sized-array-enum-niche.stderr | 2 +- .../ui/lazy-type-alias-impl-trait/branches.stderr | 6 +- .../lazy-type-alias-impl-trait/recursion4.stderr | 12 +- src/test/ui/let-else/const-fn.rs | 19 + src/test/ui/let-else/issue-100103.rs | 15 + src/test/ui/let-else/issue-102317.rs | 20 + src/test/ui/let-else/issue-94176.rs | 10 + src/test/ui/let-else/issue-94176.stderr | 19 + src/test/ui/let-else/issue-99975.rs | 20 + src/test/ui/let-else/let-else-allow-in-expr.rs | 2 - src/test/ui/let-else/let-else-allow-in-expr.stderr | 6 +- src/test/ui/let-else/let-else-allow-unused.rs | 2 +- .../let-else-binding-explicit-mut-annotated.rs | 2 +- .../let-else-binding-explicit-mut-borrow.rs | 4 +- .../let-else/let-else-binding-explicit-mut-pass.rs | 2 +- .../ui/let-else/let-else-binding-explicit-mut.rs | 2 +- src/test/ui/let-else/let-else-binding-immutable.rs | 2 +- src/test/ui/let-else/let-else-bindings.rs | 2 +- .../ui/let-else/let-else-bool-binop-init.fixed | 2 +- src/test/ui/let-else/let-else-bool-binop-init.rs | 2 +- .../ui/let-else/let-else-brace-before-else.fixed | 2 +- src/test/ui/let-else/let-else-brace-before-else.rs | 2 +- src/test/ui/let-else/let-else-check.rs | 2 - src/test/ui/let-else/let-else-check.stderr | 6 +- .../let-else/let-else-deref-coercion-annotated.rs | 2 +- src/test/ui/let-else/let-else-deref-coercion.rs | 2 +- src/test/ui/let-else/let-else-destructuring.rs | 1 - src/test/ui/let-else/let-else-destructuring.stderr | 4 +- src/test/ui/let-else/let-else-drop-order.rs | 270 ++ .../ui/let-else/let-else-drop-order.run.stdout | 51 + src/test/ui/let-else/let-else-if.rs | 2 - src/test/ui/let-else/let-else-if.stderr | 2 +- src/test/ui/let-else/let-else-irrefutable.rs | 2 +- src/test/ui/let-else/let-else-missing-semicolon.rs | 2 - .../ui/let-else/let-else-missing-semicolon.stderr | 4 +- src/test/ui/let-else/let-else-no-double-error.rs | 2 +- src/test/ui/let-else/let-else-non-copy.rs | 2 +- src/test/ui/let-else/let-else-non-diverging.rs | 2 - src/test/ui/let-else/let-else-non-diverging.stderr | 6 +- src/test/ui/let-else/let-else-ref-bindings-pass.rs | 2 +- src/test/ui/let-else/let-else-ref-bindings.rs | 2 +- src/test/ui/let-else/let-else-run-pass.rs | 2 +- src/test/ui/let-else/let-else-scope.rs | 2 - src/test/ui/let-else/let-else-scope.stderr | 2 +- src/test/ui/let-else/let-else-slicing-error.rs | 2 +- .../let-else/let-else-source-expr-nomove-pass.rs | 2 +- src/test/ui/let-else/let-else-temp-borrowck.rs | 2 +- .../ui/let-else/let-else-temporary-lifetime.rs | 13 +- src/test/ui/let-else/let-else-then-diverge.rs | 19 + src/test/ui/let-else/let-else-then-diverge.stderr | 14 + src/test/ui/let-else/let-else.rs | 8 + src/test/ui/lexical-scopes.stderr | 2 + src/test/ui/lifetimes/fullwidth-ampersand.rs | 7 + src/test/ui/lifetimes/fullwidth-ampersand.stderr | 26 + src/test/ui/lifetimes/issue-26638.stderr | 2 +- ...ision-return-type-requires-explicit-lifetime.rs | 6 + ...n-return-type-requires-explicit-lifetime.stderr | 14 +- src/test/ui/lifetimes/missing-lifetime-in-alias.rs | 2 - .../ui/lifetimes/missing-lifetime-in-alias.stderr | 10 +- ...gest-introducing-and-adding-missing-lifetime.rs | 9 + ...-introducing-and-adding-missing-lifetime.stderr | 23 + src/test/ui/limits/issue-17913.rs | 6 +- .../linkage-attr/link-attr-validation-early.stderr | 4 +- .../linkage-attr/link-attr-validation-late.stderr | 4 +- .../allowed-group-warn-by-default-lint.stderr | 15 +- src/test/ui/lint/force-warn/cap-lints-allow.stderr | 15 +- ...t-group-allowed-cli-warn-by-default-lint.stderr | 15 +- .../lint-group-allowed-lint-group.stderr | 15 +- .../lint-group-allowed-warn-by-default-lint.stderr | 15 +- src/test/ui/lint/issue-101284.rs | 15 + ...sue-70819-dont-override-forbid-in-same-scope.rs | 2 +- .../ui/lint/let_underscore/let_underscore_drop.rs | 14 + .../lint/let_underscore/let_underscore_drop.stderr | 22 + .../ui/lint/let_underscore/let_underscore_lock.rs | 7 + .../lint/let_underscore/let_underscore_lock.stderr | 20 + src/test/ui/lint/lint-attr-everywhere-early.rs | 176 + src/test/ui/lint/lint-attr-everywhere-early.stderr | 486 +++ src/test/ui/lint/lint-attr-everywhere-late.rs | 197 + src/test/ui/lint/lint-attr-everywhere-late.stderr | 428 +++ .../ui/lint/must_not_suspend/ref-drop-tracking.rs | 30 + .../lint/must_not_suspend/ref-drop-tracking.stderr | 27 + .../lint/must_not_suspend/ref.drop_tracking.stderr | 27 + .../must_not_suspend/ref.no_drop_tracking.stderr | 27 + src/test/ui/lint/must_not_suspend/ref.rs | 12 +- src/test/ui/lint/must_not_suspend/ref.stderr | 27 - src/test/ui/lint/uninitialized-zeroed.rs | 15 +- src/test/ui/lint/uninitialized-zeroed.stderr | 60 +- .../unused/issue-54180-unused-ref-field.stderr | 12 +- .../ui/lint/unused/lint-unused-variables.stderr | 28 +- .../ui/lint/unused/unused_attributes-must_use.rs | 6 + .../lint/unused/unused_attributes-must_use.stderr | 14 +- src/test/ui/lint/unused_labels.rs | 1 - src/test/ui/lint/unused_labels.stderr | 20 +- .../ui/lint/unused_parens_multibyte_recovery.rs | 11 + .../lint/unused_parens_multibyte_recovery.stderr | 43 + src/test/ui/liveness/liveness-consts.stderr | 12 +- src/test/ui/lowering/issue-96847.rs | 14 + .../lub-glb/old-lub-glb-hr-noteq1.nllleak.stderr | 2 - .../lub-glb/old-lub-glb-hr-noteq1.nllnoleak.stderr | 2 - src/test/ui/macros/auxiliary/issue-100199.rs | 18 + src/test/ui/macros/issue-100199.rs | 16 + src/test/ui/macros/issue-100199.stderr | 15 + src/test/ui/macros/stringify.rs | 11 +- src/test/ui/malformed/malformed-regressions.stderr | 4 +- src/test/ui/match/issue-42679.rs | 7 +- src/test/ui/match/match_non_exhaustive.rs | 2 +- src/test/ui/match/match_non_exhaustive.stderr | 8 +- src/test/ui/methods/method-call-err-msg.stderr | 16 +- .../method-on-ambiguous-numeric-type.stderr | 8 +- .../ui/mir/issue-100476-recursion-check-blewup.rs | 42 - src/test/ui/mir/issue-101844.rs | 73 + src/test/ui/mir/issue-102389.rs | 8 + src/test/ui/mir/issue-102389.stderr | 9 + src/test/ui/mir/issue-99852.rs | 24 + src/test/ui/mir/issue-99866.rs | 25 + .../ice-issue-100550-unnormalized-projection.rs | 30 + .../ui/mir/mir_codegen_calls_diverging_drops.rs | 1 + src/test/ui/mismatched_types/E0409.stderr | 4 + src/test/ui/mismatched_types/E0631.rs | 2 +- src/test/ui/mismatched_types/E0631.stderr | 8 +- src/test/ui/mismatched_types/closure-arg-count.rs | 2 +- .../ui/mismatched_types/closure-arg-count.stderr | 8 +- ...st-boxed-trait-objects-instead-of-impl-trait.rs | 23 + ...oxed-trait-objects-instead-of-impl-trait.stderr | 26 + .../mismatched_types/dont-point-return-on-E0308.rs | 18 + .../dont-point-return-on-E0308.stderr | 19 + src/test/ui/mismatched_types/issue-19109.stderr | 2 +- src/test/ui/mismatched_types/issue-84976.stderr | 5 + .../method-help-unsatisfied-bound.stderr | 6 +- src/test/ui/mismatched_types/normalize-fn-sig.rs | 16 + .../ui/mismatched_types/normalize-fn-sig.stderr | 19 + .../mismatched_types/overloaded-calls-bad.stderr | 4 +- ...dding-or-removing-ref-for-binding-pattern.fixed | 21 + ...t-adding-or-removing-ref-for-binding-pattern.rs | 21 + ...ding-or-removing-ref-for-binding-pattern.stderr | 49 + ...boxed-trait-objects-instead-of-impl-trait.fixed | 28 + ...st-boxed-trait-objects-instead-of-impl-trait.rs | 28 + ...oxed-trait-objects-instead-of-impl-trait.stderr | 47 + src/test/ui/modules/auxiliary/dummy_lib.rs | 2 + src/test/ui/modules/special_module_name.rs | 8 + src/test/ui/modules/special_module_name.stderr | 37 + src/test/ui/modules/special_module_name_ignore.rs | 9 + src/test/ui/moves/move-out-of-array-ref.stderr | 4 +- src/test/ui/moves/move-out-of-slice-2.stderr | 8 +- src/test/ui/mutexguard-sync.stderr | 2 +- src/test/ui/namespace/namespace-mix.stderr | 8 +- src/test/ui/nested-ty-params.stderr | 12 +- .../defaulted-never-note.fallback.stderr | 6 +- src/test/ui/never_type/defaulted-never-note.rs | 1 + .../diverging-fallback-no-leak.fallback.stderr | 6 +- .../fallback-closure-wrap.fallback.stderr | 2 +- src/test/ui/never_type/fallback-closure-wrap.rs | 4 +- .../feature-gate-never_type_fallback.stderr | 8 +- ...er-value-fallback-issue-66757.nofallback.stderr | 6 +- .../escape-argument-callee.stderr | 10 +- .../closure-requirements/escape-argument.stderr | 10 +- .../escape-upvar-nested.stderr | 10 +- .../closure-requirements/escape-upvar-ref.stderr | 10 +- .../propagate-approximated-fail-no-postdom.stderr | 10 +- .../propagate-approximated-ref.stderr | 10 +- ...shorter-to-static-comparing-against-free.stderr | 20 +- ...-approximated-shorter-to-static-no-bound.stderr | 12 +- ...proximated-shorter-to-static-wrong-bound.stderr | 12 +- .../propagate-approximated-val.stderr | 10 +- .../propagate-despite-same-free-region.stderr | 10 +- ...ate-fail-to-approximate-longer-no-bounds.stderr | 10 +- ...-fail-to-approximate-longer-wrong-bounds.stderr | 10 +- .../propagate-from-trait-match.stderr | 6 +- .../return-wrong-bound-region.stderr | 7 +- .../ui/nll/issue-21232-partial-init-and-use.rs | 2 +- src/test/ui/nll/issue-51244.stderr | 2 +- .../ui/nll/local-outlives-static-via-hrtb.stderr | 12 + src/test/ui/nll/normalization-bounds-error.stderr | 8 +- src/test/ui/nll/polonius/assignment-kills-loans.rs | 2 +- .../relate_tys/impl-fn-ignore-binder-via-bottom.rs | 1 + .../impl-fn-ignore-binder-via-bottom.stderr | 11 +- .../projection-no-regions-closure.stderr | 22 +- .../projection-one-region-closure.stderr | 22 +- ...rojection-one-region-trait-bound-closure.stderr | 27 +- ...on-one-region-trait-bound-static-closure.stderr | 26 +- ...rojection-two-region-trait-bound-closure.stderr | 43 +- ...ty-param-closure-approximate-lower-bound.stderr | 14 +- ...-param-closure-outlives-from-return-type.stderr | 6 +- ...param-closure-outlives-from-where-clause.stderr | 27 +- src/test/ui/nll/type-test-universe.stderr | 6 + .../nll/user-annotations/adt-nullary-enums.stderr | 5 +- .../user-annotations/adt-tuple-struct-calls.stderr | 10 +- src/test/ui/nll/user-annotations/fns.stderr | 6 +- .../ui/nll/user-annotations/method-call.stderr | 5 +- .../ui/nll/user-annotations/method-ufcs-3.stderr | 5 +- src/test/ui/no-send-res-ports.stderr | 17 +- src/test/ui/not-clone-closure.stderr | 6 +- src/test/ui/not-enough-arguments.stderr | 4 +- src/test/ui/not-panic/not-panic-safe-2.stderr | 12 +- src/test/ui/not-panic/not-panic-safe-3.stderr | 12 +- src/test/ui/not-panic/not-panic-safe-4.stderr | 12 +- src/test/ui/not-panic/not-panic-safe-5.stderr | 6 +- src/test/ui/not-panic/not-panic-safe-6.stderr | 12 +- .../ui/object-lifetime/object-lifetime-default.rs | 44 +- .../object-lifetime/object-lifetime-default.stderr | 60 +- src/test/ui/object-safety/issue-19538.stderr | 2 +- .../object-safety-associated-consts.curr.stderr | 4 +- ...sociated-consts.object_safe_for_dispatch.stderr | 2 +- .../ui/object-safety/object-safety-bounds.stderr | 4 +- .../object-safety-generics.curr.stderr | 8 +- ...safety-generics.object_safe_for_dispatch.stderr | 4 +- .../object-safety-mentions-Self.curr.stderr | 8 +- ...y-mentions-Self.object_safe_for_dispatch.stderr | 4 +- .../object-safety-no-static.curr.stderr | 4 +- ...afety-no-static.object_safe_for_dispatch.stderr | 2 +- .../object-safety-sized-2.curr.stderr | 4 +- ...-safety-sized-2.object_safe_for_dispatch.stderr | 2 +- .../object-safety/object-safety-sized.curr.stderr | 4 +- ...ct-safety-sized.object_safe_for_dispatch.stderr | 2 +- src/test/ui/on-unimplemented/enclosing-scope.rs | 27 - .../ui/on-unimplemented/enclosing-scope.stderr | 86 - src/test/ui/on-unimplemented/multiple-impls.rs | 3 + src/test/ui/on-unimplemented/multiple-impls.stderr | 51 +- src/test/ui/on-unimplemented/on-impl.rs | 1 + src/test/ui/on-unimplemented/on-impl.stderr | 15 +- src/test/ui/on-unimplemented/parent-label.rs | 27 + src/test/ui/on-unimplemented/parent-label.stderr | 69 + src/test/ui/on-unimplemented/slice-index.stderr | 4 +- src/test/ui/or-patterns/inner-or-pat.or3.stderr | 11 + src/test/ui/or-patterns/inner-or-pat.or4.stderr | 11 + src/test/ui/or-patterns/inner-or-pat.rs | 73 + .../ui/or-patterns/or-patterns-syntactic-pass.rs | 16 +- .../or-patterns/or-patterns-syntactic-pass.stderr | 13 + src/test/ui/parser/bad-interpolated-block.rs | 2 - src/test/ui/parser/bad-interpolated-block.stderr | 6 +- ...nstraints-before-generic-args-syntactic-pass.rs | 4 + ...aints-before-generic-args-syntactic-pass.stderr | 24 + .../do-not-suggest-semicolon-before-array.rs | 8 + .../do-not-suggest-semicolon-before-array.stderr | 10 + ...een-macro-without-exclamation-mark-and-array.rs | 3 + ...macro-without-exclamation-mark-and-array.stderr | 8 + src/test/ui/parser/fn-defined-using-def.rs | 10 + src/test/ui/parser/fn-defined-using-def.stderr | 10 + src/test/ui/parser/fn-defined-using-fun.rs | 10 + src/test/ui/parser/fn-defined-using-fun.stderr | 10 + src/test/ui/parser/fn-defined-using-func.rs | 10 + src/test/ui/parser/fn-defined-using-func.stderr | 10 + src/test/ui/parser/fn-defined-using-function.rs | 10 + .../ui/parser/fn-defined-using-function.stderr | 10 + src/test/ui/parser/fn-header-semantic-fail.rs | 2 - src/test/ui/parser/fn-header-semantic-fail.stderr | 184 +- .../parser/impl-item-type-no-body-semantic-fail.rs | 2 - .../impl-item-type-no-body-semantic-fail.stderr | 20 +- src/test/ui/parser/increment-notfixed.stderr | 30 +- src/test/ui/parser/issue-100197-mut-let.fixed | 6 + src/test/ui/parser/issue-100197-mut-let.rs | 6 + src/test/ui/parser/issue-100197-mut-let.stderr | 8 + src/test/ui/parser/issue-101477-enum.fixed | 10 + src/test/ui/parser/issue-101477-enum.rs | 10 + src/test/ui/parser/issue-101477-enum.stderr | 14 + src/test/ui/parser/issue-101477-let.fixed | 6 + src/test/ui/parser/issue-101477-let.rs | 6 + src/test/ui/parser/issue-101477-let.stderr | 8 + .../issue-99910-const-let-mutually-exclusive.fixed | 8 + .../issue-99910-const-let-mutually-exclusive.rs | 8 + ...issue-99910-const-let-mutually-exclusive.stderr | 14 + src/test/ui/parser/issues/issue-14303-enum.rs | 6 - src/test/ui/parser/issues/issue-14303-enum.stderr | 8 - src/test/ui/parser/issues/issue-14303-fn-def.rs | 4 - .../ui/parser/issues/issue-14303-fn-def.stderr | 8 - src/test/ui/parser/issues/issue-14303-impl.rs | 6 - src/test/ui/parser/issues/issue-14303-impl.stderr | 8 - src/test/ui/parser/issues/issue-14303-path.rs | 13 - src/test/ui/parser/issues/issue-14303-path.stderr | 9 - src/test/ui/parser/issues/issue-14303-struct.rs | 6 - .../ui/parser/issues/issue-14303-struct.stderr | 8 - src/test/ui/parser/issues/issue-14303-trait.rs | 4 - src/test/ui/parser/issues/issue-14303-trait.stderr | 8 - src/test/ui/parser/issues/issue-14303.rs | 33 + src/test/ui/parser/issues/issue-14303.stderr | 39 + ...7377-invalid-syntax-in-enum-discriminant.stderr | 4 +- src/test/ui/parser/issues/issue-89574.stderr | 4 +- .../item-free-const-no-body-semantic-fail.stderr | 4 +- .../item-free-static-no-body-semantic-fail.stderr | 8 +- src/test/ui/parser/kw-in-trait-bounds.rs | 47 + src/test/ui/parser/kw-in-trait-bounds.stderr | 171 + src/test/ui/parser/labeled-no-colon-expr.rs | 2 - src/test/ui/parser/labeled-no-colon-expr.stderr | 16 +- src/test/ui/parser/public-instead-of-pub-1.fixed | 11 + src/test/ui/parser/public-instead-of-pub-1.rs | 11 + src/test/ui/parser/public-instead-of-pub-1.stderr | 13 + src/test/ui/parser/public-instead-of-pub-2.rs | 7 + src/test/ui/parser/public-instead-of-pub-2.stderr | 8 + src/test/ui/parser/public-instead-of-pub-3.fixed | 9 + src/test/ui/parser/public-instead-of-pub-3.rs | 9 + src/test/ui/parser/public-instead-of-pub-3.stderr | 13 + src/test/ui/parser/recover-field-semi.rs | 16 + src/test/ui/parser/recover-field-semi.stderr | 29 + .../ui/parser/recover-labeled-non-block-expr.fixed | 1 - .../ui/parser/recover-labeled-non-block-expr.rs | 1 - .../parser/recover-labeled-non-block-expr.stderr | 12 +- .../parser/recover-missing-semi-before-item.fixed | 61 + .../ui/parser/recover-missing-semi-before-item.rs | 61 + .../parser/recover-missing-semi-before-item.stderr | 83 + .../ui/parser/removed-syntax-field-semicolon.rs | 2 +- .../parser/removed-syntax-field-semicolon.stderr | 4 +- src/test/ui/parser/removed-syntax-static-fn.stderr | 4 +- src/test/ui/parser/struct-filed-with-attr.fixed | 18 + src/test/ui/parser/struct-filed-with-attr.rs | 18 + src/test/ui/parser/struct-filed-with-attr.stderr | 8 + src/test/ui/parser/struct-literal-in-for.stderr | 2 +- src/test/ui/parser/suggest-assoc-const.fixed | 10 + src/test/ui/parser/suggest-assoc-const.rs | 10 + src/test/ui/parser/suggest-assoc-const.stderr | 8 + src/test/ui/parser/suggest-const-for-global-var.rs | 6 + .../ui/parser/suggest-const-for-global-var.stderr | 8 + ...removing-semicolon-after-impl-trait-items.fixed | 7 + ...st-removing-semicolon-after-impl-trait-items.rs | 7 + ...emoving-semicolon-after-impl-trait-items.stderr | 15 + .../ui/parser/suggest-semicolon-before-array.fixed | 11 + .../ui/parser/suggest-semicolon-before-array.rs | 11 + .../parser/suggest-semicolon-before-array.stderr | 13 + src/test/ui/parser/trait-object-delimiters.rs | 2 +- src/test/ui/parser/trait-object-delimiters.stderr | 4 +- .../ui/parser/trait-object-trait-parens.stderr | 15 +- src/test/ui/parser/type-alias-where-fixable.fixed | 2 - src/test/ui/parser/type-alias-where-fixable.rs | 2 - src/test/ui/parser/type-alias-where-fixable.stderr | 6 +- src/test/ui/parser/type-alias-where.rs | 2 - src/test/ui/parser/type-alias-where.stderr | 4 +- src/test/ui/parser/unnecessary-let.rs | 11 + src/test/ui/parser/unnecessary-let.stderr | 20 + ...ther-can-live-while-the-other-survives-1.stderr | 10 +- .../bind-by-move-no-subbindings-fun-param.stderr | 5 +- .../borrowck-move-and-move.stderr | 37 +- .../borrowck-pat-at-and-box.stderr | 30 +- .../borrowck-pat-by-move-and-ref-inverse.stderr | 40 +- .../borrowck-pat-by-move-and-ref.stderr | 52 +- .../borrowck-pat-ref-mut-and-ref.stderr | 45 +- .../borrowck-pat-ref-mut-twice.stderr | 35 +- .../bindings-after-at/copy-and-move-mixed.stderr | 5 +- ...ult-binding-modes-both-sides-independent.stderr | 2 +- .../nested-binding-modes-mut.stderr | 2 +- .../borrowck-move-ref-pattern.stderr | 6 +- .../move-ref-patterns-closure-captures.stderr | 30 +- .../ui/pattern/rest-pat-semantic-disallowed.rs | 2 +- src/test/ui/pattern/rest-pat-syntactic.rs | 5 +- src/test/ui/pattern/rest-pat-syntactic.stderr | 24 + ...priate-missing-pattern-excluding-comments.fixed | 10 + ...propriate-missing-pattern-excluding-comments.rs | 9 + ...riate-missing-pattern-excluding-comments.stderr | 24 + .../usefulness/doc-hidden-non-exhaustive.rs | 8 +- .../usefulness/doc-hidden-non-exhaustive.stderr | 24 +- .../empty-match.exhaustive_patterns.stderr | 28 +- .../pattern/usefulness/empty-match.normal.stderr | 28 +- src/test/ui/pattern/usefulness/empty-match.rs | 12 +- src/test/ui/pattern/usefulness/issue-15129.rs | 2 +- src/test/ui/pattern/usefulness/issue-15129.stderr | 6 +- src/test/ui/pattern/usefulness/issue-31561.rs | 2 +- src/test/ui/pattern/usefulness/issue-31561.stderr | 6 +- src/test/ui/pattern/usefulness/issue-35609.stderr | 32 +- src/test/ui/pattern/usefulness/issue-39362.stderr | 4 +- src/test/ui/pattern/usefulness/issue-40221.stderr | 6 +- src/test/ui/pattern/usefulness/issue-50900.rs | 2 +- src/test/ui/pattern/usefulness/issue-50900.stderr | 6 +- src/test/ui/pattern/usefulness/issue-56379.rs | 2 +- src/test/ui/pattern/usefulness/issue-56379.stderr | 6 +- src/test/ui/pattern/usefulness/issue-72377.rs | 2 +- src/test/ui/pattern/usefulness/issue-72377.stderr | 4 +- .../ui/pattern/usefulness/match-arm-statics-2.rs | 4 +- .../pattern/usefulness/match-arm-statics-2.stderr | 12 +- .../usefulness/non-exhaustive-defined-here.rs | 32 +- .../usefulness/non-exhaustive-defined-here.stderr | 42 +- .../usefulness/non-exhaustive-match-nested.rs | 2 +- .../usefulness/non-exhaustive-match-nested.stderr | 6 +- .../ui/pattern/usefulness/non-exhaustive-match.rs | 6 +- .../pattern/usefulness/non-exhaustive-match.stderr | 20 +- .../usefulness/non-exhaustive-pattern-witness.rs | 10 +- .../non-exhaustive-pattern-witness.stderr | 28 +- .../ui/pattern/usefulness/stable-gated-patterns.rs | 2 +- .../usefulness/stable-gated-patterns.stderr | 6 +- .../struct-like-enum-nonexhaustive.stderr | 6 +- .../ui/pattern/usefulness/top-level-alternation.rs | 2 - .../usefulness/top-level-alternation.stderr | 24 +- .../pattern/usefulness/unstable-gated-patterns.rs | 2 +- .../usefulness/unstable-gated-patterns.stderr | 6 +- src/test/ui/phantom-auto-trait.stderr | 4 +- src/test/ui/privacy/access_levels.rs | 49 + src/test/ui/privacy/access_levels.stderr | 125 + src/test/ui/proc-macro/auxiliary/expand-expr.rs | 23 +- src/test/ui/proc-macro/auxiliary/re-export.rs | 19 + src/test/ui/proc-macro/crt-static.rs | 2 +- .../ui/proc-macro/dollar-crate-issue-101211.rs | 29 + src/test/ui/proc-macro/expand-to-unstable-2.rs | 17 - src/test/ui/proc-macro/expand-to-unstable-2.stderr | 10 - src/test/ui/proc-macro/inner-attrs.rs | 1 + src/test/ui/proc-macro/inner-attrs.stderr | 8 +- src/test/ui/proc-macro/inner-attrs.stdout | 356 +- src/test/ui/proc-macro/invalid-punct-ident-1.rs | 1 + .../ui/proc-macro/invalid-punct-ident-1.stderr | 2 +- src/test/ui/proc-macro/invalid-punct-ident-2.rs | 1 + .../ui/proc-macro/invalid-punct-ident-2.stderr | 2 +- src/test/ui/proc-macro/invalid-punct-ident-3.rs | 1 + .../ui/proc-macro/invalid-punct-ident-3.stderr | 2 +- src/test/ui/proc-macro/invalid-punct-ident-4.rs | 1 + .../ui/proc-macro/invalid-punct-ident-4.stderr | 6 +- src/test/ui/proc-macro/issue-36935.rs | 1 + src/test/ui/proc-macro/issue-36935.stderr | 4 +- src/test/ui/proc-macro/issue-41211.rs | 16 - src/test/ui/proc-macro/issue-41211.stderr | 22 - .../issue-76270-panic-in-libproc-macro.rs | 1 + .../issue-76270-panic-in-libproc-macro.stderr | 2 +- src/test/ui/proc-macro/issue-79148.rs | 10 + src/test/ui/proc-macro/issue-79148.stderr | 16 + src/test/ui/proc-macro/load-panic-backtrace.rs | 1 + src/test/ui/proc-macro/load-panic-backtrace.stderr | 2 +- src/test/ui/proc-macro/load-panic.rs | 1 + src/test/ui/proc-macro/load-panic.stderr | 2 +- src/test/ui/proc-macro/signature.stderr | 7 +- src/test/ui/process/core-run-destroy.rs | 1 + src/test/ui/process/process-envs.rs | 1 + src/test/ui/process/process-remove-from-env.rs | 1 + src/test/ui/process/process-sigpipe.rs | 1 + src/test/ui/ptr_ops/issue-80309-safe.rs | 1 - src/test/ui/ptr_ops/issue-80309.rs | 1 - src/test/ui/range/range-1.stderr | 6 +- src/test/ui/recursion/issue-83150.stderr | 6 +- src/test/ui/recursion/issue-95134.rs | 28 + src/test/ui/recursion/issue-95134.stderr | 7 + .../recursive-types-are-not-uninhabited.stderr | 2 +- .../do-not-suggest-adding-bound-to-opaque-type.rs | 12 + ...-not-suggest-adding-bound-to-opaque-type.stderr | 14 + ...sue-56537-closure-uses-region-from-container.rs | 2 +- src/test/ui/regions/outlives-with-missing.rs | 16 + src/test/ui/regions/outlives-with-missing.stderr | 12 + .../regions-implied-bounds-projection-gap-hr-1.rs | 3 +- ...gions-implied-bounds-projection-gap-hr-1.stderr | 17 +- src/test/ui/reify-intrinsic.stderr | 3 + src/test/ui/repr/invalid_repr_list_help.rs | 17 + src/test/ui/repr/invalid_repr_list_help.stderr | 35 + src/test/ui/resolve/bad-type-env-capture.stderr | 6 +- src/test/ui/resolve/issue-100365.rs | 50 + src/test/ui/resolve/issue-100365.stderr | 54 + src/test/ui/resolve/issue-22692.rs | 59 +- src/test/ui/resolve/issue-22692.stderr | 85 +- src/test/ui/resolve/issue-3021-c.stderr | 16 +- .../issue-70736-async-fn-no-body-def-collector.rs | 1 - ...sue-70736-async-fn-no-body-def-collector.stderr | 43 +- src/test/ui/resolve/issue-73427.rs | 6 + src/test/ui/resolve/issue-73427.stderr | 44 +- ...int-at-type-parameter-shadowing-another-type.rs | 21 + ...at-type-parameter-shadowing-another-type.stderr | 12 + src/test/ui/resolve/privacy-enum-ctor.stderr | 22 +- .../resolve-inconsistent-binding-mode.stderr | 8 + src/test/ui/resolve/resolve-inconsistent-names.rs | 1 + .../ui/resolve/resolve-inconsistent-names.stderr | 9 +- .../ui/resolve/resolve-primitive-fallback.stderr | 2 +- .../resolve-type-param-in-item-in-trait.stderr | 18 +- .../resolve/suggest-path-for-tuple-struct.stderr | 8 +- .../suggest-path-instead-of-mod-dot-item.rs | 52 + .../suggest-path-instead-of-mod-dot-item.stderr | 82 +- .../termination-trait-test-wrong-type.stderr | 2 +- .../ui/rfc-2008-non-exhaustive/enum-as-cast.rs | 8 +- .../ui/rfc-2008-non-exhaustive/enum-as-cast.stderr | 11 + .../enum_same_crate_empty_match.rs | 4 +- .../enum_same_crate_empty_match.stderr | 12 +- .../omitted-patterns.stderr | 16 +- .../stable-omitted-patterns.stderr | 2 +- .../uninhabited/match.stderr | 6 +- .../uninhabited/match_same_crate.stderr | 6 +- .../match_with_exhaustive_patterns.stderr | 6 +- .../disallowed-positions.stderr | 48 +- ...t-let-else-does-not-interact-with-let-chains.rs | 2 +- .../ui/rfc-2565-param-attrs/param-attrs-cfg.stderr | 42 +- .../import-name-type-invalid-format.rs | 9 + .../import-name-type-invalid-format.stderr | 8 + .../import-name-type-multiple.rs | 10 + .../import-name-type-multiple.stderr | 8 + .../import-name-type-unknown-value.rs | 9 + .../import-name-type-unknown-value.stderr | 8 + .../import-name-type-unsupported-link-kind.rs | 17 + .../import-name-type-unsupported-link-kind.stderr | 14 + .../import-name-type-x86-only.rs | 7 + .../import-name-type-x86-only.stderr | 8 + .../ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs | 7 +- .../link-ordinal-and-name.stderr | 19 +- .../link-ordinal-invalid-format.rs | 6 +- .../link-ordinal-invalid-format.stderr | 15 +- .../link-ordinal-missing-argument.rs | 6 +- .../link-ordinal-missing-argument.stderr | 15 +- .../ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs | 6 +- .../link-ordinal-multiple.stderr | 21 +- .../link-ordinal-not-foreign-fn.rs | 24 + .../link-ordinal-not-foreign-fn.stderr | 20 + .../rfc-2627-raw-dylib/link-ordinal-too-large.rs | 6 +- .../link-ordinal-too-large.stderr | 15 +- .../link-ordinal-too-many-arguments.rs | 6 +- .../link-ordinal-too-many-arguments.stderr | 15 +- .../link-ordinal-unsupported-link-kind.rs | 17 + .../link-ordinal-unsupported-link-kind.stderr | 14 + .../ui/rfc-2627-raw-dylib/multiple-declarations.rs | 1 - .../multiple-declarations.stderr | 13 +- .../rfc-2627-raw-dylib/raw-dylib-windows-only.rs | 3 +- .../raw-dylib-windows-only.stderr | 13 +- src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs | 2 - .../ui/rfc-2627-raw-dylib/unsupported-abi.stderr | 2 +- .../const-default-method-bodies.stderr | 10 +- .../const-drop-fail.precise.stderr | 8 +- .../const-drop-fail.stock.stderr | 8 +- .../cross-crate.gatednc.stderr | 10 +- .../cross-crate.stocknc.stderr | 10 +- ...fault-method-body-is-const-same-trait-ck.stderr | 10 +- .../ui/rfc-2632-const-trait-impl/issue-100222.rs | 29 + .../trait-where-clause.stderr | 12 +- .../ui/rfc-2632-const-trait-impl/without-tilde.rs | 2 +- .../rfc-2632-const-trait-impl/without-tilde.stderr | 6 +- .../rfc-2396-target_feature-11/fn-traits.stderr | 12 +- .../rust-2021/reserved-prefixes-migration.stderr | 25 +- src/test/ui/rust-2021/reserved-prefixes.stderr | 45 +- src/test/ui/sanitize/memory-eager.rs | 38 + src/test/ui/sanitize/memory.rs | 14 +- ...rbitrary-self-types-not-object-safe.curr.stderr | 2 +- ...not-object-safe.object_safe_for_dispatch.stderr | 2 +- src/test/ui/simd/intrinsic/ptr-cast.rs | 33 + ...ust-2021-incompatible-closure-captures-93117.rs | 5 +- ...2021-incompatible-closure-captures-93117.stderr | 46 +- src/test/ui/span/issue-34264.stderr | 6 +- src/test/ui/span/issue-35987.stderr | 4 +- src/test/ui/span/issue-36530.rs | 12 - src/test/ui/span/issue-36530.stderr | 12 - src/test/ui/span/lint-unused-unsafe-thir.rs | 4 +- src/test/ui/span/lint-unused-unsafe-thir.stderr | 18 +- src/test/ui/span/lint-unused-unsafe.mir.stderr | 548 +-- src/test/ui/span/lint-unused-unsafe.rs | 74 +- src/test/ui/span/missing-unit-argument.stderr | 16 +- .../default-generic-associated-type-bound.rs | 3 +- .../default-generic-associated-type-bound.stderr | 6 +- src/test/ui/specialization/issue-33017.rs | 2 +- src/test/ui/specialization/issue-38091-2.stderr | 2 +- src/test/ui/specialization/issue-39448.stderr | 4 +- src/test/ui/specialization/issue-45814.stderr | 4 +- .../min_specialization/issue-79224.stderr | 22 +- .../auxiliary/ctor-stability.rs | 8 + .../stability-attribute/auxiliary/default_body.rs | 29 + src/test/ui/stability-attribute/ctor-stability.rs | 8 + .../default-body-stability-err.rs | 19 + .../default-body-stability-err.stderr | 38 + .../default-body-stability-ok-enables.rs | 18 + .../default-body-stability-ok-impls.rs | 21 + .../static/static-vec-repeat-not-constant.stderr | 1 + src/test/ui/stats/hir-stats.rs | 42 + src/test/ui/stats/hir-stats.stderr | 178 + src/test/ui/std-backtrace.rs | 2 - src/test/ui/str/str-idx.stderr | 4 +- src/test/ui/str/str-mut-idx.stderr | 4 +- src/test/ui/structs-enums/align-struct.rs | 5 +- src/test/ui/structs-enums/type-sizes.rs | 79 + src/test/ui/structs/struct-record-suggestion.fixed | 24 +- src/test/ui/structs/struct-record-suggestion.rs | 24 +- .../ui/structs/struct-record-suggestion.stderr | 23 +- .../args-instead-of-tuple-errors.stderr | 24 +- .../ui/suggestions/args-instead-of-tuple.stderr | 2 +- src/test/ui/suggestions/as-ref-2.fixed | 13 - src/test/ui/suggestions/as-ref-2.rs | 2 - src/test/ui/suggestions/as-ref-2.stderr | 10 +- src/test/ui/suggestions/as-ref.rs | 7 + src/test/ui/suggestions/as-ref.stderr | 62 +- .../ui/suggestions/assoc-const-as-field.stderr | 4 +- ...-as-arg-where-it-should-have-been-called.stderr | 4 +- src/test/ui/suggestions/bool_typo_err_suggest.rs | 12 + .../ui/suggestions/bool_typo_err_suggest.stderr | 25 + src/test/ui/suggestions/call-boxed.rs | 7 + src/test/ui/suggestions/call-boxed.stderr | 20 + src/test/ui/suggestions/call-on-missing.rs | 39 + src/test/ui/suggestions/call-on-missing.stderr | 75 + src/test/ui/suggestions/const-no-type.rs | 14 +- src/test/ui/suggestions/const-no-type.stderr | 28 +- src/test/ui/suggestions/copied-and-cloned.fixed | 23 + src/test/ui/suggestions/copied-and-cloned.rs | 23 + src/test/ui/suggestions/copied-and-cloned.stderr | 83 + src/test/ui/suggestions/deref-path-method.rs | 6 + src/test/ui/suggestions/deref-path-method.stderr | 14 + src/test/ui/suggestions/derive-clone-for-eq.stderr | 2 +- .../suggestions/derive-macro-missing-bounds.stderr | 16 +- .../dont-suggest-pin-array-dot-set.stderr | 2 +- .../ui/suggestions/dont-try-removing-the-field.rs | 17 + .../suggestions/dont-try-removing-the-field.stderr | 10 + .../expected-boxed-future-isnt-pinned.stderr | 14 +- .../field-access-considering-privacy.rs | 35 + .../field-access-considering-privacy.stderr | 14 + ...-as-arg-where-it-should-have-been-called.stderr | 4 +- .../fn-or-tuple-struct-without-args.stderr | 60 +- ...m-ref-trait-object-literal-bound-regions.stderr | 6 +- .../imm-ref-trait-object-literal.stderr | 2 +- src/test/ui/suggestions/into-str.stderr | 2 +- src/test/ui/suggestions/issue-101421.rs | 12 + src/test/ui/suggestions/issue-101421.stderr | 17 + src/test/ui/suggestions/issue-101465.rs | 25 + src/test/ui/suggestions/issue-101465.stderr | 25 + src/test/ui/suggestions/issue-101984.rs | 27 + src/test/ui/suggestions/issue-101984.stderr | 14 + src/test/ui/suggestions/issue-61963.stderr | 35 +- src/test/ui/suggestions/issue-62843.stderr | 4 +- .../ui/suggestions/issue-71394-no-from-impl.stderr | 8 +- src/test/ui/suggestions/issue-84973-2.stderr | 2 +- .../ui/suggestions/issue-84973-blacklist.stderr | 6 +- .../ui/suggestions/issue-84973-negative.stderr | 2 +- src/test/ui/suggestions/issue-84973.stderr | 2 +- src/test/ui/suggestions/issue-85347.rs | 3 +- src/test/ui/suggestions/issue-85347.stderr | 15 +- src/test/ui/suggestions/issue-89064.rs | 35 + src/test/ui/suggestions/issue-89064.stderr | 82 + src/test/ui/suggestions/issue-96223.stderr | 4 +- src/test/ui/suggestions/issue-96555.stderr | 6 +- src/test/ui/suggestions/issue-97677.fixed | 2 +- src/test/ui/suggestions/issue-97677.stderr | 4 +- .../missing-lifetimes-in-signature-2.stderr | 4 +- .../missing-lifetimes-in-signature.stderr | 18 +- src/test/ui/suggestions/many-type-ascription.rs | 4 + .../ui/suggestions/many-type-ascription.stderr | 12 + .../move-generic-to-trait-in-method-with-params.rs | 18 + ...e-generic-to-trait-in-method-with-params.stderr | 24 + src/test/ui/suggestions/option-content-move.fixed | 39 - src/test/ui/suggestions/option-content-move.rs | 2 - src/test/ui/suggestions/option-content-move.stderr | 14 +- src/test/ui/suggestions/restrict-type-not-param.rs | 12 + .../ui/suggestions/restrict-type-not-param.stderr | 26 + src/test/ui/suggestions/return-closures.rs | 13 + src/test/ui/suggestions/return-closures.stderr | 27 + src/test/ui/suggestions/return-cycle-2.rs | 14 + src/test/ui/suggestions/return-cycle-2.stderr | 12 + src/test/ui/suggestions/return-cycle.rs | 14 + src/test/ui/suggestions/return-cycle.stderr | 12 + src/test/ui/suggestions/slice-issue-87994.stderr | 16 +- .../sugg_with_positional_args_and_debug_fmt.rs | 10 + .../sugg_with_positional_args_and_debug_fmt.stderr | 21 + ...gest-adding-reference-to-trait-assoc-item.fixed | 15 + ...suggest-adding-reference-to-trait-assoc-item.rs | 15 + ...est-adding-reference-to-trait-assoc-item.stderr | 25 + .../suggest-blanket-impl-local-trait.rs | 2 +- .../suggest-blanket-impl-local-trait.stderr | 35 +- .../suggest-borrow-to-dyn-object.stderr | 4 +- .../suggestions/suggest-dereferencing-index.stderr | 2 +- .../suggest-imm-mut-trait-implementations.stderr | 6 +- src/test/ui/suggestions/suggest-methods.stderr | 8 +- .../ui/suggestions/suggest-move-lifetimes.stderr | 8 +- src/test/ui/suggestions/suggest-move-types.stderr | 4 +- src/test/ui/suggestions/suggest-ref-macro.stderr | 10 +- .../ui/suggestions/suggest-remove-refs-1.stderr | 2 +- .../ui/suggestions/suggest-remove-refs-2.stderr | 2 +- .../ui/suggestions/suggest-remove-refs-3.stderr | 2 +- ...-swapping-self-ty-and-trait-edition-2021.stderr | 5 +- .../suggest-swapping-self-ty-and-trait.stderr | 5 +- .../ui/suggestions/too-many-field-suggestions.rs | 29 + .../suggestions/too-many-field-suggestions.stderr | 44 + src/test/ui/suggestions/try-removing-the-field.rs | 17 + .../ui/suggestions/try-removing-the-field.stderr | 12 + .../suggestions/type-ascription-and-other-error.rs | 6 + .../type-ascription-and-other-error.stderr | 8 + src/test/ui/suggestions/unnamable-types.stderr | 20 +- .../use-type-argument-instead-of-assoc-type.stderr | 2 +- src/test/ui/tag-variant-disr-dup.rs | 12 - src/test/ui/tag-variant-disr-dup.stderr | 14 - src/test/ui/thir-tree.stdout | 22 +- src/test/ui/traits/alias/cross-crate.stderr | 4 +- src/test/ui/traits/alias/generic-default-in-dyn.rs | 10 + .../ui/traits/alias/generic-default-in-dyn.stderr | 39 + src/test/ui/traits/alias/self-in-const-generics.rs | 12 + .../ui/traits/alias/self-in-const-generics.stderr | 11 + src/test/ui/traits/alias/self-in-generics.rs | 15 + src/test/ui/traits/alias/self-in-generics.stderr | 11 + src/test/ui/traits/assoc-type-in-superbad.rs | 8 +- src/test/ui/traits/assoc-type-in-superbad.stderr | 6 +- .../check-trait-object-bounds-1.stderr | 4 +- .../check-trait-object-bounds-2.stderr | 4 +- .../check-trait-object-bounds-4.stderr | 4 +- .../check-trait-object-bounds-5.stderr | 6 +- .../check-trait-object-bounds-6.stderr | 6 +- src/test/ui/traits/bad-method-typaram-kind.stderr | 4 +- .../traits/bound/assoc-fn-bound-root-obligation.rs | 3 +- .../bound/assoc-fn-bound-root-obligation.stderr | 8 +- src/test/ui/traits/bound/not-on-bare-trait.stderr | 5 +- .../ui/traits/bound/on-structs-and-enums-locals.rs | 2 +- .../bound/on-structs-and-enums-locals.stderr | 6 +- .../ui/traits/bound/on-structs-and-enums-xc1.rs | 2 +- .../traits/bound/on-structs-and-enums-xc1.stderr | 6 +- src/test/ui/traits/cycle-cache-err-60010.stderr | 4 +- src/test/ui/traits/inductive-overflow/lifetime.rs | 2 +- .../ui/traits/inductive-overflow/lifetime.stderr | 4 +- .../traits/inductive-overflow/simultaneous.stderr | 2 +- .../supertrait-auto-trait.stderr | 2 +- .../ui/traits/inductive-overflow/supertrait.stderr | 2 +- .../inheritance/repeated-supertrait-ambig.stderr | 30 +- src/test/ui/traits/issue-18400.stderr | 4 +- src/test/ui/traits/issue-20692.stderr | 2 +- src/test/ui/traits/issue-38604.stderr | 2 +- src/test/ui/traits/issue-71036.rs | 2 +- src/test/ui/traits/issue-71036.stderr | 2 +- src/test/ui/traits/issue-71136.stderr | 2 +- src/test/ui/traits/issue-77982.stderr | 8 +- src/test/ui/traits/issue-82830.stderr | 2 +- src/test/ui/traits/issue-91594.stderr | 6 +- .../traits/issue-91949-hangs-on-recursion.stderr | 4 +- src/test/ui/traits/issue-97576.stderr | 8 +- src/test/ui/traits/multidispatch-bad.stderr | 2 +- .../traits/multidispatch-convert-ambig-dest.stderr | 10 +- .../explicitly-unimplemented-error-message.rs | 2 +- .../negated-auto-traits-error.stderr | 8 +- ...uggest-non-existing-fully-qualified-path.stderr | 2 +- .../object/enforce-supertrait-projection.stderr | 4 +- src/test/ui/traits/object/safety.stderr | 2 +- .../traits/pointee-tail-is-generic-errors.stderr | 8 +- .../ui/traits/resolution-in-overloaded-op.stderr | 4 +- .../traits/suggest-deferences/issue-39029.stderr | 12 +- .../traits/suggest-deferences/issue-62530.stderr | 10 +- .../ui/traits/suggest-deferences/multiple-0.stderr | 10 +- .../suggest-deferences/root-obligation.stderr | 4 +- src/test/ui/traits/suggest-where-clause.stderr | 4 +- src/test/ui/traits/test-2.stderr | 2 +- .../traits/trait-upcasting/subtrait-method.stderr | 10 +- .../ui/traits/unspecified-self-in-trait-ref.rs | 30 + .../ui/traits/unspecified-self-in-trait-ref.stderr | 105 + .../abstraction/abstracted_assume.rs | 27 +- .../abstraction/const_generic_fn.rs | 6 +- .../arrays/should_have_correct_length.rs | 4 +- .../arrays/should_inherit_alignment.rs | 9 +- .../arrays/should_require_well_defined_layout.rs | 9 +- .../should_require_well_defined_layout.stderr | 120 +- .../primitive_reprs_should_have_correct_length.rs | 11 +- ...imitive_reprs_should_have_correct_length.stderr | 420 +- .../repr/should_require_well_defined_layout.rs | 11 +- .../repr/should_require_well_defined_layout.stderr | 126 +- .../enums/should_order_correctly.rs | 9 +- .../transmutability/enums/should_pad_variants.rs | 9 +- .../enums/should_pad_variants.stderr | 20 +- .../enums/should_respect_endianness.rs | 9 +- .../enums/should_respect_endianness.stderr | 20 +- .../malformed-program-gracefulness/unknown_dst.rs | 2 +- .../malformed-program-gracefulness/unknown_src.rs | 2 +- .../unknown_src_field.rs | 2 +- .../wrong-type-assume.rs | 29 +- .../wrong-type-assume.stderr | 37 +- src/test/ui/transmutability/primitives/bool.rs | 6 +- src/test/ui/transmutability/primitives/bool.stderr | 6 +- src/test/ui/transmutability/primitives/numbers.rs | 2 +- .../ui/transmutability/primitives/numbers.stderr | 342 +- src/test/ui/transmutability/primitives/unit.rs | 9 +- src/test/ui/transmutability/primitives/unit.stderr | 20 +- src/test/ui/transmutability/references.rs | 11 +- src/test/ui/transmutability/references.stderr | 23 +- .../structs/repr/should_handle_align.rs | 11 +- .../structs/repr/should_handle_packed.rs | 11 +- .../repr/should_require_well_defined_layout.rs | 11 +- .../repr/should_require_well_defined_layout.stderr | 252 +- .../structs/should_order_fields_correctly.rs | 9 +- src/test/ui/transmutability/unions/boolish.rs | 4 +- .../unions/repr/should_handle_align.rs | 11 +- .../unions/repr/should_handle_packed.rs | 11 +- .../repr/should_require_well_defined_layout.rs | 11 +- .../repr/should_require_well_defined_layout.stderr | 42 +- .../transmutability/unions/should_pad_variants.rs | 9 +- .../unions/should_pad_variants.stderr | 20 +- ...d_permit_intersecting_if_validity_is_assumed.rs | 5 +- .../unions/should_reject_contraction.rs | 4 +- .../unions/should_reject_contraction.stderr | 6 +- .../unions/should_reject_disjoint.rs | 5 +- .../unions/should_reject_disjoint.stderr | 16 +- .../unions/should_reject_intersecting.rs | 6 +- .../unions/should_reject_intersecting.stderr | 12 +- .../should_accept_if_dst_has_private_field.rs | 6 +- .../should_accept_if_dst_has_private_variant.rs | 6 +- ...d_accept_if_dst_has_tricky_unreachable_field.rs | 6 +- .../should_accept_if_dst_has_unreachable_field.rs | 6 +- .../should_accept_if_dst_has_unreachable_ty.rs | 6 +- .../should_accept_if_src_has_private_field.rs | 3 +- .../should_accept_if_src_has_private_variant.rs | 3 +- .../should_accept_if_src_has_unreachable_field.rs | 3 +- ...ould_accept_if_src_has_unreachable_field.stderr | 2 +- .../should_accept_if_src_has_unreachable_ty.rs | 3 +- .../should_accept_if_src_has_unreachable_ty.stderr | 4 +- .../should_reject_if_dst_has_private_field.rs | 3 +- .../should_reject_if_dst_has_private_field.stderr | 8 +- .../should_reject_if_dst_has_private_variant.rs | 3 +- ...should_reject_if_dst_has_private_variant.stderr | 8 +- ...d_reject_if_dst_has_tricky_unreachable_field.rs | 3 +- .../should_reject_if_dst_has_unreachable_field.rs | 3 +- ...ould_reject_if_dst_has_unreachable_field.stderr | 8 +- .../should_reject_if_dst_has_unreachable_ty.rs | 3 +- .../should_reject_if_dst_has_unreachable_ty.stderr | 12 +- src/test/ui/try-block/try-block-bad-type.stderr | 2 +- src/test/ui/try-trait/bad-interconversion.stderr | 75 +- src/test/ui/try-trait/option-to-result.stderr | 24 +- .../ui/try-trait/try-on-option-diagnostics.stderr | 47 +- src/test/ui/try-trait/try-on-option.stderr | 24 +- src/test/ui/try-trait/try-operator-on-main.stderr | 30 +- .../ui/tuple/add-tuple-within-arguments.stderr | 4 +- src/test/ui/tuple/builtin-fail.rs | 19 + src/test/ui/tuple/builtin-fail.stderr | 55 + src/test/ui/tuple/builtin.rs | 20 + src/test/ui/tuple/wrong_argument_ice-3.stderr | 11 +- src/test/ui/tuple/wrong_argument_ice-4.stderr | 2 +- ...iant-priority-higher-than-other-inherent.stderr | 2 +- src/test/ui/type-alias-impl-trait/closure_args.rs | 16 + src/test/ui/type-alias-impl-trait/closure_args2.rs | 23 + .../ui/type-alias-impl-trait/constrain_inputs.rs | 24 +- .../type-alias-impl-trait/constrain_inputs.stderr | 58 + .../constrain_inputs_unsound.rs | 31 + .../constrain_inputs_unsound.stderr | 9 + .../generic_duplicate_param_use5.stderr | 8 +- .../generic_duplicate_param_use6.stderr | 6 +- .../generic_duplicate_param_use8.stderr | 4 +- .../generic_duplicate_param_use9.stderr | 8 +- src/test/ui/type-alias-impl-trait/issue-57961.rs | 2 +- .../ui/type-alias-impl-trait/issue-57961.stderr | 2 +- .../ui/type-alias-impl-trait/issue-60371.stderr | 2 +- .../ui/type-alias-impl-trait/issue-74280.stderr | 2 +- src/test/ui/type-alias-impl-trait/issue-90400-1.rs | 1 - .../ui/type-alias-impl-trait/issue-90400-1.stderr | 4 +- src/test/ui/type-alias-impl-trait/issue-90400-2.rs | 1 - .../ui/type-alias-impl-trait/issue-90400-2.stderr | 6 +- src/test/ui/type-alias-impl-trait/issue-98604.rs | 6 +- .../ui/type-alias-impl-trait/issue-98604.stderr | 6 +- src/test/ui/type-alias-impl-trait/issue-98608.rs | 6 +- .../ui/type-alias-impl-trait/issue-98608.stderr | 6 +- .../multiple-def-uses-in-one-fn.stderr | 2 +- .../not_a_defining_use.stderr | 4 +- .../underconstrained_generic.stderr | 2 +- src/test/ui/type/issue-100584.rs | 15 + src/test/ui/type/issue-100584.stderr | 44 + src/test/ui/type/type-alias-bounds.rs | 2 +- src/test/ui/type/type-arg-out-of-scope.stderr | 12 +- .../type-ascription-instead-of-initializer.stderr | 2 +- src/test/ui/type/type-check-defaults.stderr | 8 +- ...-check-fn-with-more-than-65535-arguments.stderr | 16 +- .../type/type-params-in-different-spaces-2.stderr | 12 +- src/test/ui/type_length_limit.stderr | 4 +- src/test/ui/typeck/assign-non-lval-derefmut.stderr | 4 +- src/test/ui/typeck/assign-non-lval-mut-ref.stderr | 4 +- src/test/ui/typeck/assign-non-lval-needs-deref.rs | 19 + .../ui/typeck/assign-non-lval-needs-deref.stderr | 16 + ...est-placeholder-to-const-static-without-type.rs | 8 + ...placeholder-to-const-static-without-type.stderr | 20 + src/test/ui/typeck/issue-100164.fixed | 9 + src/test/ui/typeck/issue-100164.rs | 9 + src/test/ui/typeck/issue-100164.stderr | 14 + src/test/ui/typeck/issue-100246.rs | 30 + src/test/ui/typeck/issue-100246.stderr | 13 + src/test/ui/typeck/issue-100285.rs | 22 + src/test/ui/typeck/issue-100285.stderr | 34 + src/test/ui/typeck/issue-29124.stderr | 8 +- src/test/ui/typeck/issue-79040.stderr | 4 +- .../ui/typeck/issue-87181/empty-tuple-method.rs | 2 +- .../typeck/issue-87181/empty-tuple-method.stderr | 6 +- src/test/ui/typeck/issue-87181/enum-variant.rs | 2 +- src/test/ui/typeck/issue-87181/enum-variant.stderr | 6 +- src/test/ui/typeck/issue-87181/tuple-field.stderr | 10 +- src/test/ui/typeck/issue-87181/tuple-method.stderr | 9 +- src/test/ui/typeck/issue-90101.stderr | 2 +- src/test/ui/typeck/issue-91210-ptr-method.stderr | 9 +- src/test/ui/typeck/issue-91633.rs | 8 + src/test/ui/typeck/issue-96738.stderr | 18 +- src/test/ui/typeck/issue-98982.rs | 9 + src/test/ui/typeck/issue-98982.stderr | 24 + .../ui/typeck/point-at-type-param-in-path-expr.rs | 6 + .../typeck/point-at-type-param-in-path-expr.stderr | 17 + src/test/ui/typeck/remove-extra-argument.stderr | 2 +- src/test/ui/typeck/struct-enum-wrong-args.stderr | 16 +- ...ng-missing-zero-to-floating-point-number.stderr | 14 +- .../typeck-default-trait-impl-negation-sync.stderr | 8 +- .../ui/typeck/typeck_type_placeholder_item.stderr | 4 +- src/test/ui/typeof/issue-100183.rs | 6 + src/test/ui/typeof/issue-100183.stderr | 14 + src/test/ui/ufcs/ufcs-qpath-self-mismatch.rs | 1 + src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 30 +- .../ui/unboxed-closures/non-tupled-arg-mismatch.rs | 8 + .../non-tupled-arg-mismatch.stderr | 17 + ...sures-infer-fn-once-move-from-projection.stderr | 12 +- ...unboxed-closures-static-call-wrong-trait.stderr | 4 +- .../unboxed-closures-type-mismatch.stderr | 6 +- .../unboxed-closures-unsafe-extern-fn.stderr | 6 +- .../unboxed-closures-wrong-abi.stderr | 6 +- ...nboxed-closures-wrong-arg-type-extern-fn.stderr | 6 +- src/test/ui/uninhabited/uninhabited-irrefutable.rs | 2 +- .../ui/uninhabited/uninhabited-irrefutable.stderr | 6 +- .../uninhabited-matches-feature-gated.stderr | 2 +- src/test/ui/union/union-generic.mirunsafeck.stderr | 4 +- .../ui/union/union-generic.thirunsafeck.stderr | 4 +- src/test/ui/unpretty/avoid-crash.rs | 4 + src/test/ui/unpretty/avoid-crash.stderr | 4 + src/test/ui/unpretty/bad-literal.rs | 8 + src/test/ui/unpretty/bad-literal.stderr | 10 + src/test/ui/unpretty/bad-literal.stdout | 11 + src/test/ui/unpretty/pretty-let-else.rs | 10 + src/test/ui/unpretty/pretty-let-else.stdout | 18 + .../rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr | 38 +- .../ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 2 - .../rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr | 24 +- src/test/ui/unsized-locals/unsized-exprs.stderr | 4 +- src/test/ui/unsized/issue-71659.stderr | 6 +- src/test/ui/unsized/issue-75707.stderr | 4 +- src/test/ui/unsized/issue-75899-but-gats.rs | 21 + src/test/ui/unsized/issue-75899.rs | 18 + src/test/ui/unsized/unsized-fn-param.stderr | 16 +- src/test/ui/unsized/unsized-struct.stderr | 4 +- src/test/ui/unsized/unsized3.stderr | 10 +- src/test/ui/unspecified-self-in-trait-ref.rs | 30 - src/test/ui/unspecified-self-in-trait-ref.stderr | 105 - .../variance-use-contravariant-struct-1.rs | 2 +- .../variance-use-contravariant-struct-2.rs | 2 +- .../ui/variance/variance-use-invariant-struct-1.rs | 2 +- src/test/ui/wait-forked-but-failed-child.rs | 1 + src/test/ui/wf/hir-wf-check-erase-regions.stderr | 4 +- src/test/ui/wf/wf-const-type.stderr | 2 +- .../ui/wf/wf-convert-unsafe-trait-obj-box.stderr | 6 +- src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr | 6 +- src/test/ui/wf/wf-foreign-fn-decl-ret.stderr | 4 +- src/test/ui/wf/wf-static-type.stderr | 2 +- src/test/ui/wf/wf-trait-fn-ret.stderr | 4 +- src/test/ui/wf/wf-unsafe-trait-obj-match.stderr | 4 +- .../where-clause-method-substituion.stderr | 4 +- .../where-clauses-method-unsatisfied.stderr | 6 +- src/tools/build-manifest/Cargo.toml | 1 - src/tools/build-manifest/src/main.rs | 2 +- src/tools/clippy/.github/workflows/clippy.yml | 1 + src/tools/clippy/.github/workflows/clippy_bors.yml | 1 + src/tools/clippy/CHANGELOG.md | 171 +- src/tools/clippy/CONTRIBUTING.md | 6 +- src/tools/clippy/Cargo.toml | 2 +- src/tools/clippy/README.md | 2 +- src/tools/clippy/book/src/configuration.md | 2 +- .../src/development/common_tools_writing_lints.md | 2 +- src/tools/clippy/clippy_dev/src/bless.rs | 2 +- src/tools/clippy/clippy_dev/src/fmt.rs | 8 +- src/tools/clippy/clippy_dev/src/lib.rs | 2 +- src/tools/clippy/clippy_dev/src/new_lint.rs | 10 +- src/tools/clippy/clippy_dev/src/update_lints.rs | 204 +- src/tools/clippy/clippy_lints/Cargo.toml | 2 +- src/tools/clippy/clippy_lints/src/as_underscore.rs | 74 - .../src/assertions_on_result_states.rs | 13 +- .../clippy/clippy_lints/src/async_yields_async.rs | 2 +- src/tools/clippy/clippy_lints/src/attrs.rs | 6 +- .../clippy/clippy_lints/src/blacklisted_name.rs | 77 - .../clippy_lints/src/blocks_in_if_conditions.rs | 5 +- .../clippy/clippy_lints/src/bool_to_int_with_if.rs | 125 + src/tools/clippy/clippy_lints/src/booleans.rs | 12 +- src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs | 99 - .../clippy/clippy_lints/src/borrow_deref_ref.rs | 7 +- src/tools/clippy/clippy_lints/src/bytecount.rs | 103 - .../clippy/clippy_lints/src/bytes_count_to_len.rs | 70 - .../case_sensitive_file_extension_comparisons.rs | 86 - .../clippy/clippy_lints/src/casts/as_underscore.rs | 25 + .../clippy/clippy_lints/src/casts/borrow_as_ptr.rs | 37 + .../clippy_lints/src/casts/cast_abs_to_unsigned.rs | 4 +- .../src/casts/cast_possible_truncation.rs | 6 +- .../clippy_lints/src/casts/cast_ptr_alignment.rs | 4 +- .../clippy_lints/src/casts/cast_sign_loss.rs | 4 +- .../src/casts/cast_slice_from_raw_parts.rs | 63 + src/tools/clippy/clippy_lints/src/casts/mod.rs | 109 +- .../clippy_lints/src/casts/unnecessary_cast.rs | 9 +- .../clippy/clippy_lints/src/checked_conversions.rs | 5 +- .../clippy/clippy_lints/src/crate_in_macro_def.rs | 4 +- src/tools/clippy/clippy_lints/src/create_dir.rs | 4 +- src/tools/clippy/clippy_lints/src/default.rs | 7 +- .../clippy_lints/src/default_numeric_fallback.rs | 4 +- src/tools/clippy/clippy_lints/src/dereference.rs | 714 +++- .../clippy/clippy_lints/src/derivable_impls.rs | 2 +- src/tools/clippy/clippy_lints/src/derive.rs | 13 +- .../clippy/clippy_lints/src/disallowed_names.rs | 77 + .../clippy/clippy_lints/src/disallowed_types.rs | 4 +- src/tools/clippy/clippy_lints/src/doc.rs | 8 +- .../clippy_lints/src/doc_link_with_quotes.rs | 2 +- src/tools/clippy/clippy_lints/src/duplicate_mod.rs | 2 +- src/tools/clippy/clippy_lints/src/entry.rs | 4 +- .../clippy/clippy_lints/src/equatable_if_let.rs | 4 +- src/tools/clippy/clippy_lints/src/escape.rs | 13 +- src/tools/clippy/clippy_lints/src/eta_reduction.rs | 26 +- .../clippy/clippy_lints/src/explicit_write.rs | 6 +- .../clippy/clippy_lints/src/fallible_impl_from.rs | 4 +- .../clippy_lints/src/floating_point_arithmetic.rs | 119 +- src/tools/clippy/clippy_lints/src/format.rs | 24 +- src/tools/clippy/clippy_lints/src/format_args.rs | 106 +- src/tools/clippy/clippy_lints/src/format_impl.rs | 13 +- .../clippy/clippy_lints/src/format_push_string.rs | 2 +- src/tools/clippy/clippy_lints/src/formatting.rs | 6 +- .../clippy/clippy_lints/src/from_str_radix_10.rs | 11 +- src/tools/clippy/clippy_lints/src/functions/mod.rs | 56 +- .../clippy/clippy_lints/src/functions/must_use.rs | 22 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 3 +- .../clippy/clippy_lints/src/functions/result.rs | 100 + .../clippy_lints/src/functions/result_unit_err.rs | 66 - .../clippy/clippy_lints/src/future_not_send.rs | 6 +- src/tools/clippy/clippy_lints/src/get_first.rs | 68 - src/tools/clippy/clippy_lints/src/if_let_mutex.rs | 52 +- .../clippy_lints/src/if_then_some_else_none.rs | 90 +- .../clippy/clippy_lints/src/implicit_return.rs | 4 +- .../clippy_lints/src/index_refutable_slice.rs | 16 +- src/tools/clippy/clippy_lints/src/infinite_iter.rs | 102 +- .../clippy/clippy_lints/src/large_enum_variant.rs | 96 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 21 +- src/tools/clippy/clippy_lints/src/let_if_seq.rs | 4 +- .../clippy/clippy_lints/src/lib.register_all.rs | 37 +- .../clippy_lints/src/lib.register_complexity.rs | 10 +- .../clippy_lints/src/lib.register_correctness.rs | 11 +- .../clippy/clippy_lints/src/lib.register_lints.rs | 59 +- .../clippy_lints/src/lib.register_nursery.rs | 10 +- .../clippy_lints/src/lib.register_pedantic.rs | 14 +- .../clippy/clippy_lints/src/lib.register_perf.rs | 2 + .../clippy_lints/src/lib.register_restriction.rs | 8 +- .../clippy/clippy_lints/src/lib.register_style.rs | 10 +- .../clippy_lints/src/lib.register_suspicious.rs | 4 + src/tools/clippy/clippy_lints/src/lib.rs | 482 ++- src/tools/clippy/clippy_lints/src/lifetimes.rs | 12 +- .../clippy/clippy_lints/src/loops/manual_find.rs | 2 +- .../clippy/clippy_lints/src/loops/manual_memcpy.rs | 10 +- .../clippy_lints/src/loops/missing_spin_loop.rs | 2 +- src/tools/clippy/clippy_lints/src/loops/mod.rs | 2 +- .../clippy_lints/src/loops/mut_range_bound.rs | 2 +- .../clippy_lints/src/loops/needless_collect.rs | 48 +- .../clippy_lints/src/loops/needless_range_loop.rs | 16 +- .../clippy/clippy_lints/src/loops/never_loop.rs | 9 +- .../clippy_lints/src/loops/same_item_push.rs | 9 +- .../clippy_lints/src/loops/single_element_loop.rs | 33 +- .../clippy_lints/src/loops/while_let_loop.rs | 9 +- .../src/loops/while_let_on_iterator.rs | 4 +- .../clippy/clippy_lints/src/manual_async_fn.rs | 4 +- src/tools/clippy/clippy_lints/src/manual_bits.rs | 4 +- .../clippy_lints/src/manual_instant_elapsed.rs | 69 + src/tools/clippy/clippy_lints/src/manual_ok_or.rs | 98 - src/tools/clippy/clippy_lints/src/manual_retain.rs | 22 +- .../clippy/clippy_lints/src/manual_string_new.rs | 135 + src/tools/clippy/clippy_lints/src/manual_strip.rs | 4 +- src/tools/clippy/clippy_lints/src/map_clone.rs | 167 - .../clippy/clippy_lints/src/map_err_ignore.rs | 154 - src/tools/clippy/clippy_lints/src/map_unit_fn.rs | 17 +- .../clippy/clippy_lints/src/match_result_ok.rs | 2 +- .../clippy/clippy_lints/src/matches/manual_map.rs | 2 +- .../clippy_lints/src/matches/match_as_ref.rs | 26 +- .../clippy_lints/src/matches/match_like_matches.rs | 4 +- .../clippy_lints/src/matches/match_same_arms.rs | 13 +- .../src/matches/match_str_case_mismatch.rs | 2 +- .../clippy_lints/src/matches/match_wild_err_arm.rs | 2 +- src/tools/clippy/clippy_lints/src/matches/mod.rs | 6 +- .../clippy_lints/src/matches/needless_match.rs | 25 +- .../src/matches/redundant_pattern_match.rs | 88 +- .../src/matches/significant_drop_in_scrutinee.rs | 5 +- .../clippy_lints/src/matches/single_match.rs | 12 +- .../clippy/clippy_lints/src/matches/try_err.rs | 6 +- src/tools/clippy/clippy_lints/src/mem_replace.rs | 6 +- .../src/methods/bind_instead_of_map.rs | 2 +- .../clippy/clippy_lints/src/methods/bytecount.rs | 70 + .../clippy_lints/src/methods/bytes_count_to_len.rs | 37 + .../case_sensitive_file_extension_comparisons.rs | 41 + .../clippy/clippy_lints/src/methods/chars_cmp.rs | 4 +- .../src/methods/chars_cmp_with_unwrap.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 33 +- .../clippy_lints/src/methods/clone_on_ref_ptr.rs | 15 +- .../src/methods/collapsible_str_replace.rs | 96 + .../clippy_lints/src/methods/expect_fun_call.rs | 24 +- .../clippy/clippy_lints/src/methods/expect_used.rs | 24 +- .../clippy_lints/src/methods/extend_with_drain.rs | 2 +- .../clippy/clippy_lints/src/methods/filter_map.rs | 14 +- .../clippy/clippy_lints/src/methods/get_first.rs | 39 + .../clippy_lints/src/methods/get_last_with_len.rs | 2 +- .../src/methods/inefficient_to_string.rs | 14 +- .../clippy_lints/src/methods/into_iter_on_ref.rs | 4 +- .../methods/iter_on_single_or_empty_collections.rs | 107 + .../clippy_lints/src/methods/iter_skip_next.rs | 2 +- .../clippy_lints/src/methods/iter_with_drain.rs | 2 +- .../clippy_lints/src/methods/manual_ok_or.rs | 64 + .../clippy/clippy_lints/src/methods/map_clone.rs | 122 + .../clippy_lints/src/methods/map_err_ignore.rs | 34 + src/tools/clippy/clippy_lints/src/methods/mod.rs | 967 ++++- .../clippy_lints/src/methods/mut_mutex_lock.rs | 31 + .../clippy_lints/src/methods/open_options.rs | 178 + .../src/methods/option_as_ref_deref.rs | 9 +- .../clippy_lints/src/methods/option_map_or_none.rs | 2 +- .../src/methods/option_map_unwrap_or.rs | 2 +- .../clippy/clippy_lints/src/methods/or_fun_call.rs | 20 +- .../src/methods/path_buf_push_overwrite.rs | 37 + .../clippy_lints/src/methods/range_zip_with_len.rs | 34 + .../clippy/clippy_lints/src/methods/repeat_once.rs | 52 + .../src/methods/single_char_add_str.rs | 6 +- .../src/methods/single_char_insert_string.rs | 8 +- .../src/methods/single_char_pattern.rs | 58 +- .../src/methods/single_char_push_string.rs | 6 +- .../src/methods/stable_sort_primitive.rs | 31 + .../clippy/clippy_lints/src/methods/str_splitn.rs | 17 +- .../src/methods/string_extend_chars.rs | 2 +- .../clippy_lints/src/methods/suspicious_map.rs | 4 +- .../src/methods/suspicious_to_owned.rs | 36 + .../src/methods/uninit_assumed_init.rs | 4 +- .../clippy/clippy_lints/src/methods/unit_hash.rs | 29 + .../src/methods/unnecessary_filter_map.rs | 11 +- .../clippy_lints/src/methods/unnecessary_fold.rs | 2 +- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_lazy_eval.rs | 2 +- .../src/methods/unnecessary_sort_by.rs | 228 ++ .../src/methods/unnecessary_to_owned.rs | 226 +- .../src/methods/unwrap_or_else_default.rs | 24 +- .../clippy/clippy_lints/src/methods/unwrap_used.rs | 41 +- src/tools/clippy/clippy_lints/src/methods/utils.rs | 6 +- .../clippy_lints/src/methods/vec_resize_to_zero.rs | 45 + .../clippy_lints/src/methods/verbose_file_reads.rs | 28 + src/tools/clippy/clippy_lints/src/minmax.rs | 45 +- src/tools/clippy/clippy_lints/src/misc.rs | 11 +- .../src/misc_early/redundant_pattern.rs | 12 +- .../src/misc_early/unneeded_wildcard_pattern.rs | 2 +- .../src/mismatching_type_param_order.rs | 2 +- .../clippy_lints/src/missing_const_for_fn.rs | 18 +- src/tools/clippy/clippy_lints/src/missing_doc.rs | 41 +- .../clippy/clippy_lints/src/multi_assignments.rs | 65 + .../clippy/clippy_lints/src/mut_mutex_lock.rs | 70 - src/tools/clippy/clippy_lints/src/mut_reference.rs | 14 +- .../src/needless_arbitrary_self_type.rs | 6 +- .../clippy_lints/src/needless_borrowed_ref.rs | 2 +- .../clippy/clippy_lints/src/needless_for_each.rs | 6 +- .../clippy/clippy_lints/src/needless_late_init.rs | 2 +- .../clippy_lints/src/needless_pass_by_value.rs | 12 +- .../clippy_lints/src/non_octal_unix_permissions.rs | 2 +- src/tools/clippy/clippy_lints/src/octal_escapes.rs | 8 +- .../clippy_lints/src/only_used_in_recursion.rs | 823 ++-- src/tools/clippy/clippy_lints/src/open_options.rs | 202 - .../clippy_lints/src/operators/arithmetic.rs | 119 - .../src/operators/arithmetic_side_effects.rs | 173 + .../clippy/clippy_lints/src/operators/cmp_owned.rs | 2 +- .../clippy_lints/src/operators/duration_subsec.rs | 2 +- .../clippy/clippy_lints/src/operators/float_cmp.rs | 2 +- src/tools/clippy/clippy_lints/src/operators/mod.rs | 32 +- .../clippy/clippy_lints/src/operators/op_ref.rs | 2 +- .../clippy/clippy_lints/src/option_if_let_else.rs | 167 +- .../clippy/clippy_lints/src/panic_in_result_fn.rs | 2 +- .../clippy/clippy_lints/src/partialeq_to_none.rs | 105 + .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- .../clippy_lints/src/path_buf_push_overwrite.rs | 74 - src/tools/clippy/clippy_lints/src/ptr.rs | 15 +- .../clippy_lints/src/ptr_offset_with_cast.rs | 2 +- src/tools/clippy/clippy_lints/src/question_mark.rs | 13 +- src/tools/clippy/clippy_lints/src/ranges.rs | 84 +- .../clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- .../clippy/clippy_lints/src/read_zero_byte_vec.rs | 4 +- .../clippy/clippy_lints/src/redundant_clone.rs | 6 +- .../clippy_lints/src/redundant_closure_call.rs | 21 +- .../clippy/clippy_lints/src/redundant_slicing.rs | 4 +- .../clippy_lints/src/redundant_static_lifetimes.rs | 12 +- .../clippy/clippy_lints/src/ref_option_ref.rs | 3 +- src/tools/clippy/clippy_lints/src/regex.rs | 11 +- src/tools/clippy/clippy_lints/src/renamed_lints.rs | 2 + src/tools/clippy/clippy_lints/src/repeat_once.rs | 89 - src/tools/clippy/clippy_lints/src/returns.rs | 12 +- .../clippy_lints/src/self_named_constructors.rs | 4 +- .../clippy_lints/src/size_of_in_element_count.rs | 2 +- .../clippy_lints/src/slow_vector_initialization.rs | 19 +- .../clippy_lints/src/stable_sort_primitive.rs | 145 - src/tools/clippy/clippy_lints/src/strings.rs | 28 +- .../clippy/clippy_lints/src/strlen_on_c_strings.rs | 2 +- .../clippy_lints/src/suspicious_trait_impl.rs | 2 +- .../clippy/clippy_lints/src/to_digit_is_some.rs | 10 +- src/tools/clippy/clippy_lints/src/trait_bounds.rs | 108 +- src/tools/clippy/clippy_lints/src/transmute/mod.rs | 25 + .../src/transmute/transmute_undefined_repr.rs | 400 +- .../clippy_lints/src/transmute/transmuting_null.rs | 61 + .../clippy/clippy_lints/src/transmute/utils.rs | 4 +- .../clippy/clippy_lints/src/transmuting_null.rs | 89 - src/tools/clippy/clippy_lints/src/unicode.rs | 7 + src/tools/clippy/clippy_lints/src/uninit_vec.rs | 6 +- src/tools/clippy/clippy_lints/src/unit_hash.rs | 78 - .../clippy_lints/src/unit_return_expecting_ord.rs | 5 +- .../clippy_lints/src/unit_types/let_unit_value.rs | 19 +- .../clippy/clippy_lints/src/unit_types/mod.rs | 2 +- .../clippy/clippy_lints/src/unit_types/unit_arg.rs | 42 +- .../clippy/clippy_lints/src/unnecessary_sort_by.rs | 258 -- .../clippy/clippy_lints/src/unnecessary_wraps.rs | 4 +- .../clippy_lints/src/unnested_or_patterns.rs | 4 +- src/tools/clippy/clippy_lints/src/unused_async.rs | 2 +- .../clippy/clippy_lints/src/unused_io_amount.rs | 8 +- .../clippy/clippy_lints/src/unused_peekable.rs | 226 ++ .../clippy/clippy_lints/src/unused_rounding.rs | 2 +- src/tools/clippy/clippy_lints/src/unused_unit.rs | 2 +- src/tools/clippy/clippy_lints/src/unwrap.rs | 12 +- .../clippy/clippy_lints/src/unwrap_in_result.rs | 6 +- .../clippy/clippy_lints/src/useless_conversion.rs | 23 +- src/tools/clippy/clippy_lints/src/utils/author.rs | 27 +- src/tools/clippy/clippy_lints/src/utils/conf.rs | 57 +- .../clippy_lints/src/utils/internal_lints.rs | 61 +- .../src/utils/internal_lints/metadata_collector.rs | 10 +- .../clippy/clippy_lints/src/vec_init_then_push.rs | 6 +- .../clippy/clippy_lints/src/vec_resize_to_zero.rs | 64 - .../clippy/clippy_lints/src/verbose_file_reads.rs | 88 - src/tools/clippy/clippy_lints/src/write.rs | 145 +- src/tools/clippy/clippy_utils/Cargo.toml | 3 +- src/tools/clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/clippy/clippy_utils/src/attrs.rs | 4 +- .../clippy/clippy_utils/src/check_proc_macro.rs | 329 ++ src/tools/clippy/clippy_utils/src/consts.rs | 8 +- src/tools/clippy/clippy_utils/src/diagnostics.rs | 8 +- src/tools/clippy/clippy_utils/src/eager_or_lazy.rs | 18 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 39 +- src/tools/clippy/clippy_utils/src/lib.rs | 84 +- src/tools/clippy/clippy_utils/src/macros.rs | 676 +++- src/tools/clippy/clippy_utils/src/msrvs.rs | 4 +- .../clippy/clippy_utils/src/numeric_literal.rs | 10 +- src/tools/clippy/clippy_utils/src/paths.rs | 6 +- src/tools/clippy/clippy_utils/src/ptr.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 18 +- src/tools/clippy/clippy_utils/src/source.rs | 18 - src/tools/clippy/clippy_utils/src/sugg.rs | 30 +- src/tools/clippy/clippy_utils/src/ty.rs | 118 +- src/tools/clippy/clippy_utils/src/visitors.rs | 11 +- src/tools/clippy/lintcheck/lintcheck_crates.toml | 2 +- src/tools/clippy/rust-toolchain | 2 +- src/tools/clippy/rustc_tools_util/src/lib.rs | 4 +- src/tools/clippy/src/docs.rs | 596 +++ .../clippy/src/docs/absurd_extreme_comparisons.txt | 25 + .../clippy/src/docs/alloc_instead_of_core.txt | 18 + .../src/docs/allow_attributes_without_reason.txt | 22 + .../src/docs/almost_complete_letter_range.txt | 15 + src/tools/clippy/src/docs/almost_swapped.txt | 15 + src/tools/clippy/src/docs/approx_constant.txt | 24 + .../clippy/src/docs/arithmetic_side_effects.txt | 33 + src/tools/clippy/src/docs/as_conversions.txt | 32 + src/tools/clippy/src/docs/as_underscore.txt | 21 + .../clippy/src/docs/assertions_on_constants.txt | 14 + .../src/docs/assertions_on_result_states.txt | 14 + src/tools/clippy/src/docs/assign_op_pattern.txt | 28 + src/tools/clippy/src/docs/async_yields_async.txt | 28 + .../clippy/src/docs/await_holding_invalid_type.txt | 29 + src/tools/clippy/src/docs/await_holding_lock.txt | 51 + .../clippy/src/docs/await_holding_refcell_ref.txt | 47 + src/tools/clippy/src/docs/bad_bit_mask.txt | 30 + src/tools/clippy/src/docs/bind_instead_of_map.txt | 22 + .../src/docs/blanket_clippy_restriction_lints.txt | 16 + .../clippy/src/docs/blocks_in_if_conditions.txt | 21 + .../clippy/src/docs/bool_assert_comparison.txt | 16 + src/tools/clippy/src/docs/bool_comparison.txt | 18 + src/tools/clippy/src/docs/bool_to_int_with_if.txt | 26 + src/tools/clippy/src/docs/borrow_as_ptr.txt | 26 + src/tools/clippy/src/docs/borrow_deref_ref.txt | 27 + .../src/docs/borrow_interior_mutable_const.txt | 40 + src/tools/clippy/src/docs/borrowed_box.txt | 19 + src/tools/clippy/src/docs/box_collection.txt | 23 + src/tools/clippy/src/docs/boxed_local.txt | 18 + .../clippy/src/docs/branches_sharing_code.txt | 32 + src/tools/clippy/src/docs/builtin_type_shadow.txt | 15 + src/tools/clippy/src/docs/bytes_count_to_len.txt | 18 + src/tools/clippy/src/docs/bytes_nth.txt | 16 + .../clippy/src/docs/cargo_common_metadata.txt | 33 + .../case_sensitive_file_extension_comparisons.txt | 21 + src/tools/clippy/src/docs/cast_abs_to_unsigned.txt | 16 + .../clippy/src/docs/cast_enum_constructor.txt | 11 + src/tools/clippy/src/docs/cast_enum_truncation.txt | 12 + src/tools/clippy/src/docs/cast_lossless.txt | 26 + .../clippy/src/docs/cast_possible_truncation.txt | 16 + src/tools/clippy/src/docs/cast_possible_wrap.txt | 17 + src/tools/clippy/src/docs/cast_precision_loss.txt | 19 + src/tools/clippy/src/docs/cast_ptr_alignment.txt | 21 + src/tools/clippy/src/docs/cast_ref_to_mut.txt | 28 + src/tools/clippy/src/docs/cast_sign_loss.txt | 15 + .../clippy/src/docs/cast_slice_different_sizes.txt | 38 + .../clippy/src/docs/cast_slice_from_raw_parts.txt | 20 + src/tools/clippy/src/docs/char_lit_as_u8.txt | 21 + src/tools/clippy/src/docs/chars_last_cmp.txt | 17 + src/tools/clippy/src/docs/chars_next_cmp.txt | 19 + src/tools/clippy/src/docs/checked_conversions.txt | 15 + src/tools/clippy/src/docs/clone_double_ref.txt | 16 + src/tools/clippy/src/docs/clone_on_copy.txt | 11 + src/tools/clippy/src/docs/clone_on_ref_ptr.txt | 21 + .../clippy/src/docs/cloned_instead_of_copied.txt | 16 + src/tools/clippy/src/docs/cmp_nan.txt | 16 + src/tools/clippy/src/docs/cmp_null.txt | 23 + src/tools/clippy/src/docs/cmp_owned.txt | 18 + src/tools/clippy/src/docs/cognitive_complexity.txt | 13 + src/tools/clippy/src/docs/collapsible_else_if.txt | 29 + src/tools/clippy/src/docs/collapsible_if.txt | 23 + src/tools/clippy/src/docs/collapsible_match.txt | 31 + .../clippy/src/docs/collapsible_str_replace.txt | 19 + src/tools/clippy/src/docs/comparison_chain.txt | 36 + src/tools/clippy/src/docs/comparison_to_empty.txt | 31 + src/tools/clippy/src/docs/copy_iterator.txt | 20 + src/tools/clippy/src/docs/crate_in_macro_def.txt | 35 + src/tools/clippy/src/docs/create_dir.txt | 15 + .../clippy/src/docs/crosspointer_transmute.txt | 12 + src/tools/clippy/src/docs/dbg_macro.txt | 16 + .../clippy/src/docs/debug_assert_with_mut_call.txt | 18 + .../src/docs/decimal_literal_representation.txt | 13 + .../src/docs/declare_interior_mutable_const.txt | 46 + .../src/docs/default_instead_of_iter_empty.txt | 15 + .../clippy/src/docs/default_numeric_fallback.txt | 28 + src/tools/clippy/src/docs/default_trait_access.txt | 16 + .../src/docs/default_union_representation.txt | 36 + src/tools/clippy/src/docs/deprecated_cfg_attr.txt | 24 + src/tools/clippy/src/docs/deprecated_semver.txt | 13 + src/tools/clippy/src/docs/deref_addrof.txt | 22 + src/tools/clippy/src/docs/deref_by_slicing.txt | 17 + src/tools/clippy/src/docs/derivable_impls.txt | 35 + src/tools/clippy/src/docs/derive_hash_xor_eq.txt | 23 + .../clippy/src/docs/derive_ord_xor_partial_ord.txt | 44 + .../src/docs/derive_partial_eq_without_eq.txt | 25 + src/tools/clippy/src/docs/disallowed_methods.txt | 41 + src/tools/clippy/src/docs/disallowed_names.txt | 12 + .../clippy/src/docs/disallowed_script_idents.txt | 32 + src/tools/clippy/src/docs/disallowed_types.txt | 33 + .../clippy/src/docs/diverging_sub_expression.txt | 19 + src/tools/clippy/src/docs/doc_link_with_quotes.txt | 16 + src/tools/clippy/src/docs/doc_markdown.txt | 35 + src/tools/clippy/src/docs/double_comparisons.txt | 17 + src/tools/clippy/src/docs/double_must_use.txt | 17 + src/tools/clippy/src/docs/double_neg.txt | 12 + src/tools/clippy/src/docs/double_parens.txt | 24 + src/tools/clippy/src/docs/drop_copy.txt | 15 + src/tools/clippy/src/docs/drop_non_drop.txt | 13 + src/tools/clippy/src/docs/drop_ref.txt | 17 + src/tools/clippy/src/docs/duplicate_mod.txt | 31 + .../src/docs/duplicate_underscore_argument.txt | 16 + src/tools/clippy/src/docs/duration_subsec.txt | 19 + src/tools/clippy/src/docs/else_if_without_else.txt | 27 + src/tools/clippy/src/docs/empty_drop.txt | 20 + src/tools/clippy/src/docs/empty_enum.txt | 27 + .../src/docs/empty_line_after_outer_attr.txt | 35 + src/tools/clippy/src/docs/empty_loop.txt | 27 + .../src/docs/empty_structs_with_brackets.txt | 14 + .../src/docs/enum_clike_unportable_variant.txt | 16 + src/tools/clippy/src/docs/enum_glob_use.txt | 24 + src/tools/clippy/src/docs/enum_variant_names.txt | 30 + src/tools/clippy/src/docs/eq_op.txt | 22 + src/tools/clippy/src/docs/equatable_if_let.txt | 23 + src/tools/clippy/src/docs/erasing_op.txt | 15 + src/tools/clippy/src/docs/err_expect.txt | 16 + src/tools/clippy/src/docs/excessive_precision.txt | 18 + src/tools/clippy/src/docs/exhaustive_enums.txt | 23 + src/tools/clippy/src/docs/exhaustive_structs.txt | 23 + src/tools/clippy/src/docs/exit.txt | 12 + src/tools/clippy/src/docs/expect_fun_call.txt | 24 + src/tools/clippy/src/docs/expect_used.txt | 26 + .../clippy/src/docs/expl_impl_clone_on_copy.txt | 20 + src/tools/clippy/src/docs/explicit_auto_deref.txt | 16 + .../clippy/src/docs/explicit_counter_loop.txt | 21 + .../clippy/src/docs/explicit_deref_methods.txt | 24 + .../clippy/src/docs/explicit_into_iter_loop.txt | 20 + src/tools/clippy/src/docs/explicit_iter_loop.txt | 25 + src/tools/clippy/src/docs/explicit_write.txt | 18 + src/tools/clippy/src/docs/extend_with_drain.txt | 21 + .../clippy/src/docs/extra_unused_lifetimes.txt | 23 + src/tools/clippy/src/docs/fallible_impl_from.txt | 32 + .../src/docs/field_reassign_with_default.txt | 23 + src/tools/clippy/src/docs/filetype_is_file.txt | 29 + src/tools/clippy/src/docs/filter_map_identity.txt | 14 + src/tools/clippy/src/docs/filter_map_next.txt | 16 + src/tools/clippy/src/docs/filter_next.txt | 16 + src/tools/clippy/src/docs/flat_map_identity.txt | 14 + src/tools/clippy/src/docs/flat_map_option.txt | 16 + src/tools/clippy/src/docs/float_arithmetic.txt | 11 + src/tools/clippy/src/docs/float_cmp.txt | 28 + src/tools/clippy/src/docs/float_cmp_const.txt | 26 + .../clippy/src/docs/float_equality_without_abs.txt | 26 + .../clippy/src/docs/fn_address_comparisons.txt | 17 + .../clippy/src/docs/fn_params_excessive_bools.txt | 31 + src/tools/clippy/src/docs/fn_to_numeric_cast.txt | 21 + .../clippy/src/docs/fn_to_numeric_cast_any.txt | 35 + .../docs/fn_to_numeric_cast_with_truncation.txt | 26 + src/tools/clippy/src/docs/for_kv_map.txt | 22 + .../clippy/src/docs/for_loops_over_fallibles.txt | 32 + src/tools/clippy/src/docs/forget_copy.txt | 21 + src/tools/clippy/src/docs/forget_non_drop.txt | 13 + src/tools/clippy/src/docs/forget_ref.txt | 15 + .../clippy/src/docs/format_in_format_args.txt | 16 + src/tools/clippy/src/docs/format_push_string.txt | 26 + .../src/docs/from_iter_instead_of_collect.txt | 24 + src/tools/clippy/src/docs/from_over_into.txt | 26 + src/tools/clippy/src/docs/from_str_radix_10.txt | 25 + src/tools/clippy/src/docs/future_not_send.txt | 29 + src/tools/clippy/src/docs/get_first.txt | 19 + src/tools/clippy/src/docs/get_last_with_len.txt | 26 + src/tools/clippy/src/docs/get_unwrap.txt | 30 + src/tools/clippy/src/docs/identity_op.txt | 11 + src/tools/clippy/src/docs/if_let_mutex.txt | 25 + src/tools/clippy/src/docs/if_not_else.txt | 25 + src/tools/clippy/src/docs/if_same_then_else.txt | 15 + .../clippy/src/docs/if_then_some_else_none.txt | 26 + src/tools/clippy/src/docs/ifs_same_cond.txt | 25 + src/tools/clippy/src/docs/implicit_clone.txt | 19 + src/tools/clippy/src/docs/implicit_hasher.txt | 26 + src/tools/clippy/src/docs/implicit_return.txt | 22 + .../clippy/src/docs/implicit_saturating_sub.txt | 21 + src/tools/clippy/src/docs/imprecise_flops.txt | 23 + .../src/docs/inconsistent_digit_grouping.txt | 17 + .../src/docs/inconsistent_struct_constructor.txt | 40 + .../clippy/src/docs/index_refutable_slice.txt | 29 + src/tools/clippy/src/docs/indexing_slicing.txt | 33 + src/tools/clippy/src/docs/ineffective_bit_mask.txt | 25 + .../clippy/src/docs/inefficient_to_string.txt | 17 + .../src/docs/infallible_destructuring_match.txt | 29 + src/tools/clippy/src/docs/infinite_iter.txt | 13 + src/tools/clippy/src/docs/inherent_to_string.txt | 29 + .../src/docs/inherent_to_string_shadow_display.txt | 37 + src/tools/clippy/src/docs/init_numbered_fields.txt | 24 + src/tools/clippy/src/docs/inline_always.txt | 23 + .../clippy/src/docs/inline_asm_x86_att_syntax.txt | 16 + .../src/docs/inline_asm_x86_intel_syntax.txt | 16 + .../clippy/src/docs/inline_fn_without_body.txt | 14 + src/tools/clippy/src/docs/inspect_for_each.txt | 23 + src/tools/clippy/src/docs/int_plus_one.txt | 15 + src/tools/clippy/src/docs/integer_arithmetic.txt | 18 + src/tools/clippy/src/docs/integer_division.txt | 19 + src/tools/clippy/src/docs/into_iter_on_ref.txt | 18 + .../clippy/src/docs/invalid_null_ptr_usage.txt | 16 + src/tools/clippy/src/docs/invalid_regex.txt | 12 + .../clippy/src/docs/invalid_upcast_comparisons.txt | 18 + .../clippy/src/docs/invalid_utf8_in_unchecked.txt | 12 + src/tools/clippy/src/docs/invisible_characters.txt | 10 + src/tools/clippy/src/docs/is_digit_ascii_radix.txt | 20 + .../clippy/src/docs/items_after_statements.txt | 37 + src/tools/clippy/src/docs/iter_cloned_collect.txt | 17 + src/tools/clippy/src/docs/iter_count.txt | 22 + src/tools/clippy/src/docs/iter_next_loop.txt | 17 + src/tools/clippy/src/docs/iter_next_slice.txt | 16 + .../src/docs/iter_not_returning_iterator.txt | 26 + src/tools/clippy/src/docs/iter_nth.txt | 20 + src/tools/clippy/src/docs/iter_nth_zero.txt | 17 + .../clippy/src/docs/iter_on_empty_collections.txt | 25 + src/tools/clippy/src/docs/iter_on_single_items.txt | 24 + .../clippy/src/docs/iter_overeager_cloned.txt | 22 + src/tools/clippy/src/docs/iter_skip_next.txt | 18 + src/tools/clippy/src/docs/iter_with_drain.txt | 16 + .../clippy/src/docs/iterator_step_by_zero.txt | 13 + .../src/docs/just_underscores_and_digits.txt | 14 + src/tools/clippy/src/docs/large_const_arrays.txt | 17 + src/tools/clippy/src/docs/large_digit_groups.txt | 12 + src/tools/clippy/src/docs/large_enum_variant.txt | 41 + src/tools/clippy/src/docs/large_include_file.txt | 21 + src/tools/clippy/src/docs/large_stack_arrays.txt | 10 + .../src/docs/large_types_passed_by_value.txt | 24 + src/tools/clippy/src/docs/len_without_is_empty.txt | 19 + src/tools/clippy/src/docs/len_zero.txt | 28 + src/tools/clippy/src/docs/let_and_return.txt | 21 + src/tools/clippy/src/docs/let_underscore_drop.txt | 29 + src/tools/clippy/src/docs/let_underscore_lock.txt | 20 + .../clippy/src/docs/let_underscore_must_use.txt | 17 + src/tools/clippy/src/docs/let_unit_value.txt | 13 + src/tools/clippy/src/docs/linkedlist.txt | 32 + src/tools/clippy/src/docs/lossy_float_literal.txt | 18 + src/tools/clippy/src/docs/macro_use_imports.txt | 12 + src/tools/clippy/src/docs/main_recursion.txt | 13 + src/tools/clippy/src/docs/manual_assert.txt | 18 + src/tools/clippy/src/docs/manual_async_fn.txt | 16 + src/tools/clippy/src/docs/manual_bits.txt | 15 + src/tools/clippy/src/docs/manual_filter_map.txt | 19 + src/tools/clippy/src/docs/manual_find.txt | 24 + src/tools/clippy/src/docs/manual_find_map.txt | 19 + src/tools/clippy/src/docs/manual_flatten.txt | 25 + .../clippy/src/docs/manual_instant_elapsed.txt | 21 + src/tools/clippy/src/docs/manual_map.txt | 17 + src/tools/clippy/src/docs/manual_memcpy.txt | 18 + .../clippy/src/docs/manual_non_exhaustive.txt | 41 + src/tools/clippy/src/docs/manual_ok_or.txt | 19 + .../clippy/src/docs/manual_range_contains.txt | 19 + src/tools/clippy/src/docs/manual_rem_euclid.txt | 17 + src/tools/clippy/src/docs/manual_retain.txt | 15 + .../src/docs/manual_saturating_arithmetic.txt | 18 + src/tools/clippy/src/docs/manual_split_once.txt | 29 + src/tools/clippy/src/docs/manual_str_repeat.txt | 15 + src/tools/clippy/src/docs/manual_string_new.txt | 20 + src/tools/clippy/src/docs/manual_strip.txt | 24 + src/tools/clippy/src/docs/manual_swap.txt | 22 + src/tools/clippy/src/docs/manual_unwrap_or.txt | 20 + .../clippy/src/docs/many_single_char_names.txt | 12 + src/tools/clippy/src/docs/map_clone.txt | 22 + .../clippy/src/docs/map_collect_result_unit.txt | 14 + src/tools/clippy/src/docs/map_entry.txt | 28 + src/tools/clippy/src/docs/map_err_ignore.txt | 93 + src/tools/clippy/src/docs/map_flatten.txt | 21 + src/tools/clippy/src/docs/map_identity.txt | 16 + src/tools/clippy/src/docs/map_unwrap_or.txt | 22 + src/tools/clippy/src/docs/match_as_ref.txt | 23 + src/tools/clippy/src/docs/match_bool.txt | 24 + .../clippy/src/docs/match_like_matches_macro.txt | 32 + src/tools/clippy/src/docs/match_on_vec_items.txt | 29 + .../clippy/src/docs/match_overlapping_arm.txt | 16 + src/tools/clippy/src/docs/match_ref_pats.txt | 26 + src/tools/clippy/src/docs/match_result_ok.txt | 27 + src/tools/clippy/src/docs/match_same_arms.txt | 38 + src/tools/clippy/src/docs/match_single_binding.txt | 23 + .../clippy/src/docs/match_str_case_mismatch.txt | 22 + src/tools/clippy/src/docs/match_wild_err_arm.txt | 16 + .../docs/match_wildcard_for_single_variants.txt | 27 + src/tools/clippy/src/docs/maybe_infinite_iter.txt | 16 + src/tools/clippy/src/docs/mem_forget.txt | 12 + .../src/docs/mem_replace_option_with_none.txt | 21 + .../clippy/src/docs/mem_replace_with_default.txt | 18 + .../clippy/src/docs/mem_replace_with_uninit.txt | 24 + src/tools/clippy/src/docs/min_max.txt | 18 + src/tools/clippy/src/docs/mismatched_target_os.txt | 24 + .../src/docs/mismatching_type_param_order.txt | 33 + .../clippy/src/docs/misrefactored_assign_op.txt | 20 + src/tools/clippy/src/docs/missing_const_for_fn.txt | 40 + .../src/docs/missing_docs_in_private_items.txt | 9 + .../src/docs/missing_enforced_import_renames.txt | 22 + src/tools/clippy/src/docs/missing_errors_doc.txt | 21 + .../src/docs/missing_inline_in_public_items.txt | 45 + src/tools/clippy/src/docs/missing_panics_doc.txt | 24 + src/tools/clippy/src/docs/missing_safety_doc.txt | 26 + src/tools/clippy/src/docs/missing_spin_loop.txt | 27 + .../clippy/src/docs/mistyped_literal_suffixes.txt | 15 + .../clippy/src/docs/mixed_case_hex_literals.txt | 16 + .../src/docs/mixed_read_write_in_expression.txt | 32 + src/tools/clippy/src/docs/mod_module_files.txt | 22 + src/tools/clippy/src/docs/module_inception.txt | 24 + .../clippy/src/docs/module_name_repetitions.txt | 20 + src/tools/clippy/src/docs/modulo_arithmetic.txt | 15 + src/tools/clippy/src/docs/modulo_one.txt | 16 + src/tools/clippy/src/docs/multi_assignments.txt | 17 + .../clippy/src/docs/multiple_crate_versions.txt | 19 + .../clippy/src/docs/multiple_inherent_impl.txt | 26 + src/tools/clippy/src/docs/must_use_candidate.txt | 23 + src/tools/clippy/src/docs/must_use_unit.txt | 13 + src/tools/clippy/src/docs/mut_from_ref.txt | 26 + src/tools/clippy/src/docs/mut_mut.txt | 12 + src/tools/clippy/src/docs/mut_mutex_lock.txt | 29 + src/tools/clippy/src/docs/mut_range_bound.txt | 29 + src/tools/clippy/src/docs/mutable_key_type.txt | 61 + src/tools/clippy/src/docs/mutex_atomic.txt | 22 + src/tools/clippy/src/docs/mutex_integer.txt | 22 + src/tools/clippy/src/docs/naive_bytecount.txt | 22 + .../src/docs/needless_arbitrary_self_type.txt | 44 + .../clippy/src/docs/needless_bitwise_bool.txt | 22 + src/tools/clippy/src/docs/needless_bool.txt | 26 + src/tools/clippy/src/docs/needless_borrow.txt | 21 + .../src/docs/needless_borrowed_reference.txt | 30 + src/tools/clippy/src/docs/needless_collect.txt | 14 + src/tools/clippy/src/docs/needless_continue.txt | 61 + .../clippy/src/docs/needless_doctest_main.txt | 22 + src/tools/clippy/src/docs/needless_for_each.txt | 24 + src/tools/clippy/src/docs/needless_late_init.txt | 42 + src/tools/clippy/src/docs/needless_lifetimes.txt | 29 + src/tools/clippy/src/docs/needless_match.txt | 36 + .../clippy/src/docs/needless_option_as_deref.txt | 18 + src/tools/clippy/src/docs/needless_option_take.txt | 17 + .../src/docs/needless_parens_on_range_literals.txt | 23 + .../clippy/src/docs/needless_pass_by_value.txt | 27 + .../clippy/src/docs/needless_question_mark.txt | 43 + src/tools/clippy/src/docs/needless_range_loop.txt | 23 + src/tools/clippy/src/docs/needless_return.txt | 19 + src/tools/clippy/src/docs/needless_splitn.txt | 16 + src/tools/clippy/src/docs/needless_update.txt | 30 + .../clippy/src/docs/neg_cmp_op_on_partial_ord.txt | 26 + src/tools/clippy/src/docs/neg_multiply.txt | 18 + .../clippy/src/docs/negative_feature_names.txt | 22 + src/tools/clippy/src/docs/never_loop.txt | 15 + src/tools/clippy/src/docs/new_ret_no_self.txt | 47 + src/tools/clippy/src/docs/new_without_default.txt | 32 + src/tools/clippy/src/docs/no_effect.txt | 12 + src/tools/clippy/src/docs/no_effect_replace.txt | 11 + .../src/docs/no_effect_underscore_binding.txt | 16 + src/tools/clippy/src/docs/non_ascii_literal.txt | 19 + .../clippy/src/docs/non_octal_unix_permissions.txt | 23 + .../clippy/src/docs/non_send_fields_in_send_ty.txt | 36 + src/tools/clippy/src/docs/nonminimal_bool.txt | 23 + .../clippy/src/docs/nonsensical_open_options.txt | 14 + .../clippy/src/docs/nonstandard_macro_braces.txt | 15 + .../clippy/src/docs/not_unsafe_ptr_arg_deref.txt | 30 + src/tools/clippy/src/docs/obfuscated_if_else.txt | 21 + src/tools/clippy/src/docs/octal_escapes.txt | 33 + src/tools/clippy/src/docs/ok_expect.txt | 19 + .../clippy/src/docs/only_used_in_recursion.txt | 58 + src/tools/clippy/src/docs/op_ref.txt | 17 + src/tools/clippy/src/docs/option_as_ref_deref.txt | 15 + src/tools/clippy/src/docs/option_env_unwrap.txt | 19 + src/tools/clippy/src/docs/option_filter_map.txt | 15 + src/tools/clippy/src/docs/option_if_let_else.txt | 46 + src/tools/clippy/src/docs/option_map_or_none.txt | 19 + src/tools/clippy/src/docs/option_map_unit_fn.txt | 27 + src/tools/clippy/src/docs/option_option.txt | 32 + src/tools/clippy/src/docs/or_fun_call.txt | 27 + src/tools/clippy/src/docs/or_then_unwrap.txt | 22 + .../clippy/src/docs/out_of_bounds_indexing.txt | 22 + .../clippy/src/docs/overflow_check_conditional.txt | 11 + .../clippy/src/docs/overly_complex_bool_expr.txt | 20 + src/tools/clippy/src/docs/panic.txt | 10 + src/tools/clippy/src/docs/panic_in_result_fn.txt | 22 + src/tools/clippy/src/docs/panicking_unwrap.txt | 18 + src/tools/clippy/src/docs/partialeq_ne_impl.txt | 18 + src/tools/clippy/src/docs/partialeq_to_none.txt | 24 + .../clippy/src/docs/path_buf_push_overwrite.txt | 25 + .../clippy/src/docs/pattern_type_mismatch.txt | 64 + .../docs/positional_named_format_parameters.txt | 15 + .../clippy/src/docs/possible_missing_comma.txt | 14 + src/tools/clippy/src/docs/precedence.txt | 17 + src/tools/clippy/src/docs/print_in_format_impl.txt | 34 + src/tools/clippy/src/docs/print_literal.txt | 20 + src/tools/clippy/src/docs/print_stderr.txt | 21 + src/tools/clippy/src/docs/print_stdout.txt | 21 + src/tools/clippy/src/docs/print_with_newline.txt | 16 + src/tools/clippy/src/docs/println_empty_string.txt | 16 + src/tools/clippy/src/docs/ptr_arg.txt | 29 + src/tools/clippy/src/docs/ptr_as_ptr.txt | 22 + src/tools/clippy/src/docs/ptr_eq.txt | 22 + src/tools/clippy/src/docs/ptr_offset_with_cast.txt | 30 + src/tools/clippy/src/docs/pub_use.txt | 28 + src/tools/clippy/src/docs/question_mark.txt | 18 + src/tools/clippy/src/docs/range_minus_one.txt | 27 + src/tools/clippy/src/docs/range_plus_one.txt | 36 + src/tools/clippy/src/docs/range_zip_with_len.txt | 16 + src/tools/clippy/src/docs/rc_buffer.txt | 27 + src/tools/clippy/src/docs/rc_clone_in_vec_init.txt | 29 + src/tools/clippy/src/docs/rc_mutex.txt | 26 + src/tools/clippy/src/docs/read_zero_byte_vec.txt | 30 + .../clippy/src/docs/recursive_format_impl.txt | 32 + src/tools/clippy/src/docs/redundant_allocation.txt | 17 + src/tools/clippy/src/docs/redundant_clone.txt | 23 + src/tools/clippy/src/docs/redundant_closure.txt | 25 + .../clippy/src/docs/redundant_closure_call.txt | 17 + .../docs/redundant_closure_for_method_calls.txt | 15 + src/tools/clippy/src/docs/redundant_else.txt | 30 + .../clippy/src/docs/redundant_feature_names.txt | 23 + .../clippy/src/docs/redundant_field_names.txt | 22 + src/tools/clippy/src/docs/redundant_pattern.txt | 22 + .../clippy/src/docs/redundant_pattern_matching.txt | 45 + src/tools/clippy/src/docs/redundant_pub_crate.txt | 21 + src/tools/clippy/src/docs/redundant_slicing.txt | 24 + .../clippy/src/docs/redundant_static_lifetimes.txt | 19 + .../clippy/src/docs/ref_binding_to_reference.txt | 21 + src/tools/clippy/src/docs/ref_option_ref.txt | 19 + src/tools/clippy/src/docs/repeat_once.txt | 25 + .../src/docs/rest_pat_in_fully_bound_structs.txt | 24 + src/tools/clippy/src/docs/result_large_err.txt | 36 + .../clippy/src/docs/result_map_or_into_option.txt | 16 + src/tools/clippy/src/docs/result_map_unit_fn.txt | 26 + src/tools/clippy/src/docs/result_unit_err.txt | 40 + .../clippy/src/docs/return_self_not_must_use.txt | 46 + .../clippy/src/docs/reversed_empty_ranges.txt | 26 + .../src/docs/same_functions_in_if_condition.txt | 41 + src/tools/clippy/src/docs/same_item_push.txt | 29 + src/tools/clippy/src/docs/same_name_method.txt | 23 + src/tools/clippy/src/docs/search_is_some.txt | 24 + src/tools/clippy/src/docs/self_assignment.txt | 32 + .../clippy/src/docs/self_named_constructors.txt | 26 + .../clippy/src/docs/self_named_module_files.txt | 22 + .../src/docs/semicolon_if_nothing_returned.txt | 20 + .../clippy/src/docs/separated_literal_suffix.txt | 17 + src/tools/clippy/src/docs/serde_api_misuse.txt | 10 + src/tools/clippy/src/docs/shadow_reuse.txt | 20 + src/tools/clippy/src/docs/shadow_same.txt | 18 + src/tools/clippy/src/docs/shadow_unrelated.txt | 22 + .../clippy/src/docs/short_circuit_statement.txt | 14 + .../clippy/src/docs/should_implement_trait.txt | 22 + .../src/docs/significant_drop_in_scrutinee.txt | 43 + src/tools/clippy/src/docs/similar_names.txt | 12 + src/tools/clippy/src/docs/single_char_add_str.txt | 18 + .../clippy/src/docs/single_char_lifetime_names.txt | 28 + src/tools/clippy/src/docs/single_char_pattern.txt | 20 + .../src/docs/single_component_path_imports.txt | 21 + src/tools/clippy/src/docs/single_element_loop.txt | 21 + src/tools/clippy/src/docs/single_match.txt | 21 + src/tools/clippy/src/docs/single_match_else.txt | 29 + .../clippy/src/docs/size_of_in_element_count.txt | 16 + src/tools/clippy/src/docs/skip_while_next.txt | 16 + .../clippy/src/docs/slow_vector_initialization.txt | 24 + .../clippy/src/docs/stable_sort_primitive.txt | 31 + src/tools/clippy/src/docs/std_instead_of_alloc.txt | 18 + src/tools/clippy/src/docs/std_instead_of_core.txt | 18 + src/tools/clippy/src/docs/str_to_string.txt | 18 + src/tools/clippy/src/docs/string_add.txt | 27 + src/tools/clippy/src/docs/string_add_assign.txt | 17 + src/tools/clippy/src/docs/string_extend_chars.txt | 23 + .../clippy/src/docs/string_from_utf8_as_bytes.txt | 15 + src/tools/clippy/src/docs/string_lit_as_bytes.txt | 39 + src/tools/clippy/src/docs/string_slice.txt | 17 + src/tools/clippy/src/docs/string_to_string.txt | 19 + src/tools/clippy/src/docs/strlen_on_c_strings.txt | 20 + .../clippy/src/docs/struct_excessive_bools.txt | 29 + src/tools/clippy/src/docs/suboptimal_flops.txt | 50 + .../clippy/src/docs/suspicious_arithmetic_impl.txt | 17 + .../src/docs/suspicious_assignment_formatting.txt | 12 + .../clippy/src/docs/suspicious_else_formatting.txt | 30 + src/tools/clippy/src/docs/suspicious_map.txt | 13 + .../clippy/src/docs/suspicious_op_assign_impl.txt | 15 + .../src/docs/suspicious_operation_groupings.txt | 41 + src/tools/clippy/src/docs/suspicious_splitn.txt | 22 + src/tools/clippy/src/docs/suspicious_to_owned.txt | 39 + .../src/docs/suspicious_unary_op_formatting.txt | 18 + src/tools/clippy/src/docs/swap_ptr_to_ref.txt | 23 + src/tools/clippy/src/docs/tabs_in_doc_comments.txt | 44 + src/tools/clippy/src/docs/temporary_assignment.txt | 12 + src/tools/clippy/src/docs/to_digit_is_some.txt | 15 + .../clippy/src/docs/to_string_in_format_args.txt | 17 + src/tools/clippy/src/docs/todo.txt | 10 + src/tools/clippy/src/docs/too_many_arguments.txt | 14 + src/tools/clippy/src/docs/too_many_lines.txt | 17 + src/tools/clippy/src/docs/toplevel_ref_arg.txt | 28 + src/tools/clippy/src/docs/trailing_empty_array.txt | 22 + .../src/docs/trait_duplication_in_bounds.txt | 37 + .../clippy/src/docs/transmute_bytes_to_str.txt | 27 + .../clippy/src/docs/transmute_float_to_int.txt | 16 + .../clippy/src/docs/transmute_int_to_bool.txt | 16 + .../clippy/src/docs/transmute_int_to_char.txt | 27 + .../clippy/src/docs/transmute_int_to_float.txt | 16 + .../clippy/src/docs/transmute_num_to_bytes.txt | 16 + src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt | 21 + src/tools/clippy/src/docs/transmute_ptr_to_ref.txt | 21 + .../clippy/src/docs/transmute_undefined_repr.txt | 22 + .../docs/transmutes_expressible_as_ptr_casts.txt | 16 + src/tools/clippy/src/docs/transmuting_null.txt | 15 + .../clippy/src/docs/trim_split_whitespace.txt | 14 + src/tools/clippy/src/docs/trivial_regex.txt | 18 + .../clippy/src/docs/trivially_copy_pass_by_ref.txt | 43 + src/tools/clippy/src/docs/try_err.txt | 28 + src/tools/clippy/src/docs/type_complexity.txt | 14 + .../clippy/src/docs/type_repetition_in_bounds.txt | 16 + .../clippy/src/docs/undocumented_unsafe_blocks.txt | 43 + .../clippy/src/docs/undropped_manually_drops.txt | 22 + src/tools/clippy/src/docs/unicode_not_nfc.txt | 12 + src/tools/clippy/src/docs/unimplemented.txt | 10 + src/tools/clippy/src/docs/uninit_assumed_init.txt | 28 + src/tools/clippy/src/docs/uninit_vec.txt | 41 + src/tools/clippy/src/docs/unit_arg.txt | 14 + src/tools/clippy/src/docs/unit_cmp.txt | 33 + src/tools/clippy/src/docs/unit_hash.txt | 20 + .../clippy/src/docs/unit_return_expecting_ord.txt | 20 + src/tools/clippy/src/docs/unnecessary_cast.txt | 19 + .../clippy/src/docs/unnecessary_filter_map.txt | 23 + src/tools/clippy/src/docs/unnecessary_find_map.txt | 23 + src/tools/clippy/src/docs/unnecessary_fold.txt | 17 + src/tools/clippy/src/docs/unnecessary_join.txt | 25 + .../src/docs/unnecessary_lazy_evaluations.txt | 32 + .../clippy/src/docs/unnecessary_mut_passed.txt | 17 + .../clippy/src/docs/unnecessary_operation.txt | 12 + .../src/docs/unnecessary_owned_empty_strings.txt | 16 + .../clippy/src/docs/unnecessary_self_imports.txt | 19 + src/tools/clippy/src/docs/unnecessary_sort_by.txt | 21 + src/tools/clippy/src/docs/unnecessary_to_owned.txt | 24 + src/tools/clippy/src/docs/unnecessary_unwrap.txt | 20 + src/tools/clippy/src/docs/unnecessary_wraps.txt | 36 + .../clippy/src/docs/unneeded_field_pattern.txt | 26 + .../clippy/src/docs/unneeded_wildcard_pattern.txt | 28 + src/tools/clippy/src/docs/unnested_or_patterns.txt | 22 + src/tools/clippy/src/docs/unreachable.txt | 10 + src/tools/clippy/src/docs/unreadable_literal.txt | 16 + .../clippy/src/docs/unsafe_derive_deserialize.txt | 27 + .../clippy/src/docs/unsafe_removed_from_name.txt | 15 + .../clippy/src/docs/unseparated_literal_suffix.txt | 18 + .../src/docs/unsound_collection_transmute.txt | 25 + src/tools/clippy/src/docs/unused_async.txt | 23 + src/tools/clippy/src/docs/unused_io_amount.txt | 31 + src/tools/clippy/src/docs/unused_peekable.txt | 26 + src/tools/clippy/src/docs/unused_rounding.txt | 17 + src/tools/clippy/src/docs/unused_self.txt | 23 + src/tools/clippy/src/docs/unused_unit.txt | 18 + .../clippy/src/docs/unusual_byte_groupings.txt | 12 + src/tools/clippy/src/docs/unwrap_in_result.txt | 39 + .../clippy/src/docs/unwrap_or_else_default.txt | 18 + src/tools/clippy/src/docs/unwrap_used.txt | 37 + src/tools/clippy/src/docs/upper_case_acronyms.txt | 25 + src/tools/clippy/src/docs/use_debug.txt | 12 + src/tools/clippy/src/docs/use_self.txt | 31 + .../clippy/src/docs/used_underscore_binding.txt | 19 + src/tools/clippy/src/docs/useless_asref.txt | 17 + src/tools/clippy/src/docs/useless_attribute.txt | 36 + src/tools/clippy/src/docs/useless_conversion.txt | 17 + src/tools/clippy/src/docs/useless_format.txt | 22 + src/tools/clippy/src/docs/useless_let_if_seq.txt | 39 + src/tools/clippy/src/docs/useless_transmute.txt | 12 + src/tools/clippy/src/docs/useless_vec.txt | 18 + src/tools/clippy/src/docs/vec_box.txt | 26 + src/tools/clippy/src/docs/vec_init_then_push.txt | 23 + src/tools/clippy/src/docs/vec_resize_to_zero.txt | 15 + src/tools/clippy/src/docs/verbose_bit_mask.txt | 15 + src/tools/clippy/src/docs/verbose_file_reads.txt | 17 + .../clippy/src/docs/vtable_address_comparisons.txt | 17 + .../clippy/src/docs/while_immutable_condition.txt | 20 + src/tools/clippy/src/docs/while_let_loop.txt | 25 + .../clippy/src/docs/while_let_on_iterator.txt | 20 + .../clippy/src/docs/wildcard_dependencies.txt | 13 + .../clippy/src/docs/wildcard_enum_match_arm.txt | 25 + src/tools/clippy/src/docs/wildcard_imports.txt | 45 + .../clippy/src/docs/wildcard_in_or_patterns.txt | 22 + src/tools/clippy/src/docs/write_literal.txt | 21 + src/tools/clippy/src/docs/write_with_newline.txt | 18 + src/tools/clippy/src/docs/writeln_empty_string.txt | 16 + .../clippy/src/docs/wrong_self_convention.txt | 39 + src/tools/clippy/src/docs/wrong_transmute.txt | 15 + src/tools/clippy/src/docs/zero_divided_by_zero.txt | 15 + .../clippy/src/docs/zero_prefixed_literal.txt | 32 + src/tools/clippy/src/docs/zero_ptr.txt | 16 + .../clippy/src/docs/zero_sized_map_values.txt | 24 + src/tools/clippy/src/docs/zst_offset.txt | 11 + src/tools/clippy/src/driver.rs | 2 +- src/tools/clippy/src/main.rs | 13 + src/tools/clippy/tests/check-fmt.rs | 2 +- src/tools/clippy/tests/compile-test.rs | 19 +- src/tools/clippy/tests/dogfood.rs | 4 +- src/tools/clippy/tests/integration.rs | 4 +- src/tools/clippy/tests/lint_message_convention.rs | 4 +- .../check_clippy_version_attribute.stderr | 4 +- .../arithmetic_allowed/arithmetic_allowed.rs | 24 - .../tests/ui-toml/arithmetic_allowed/clippy.toml | 1 - .../arithmetic_side_effects_allowed.rs | 24 + .../arithmetic_side_effects_allowed/clippy.toml | 1 + .../clippy/tests/ui-toml/bad_toml_type/clippy.toml | 2 +- .../ui-toml/bad_toml_type/conf_bad_type.stderr | 2 +- .../blacklisted_names_append/blacklisted_names.rs | 10 - .../blacklisted_names.stderr | 16 - .../ui-toml/blacklisted_names_append/clippy.toml | 1 - .../blacklisted_names_replace/blacklisted_names.rs | 10 - .../blacklisted_names.stderr | 10 - .../ui-toml/blacklisted_names_replace/clippy.toml | 1 - .../tests/ui-toml/conf_deprecated_key/clippy.toml | 5 +- .../conf_deprecated_key/conf_deprecated_key.rs | 10 + .../conf_deprecated_key/conf_deprecated_key.stderr | 15 +- .../ui-toml/disallowed_names_append/clippy.toml | 1 + .../disallowed_names_append/disallowed_names.rs | 10 + .../disallowed_names.stderr | 16 + .../ui-toml/disallowed_names_replace/clippy.toml | 1 + .../disallowed_names_replace/disallowed_names.rs | 10 + .../disallowed_names.stderr | 10 + .../tests/ui-toml/duplicated_keys/clippy.toml | 5 + .../ui-toml/duplicated_keys/duplicated_keys.rs | 1 + .../ui-toml/duplicated_keys/duplicated_keys.stderr | 8 + .../tests/ui-toml/expect_used/expect_used.stderr | 2 +- .../tests/ui-toml/toml_blacklist/clippy.toml | 1 - .../toml_blacklist/conf_french_blacklisted_name.rs | 20 - .../conf_french_blacklisted_name.stderr | 46 - .../clippy/tests/ui-toml/toml_disallow/clippy.toml | 1 + .../toml_disallow/conf_french_disallowed_name.rs | 20 + .../conf_french_disallowed_name.stderr | 46 + .../toml_unknown_key/conf_unknown_key.stderr | 4 +- src/tools/clippy/tests/ui/arithmetic.fixed | 27 - src/tools/clippy/tests/ui/arithmetic.rs | 27 - .../clippy/tests/ui/arithmetic_side_effects.rs | 57 + .../clippy/tests/ui/arithmetic_side_effects.stderr | 22 + .../tests/ui/assertions_on_result_states.fixed | 8 + .../clippy/tests/ui/assertions_on_result_states.rs | 8 + .../tests/ui/assertions_on_result_states.stderr | 10 +- src/tools/clippy/tests/ui/author.stdout | 2 +- src/tools/clippy/tests/ui/author/blocks.stdout | 6 +- src/tools/clippy/tests/ui/author/loop.stdout | 4 +- src/tools/clippy/tests/ui/author/matches.stdout | 4 +- src/tools/clippy/tests/ui/author/struct.rs | 7 +- src/tools/clippy/tests/ui/author/struct.stdout | 6 +- src/tools/clippy/tests/ui/blacklisted_name.rs | 57 - src/tools/clippy/tests/ui/blacklisted_name.stderr | 88 - .../clippy/tests/ui/bool_to_int_with_if.fixed | 85 + src/tools/clippy/tests/ui/bool_to_int_with_if.rs | 109 + .../clippy/tests/ui/bool_to_int_with_if.stderr | 84 + src/tools/clippy/tests/ui/borrow_box.rs | 2 +- src/tools/clippy/tests/ui/box_collection.rs | 2 +- .../case_sensitive_file_extension_comparisons.rs | 10 +- ...ase_sensitive_file_extension_comparisons.stderr | 12 +- .../clippy/tests/ui/cast_abs_to_unsigned.fixed | 2 + src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs | 2 + .../clippy/tests/ui/cast_abs_to_unsigned.stderr | 8 +- .../tests/ui/cast_raw_slice_pointer_cast.fixed | 24 + .../clippy/tests/ui/cast_raw_slice_pointer_cast.rs | 24 + .../tests/ui/cast_raw_slice_pointer_cast.stderr | 46 + src/tools/clippy/tests/ui/clone_on_copy.fixed | 7 +- src/tools/clippy/tests/ui/clone_on_copy.rs | 7 +- src/tools/clippy/tests/ui/clone_on_copy.stderr | 8 +- .../clippy/tests/ui/collapsible_str_replace.fixed | 73 + .../clippy/tests/ui/collapsible_str_replace.rs | 76 + .../clippy/tests/ui/collapsible_str_replace.stderr | 86 + src/tools/clippy/tests/ui/crashes/ice-2760.rs | 2 +- src/tools/clippy/tests/ui/crashes/ice-3462.rs | 2 +- src/tools/clippy/tests/ui/crashes/ice-9405.rs | 11 + src/tools/clippy/tests/ui/crashes/ice-9405.stderr | 11 + src/tools/clippy/tests/ui/crashes/ice-9414.rs | 8 + src/tools/clippy/tests/ui/crashes/regressions.rs | 2 +- src/tools/clippy/tests/ui/def_id_nocore.rs | 1 - src/tools/clippy/tests/ui/def_id_nocore.stderr | 2 +- .../clippy/tests/ui/default_trait_access.fixed | 6 + src/tools/clippy/tests/ui/default_trait_access.rs | 6 + .../clippy/tests/ui/default_trait_access.stderr | 18 +- src/tools/clippy/tests/ui/disallowed_names.rs | 57 + src/tools/clippy/tests/ui/disallowed_names.stderr | 88 + .../clippy/tests/ui/diverging_sub_expression.rs | 2 +- src/tools/clippy/tests/ui/empty_loop_no_std.rs | 1 - src/tools/clippy/tests/ui/empty_loop_no_std.stderr | 4 +- src/tools/clippy/tests/ui/expect.rs | 3 +- src/tools/clippy/tests/ui/expect.stderr | 12 +- .../clippy/tests/ui/expect_tool_lint_rfc_2383.rs | 4 +- .../tests/ui/expect_tool_lint_rfc_2383.stderr | 4 +- .../clippy/tests/ui/explicit_auto_deref.fixed | 51 + src/tools/clippy/tests/ui/explicit_auto_deref.rs | 51 + .../clippy/tests/ui/explicit_auto_deref.stderr | 144 +- src/tools/clippy/tests/ui/floating_point_exp.fixed | 1 + src/tools/clippy/tests/ui/floating_point_exp.rs | 1 + .../clippy/tests/ui/floating_point_exp.stderr | 12 +- src/tools/clippy/tests/ui/floating_point_log.fixed | 1 + src/tools/clippy/tests/ui/floating_point_log.rs | 1 + .../clippy/tests/ui/floating_point_log.stderr | 54 +- .../clippy/tests/ui/floating_point_logbase.fixed | 1 + .../clippy/tests/ui/floating_point_logbase.rs | 1 + .../clippy/tests/ui/floating_point_logbase.stderr | 12 +- .../clippy/tests/ui/floating_point_powf.fixed | 8 + src/tools/clippy/tests/ui/floating_point_powf.rs | 8 + .../clippy/tests/ui/floating_point_powf.stderr | 76 +- .../clippy/tests/ui/floating_point_powi.fixed | 1 + src/tools/clippy/tests/ui/floating_point_powi.rs | 1 + .../clippy/tests/ui/floating_point_powi.stderr | 10 +- src/tools/clippy/tests/ui/floating_point_rad.fixed | 5 + src/tools/clippy/tests/ui/floating_point_rad.rs | 5 + .../clippy/tests/ui/floating_point_rad.stderr | 28 +- src/tools/clippy/tests/ui/format.fixed | 2 +- src/tools/clippy/tests/ui/format.rs | 2 +- src/tools/clippy/tests/ui/format_args.fixed | 51 +- src/tools/clippy/tests/ui/format_args.rs | 51 +- src/tools/clippy/tests/ui/format_args.stderr | 56 +- src/tools/clippy/tests/ui/identity_op.fixed | 2 +- src/tools/clippy/tests/ui/identity_op.rs | 2 +- src/tools/clippy/tests/ui/if_let_mutex.rs | 8 + src/tools/clippy/tests/ui/if_let_mutex.stderr | 30 +- src/tools/clippy/tests/ui/if_same_then_else.rs | 2 +- src/tools/clippy/tests/ui/if_same_then_else2.rs | 2 +- .../clippy/tests/ui/if_then_some_else_none.stderr | 8 +- src/tools/clippy/tests/ui/ifs_same_cond.rs | 4 +- .../clippy/tests/ui/indexing_slicing_index.rs | 2 +- .../tests/ui/iter_on_empty_collections.fixed | 63 + .../clippy/tests/ui/iter_on_empty_collections.rs | 63 + .../tests/ui/iter_on_empty_collections.stderr | 40 + .../clippy/tests/ui/iter_on_single_items.fixed | 63 + src/tools/clippy/tests/ui/iter_on_single_items.rs | 63 + .../clippy/tests/ui/iter_on_single_items.stderr | 40 + src/tools/clippy/tests/ui/iter_skip_next.fixed | 2 +- src/tools/clippy/tests/ui/iter_skip_next.rs | 2 +- src/tools/clippy/tests/ui/large_enum_variant.rs | 24 + .../clippy/tests/ui/large_enum_variant.stderr | 256 +- src/tools/clippy/tests/ui/let_if_seq.rs | 2 +- src/tools/clippy/tests/ui/logic_bug.rs | 34 - src/tools/clippy/tests/ui/logic_bug.stderr | 63 - .../tests/ui/manual_assert.edition2018.fixed | 2 +- .../tests/ui/manual_assert.edition2021.fixed | 2 +- src/tools/clippy/tests/ui/manual_assert.fixed | 2 +- src/tools/clippy/tests/ui/manual_assert.rs | 2 +- .../clippy/tests/ui/manual_instant_elapsed.fixed | 27 + .../clippy/tests/ui/manual_instant_elapsed.rs | 27 + .../clippy/tests/ui/manual_instant_elapsed.stderr | 16 + src/tools/clippy/tests/ui/manual_ok_or.fixed | 2 +- src/tools/clippy/tests/ui/manual_ok_or.rs | 2 +- src/tools/clippy/tests/ui/manual_string_new.fixed | 63 + src/tools/clippy/tests/ui/manual_string_new.rs | 63 + src/tools/clippy/tests/ui/manual_string_new.stderr | 58 + .../tests/ui/match_expr_like_matches_macro.fixed | 25 + .../tests/ui/match_expr_like_matches_macro.rs | 25 + src/tools/clippy/tests/ui/match_same_arms2.rs | 2 +- .../tests/ui/match_wild_err_arm.edition2018.stderr | 8 +- .../tests/ui/match_wild_err_arm.edition2021.stderr | 8 +- src/tools/clippy/tests/ui/methods.rs | 2 +- .../tests/ui/mismatching_type_param_order.rs | 2 +- .../clippy/tests/ui/missing-doc-crate-missing.rs | 3 - .../tests/ui/missing-doc-crate-missing.stderr | 12 - src/tools/clippy/tests/ui/missing-doc-crate.rs | 4 - src/tools/clippy/tests/ui/missing-doc-impl.rs | 92 - src/tools/clippy/tests/ui/missing-doc-impl.stderr | 107 - src/tools/clippy/tests/ui/missing-doc.rs | 102 - src/tools/clippy/tests/ui/missing-doc.stderr | 159 - .../tests/ui/missing_const_for_fn/cant_be_const.rs | 9 + src/tools/clippy/tests/ui/missing_doc.rs | 115 + src/tools/clippy/tests/ui/missing_doc.stderr | 159 + src/tools/clippy/tests/ui/missing_doc_crate.rs | 4 + .../clippy/tests/ui/missing_doc_crate_missing.rs | 3 + .../tests/ui/missing_doc_crate_missing.stderr | 12 + src/tools/clippy/tests/ui/missing_doc_impl.rs | 107 + src/tools/clippy/tests/ui/missing_doc_impl.stderr | 107 + .../clippy/tests/ui/mistyped_literal_suffix.fixed | 6 + .../clippy/tests/ui/mistyped_literal_suffix.rs | 6 + .../clippy/tests/ui/mistyped_literal_suffix.stderr | 32 +- .../tests/ui/mixed_read_write_in_expression.rs | 2 +- src/tools/clippy/tests/ui/multi_assignments.rs | 9 + src/tools/clippy/tests/ui/multi_assignments.stderr | 40 + src/tools/clippy/tests/ui/mut_mutex_lock.fixed | 7 + src/tools/clippy/tests/ui/mut_mutex_lock.rs | 7 + src/tools/clippy/tests/ui/needless_borrow.fixed | 117 +- src/tools/clippy/tests/ui/needless_borrow.rs | 117 +- src/tools/clippy/tests/ui/needless_borrow.stderr | 48 +- .../clippy/tests/ui/needless_collect_indirect.rs | 189 + .../tests/ui/needless_collect_indirect.stderr | 119 +- src/tools/clippy/tests/ui/needless_match.fixed | 39 + src/tools/clippy/tests/ui/needless_match.rs | 46 + src/tools/clippy/tests/ui/needless_match.stderr | 23 +- src/tools/clippy/tests/ui/needless_return.fixed | 11 +- src/tools/clippy/tests/ui/needless_return.rs | 11 +- src/tools/clippy/tests/ui/needless_return.stderr | 74 +- .../clippy/tests/ui/only_used_in_recursion.rs | 133 +- .../clippy/tests/ui/only_used_in_recursion.stderr | 193 +- .../clippy/tests/ui/only_used_in_recursion2.rs | 91 + .../clippy/tests/ui/only_used_in_recursion2.stderr | 63 + src/tools/clippy/tests/ui/op_ref.rs | 2 +- src/tools/clippy/tests/ui/option_if_let_else.fixed | 9 + src/tools/clippy/tests/ui/option_if_let_else.rs | 21 + .../clippy/tests/ui/option_if_let_else.stderr | 48 +- src/tools/clippy/tests/ui/or_fun_call.fixed | 12 +- src/tools/clippy/tests/ui/or_fun_call.rs | 4 +- src/tools/clippy/tests/ui/or_fun_call.stderr | 32 +- .../clippy/tests/ui/overly_complex_bool_expr.rs | 34 + .../tests/ui/overly_complex_bool_expr.stderr | 63 + src/tools/clippy/tests/ui/partialeq_to_none.fixed | 74 + src/tools/clippy/tests/ui/partialeq_to_none.rs | 74 + src/tools/clippy/tests/ui/partialeq_to_none.stderr | 110 + .../ui/positional_named_format_parameters.fixed | 56 + .../tests/ui/positional_named_format_parameters.rs | 56 + .../ui/positional_named_format_parameters.stderr | 418 ++ src/tools/clippy/tests/ui/question_mark.fixed | 15 + src/tools/clippy/tests/ui/question_mark.rs | 15 + .../clippy/tests/ui/range_plus_minus_one.fixed | 19 + src/tools/clippy/tests/ui/range_plus_minus_one.rs | 19 + .../clippy/tests/ui/range_plus_minus_one.stderr | 18 +- src/tools/clippy/tests/ui/rc_mutex.rs | 2 +- src/tools/clippy/tests/ui/redundant_allocation.rs | 12 +- .../clippy/tests/ui/redundant_allocation.stderr | 40 +- .../tests/ui/redundant_allocation_fixable.fixed | 2 +- .../tests/ui/redundant_allocation_fixable.rs | 2 +- .../tests/ui/redundant_closure_call_fixable.fixed | 20 + .../tests/ui/redundant_closure_call_fixable.rs | 20 + .../tests/ui/redundant_closure_call_fixable.stderr | 50 +- src/tools/clippy/tests/ui/regex.rs | 2 +- src/tools/clippy/tests/ui/rename.fixed | 4 + src/tools/clippy/tests/ui/rename.rs | 4 + src/tools/clippy/tests/ui/rename.stderr | 88 +- src/tools/clippy/tests/ui/result_large_err.rs | 99 + src/tools/clippy/tests/ui/result_large_err.stderr | 91 + .../tests/ui/same_functions_in_if_condition.rs | 4 +- .../tests/ui/same_functions_in_if_condition.stderr | 8 +- src/tools/clippy/tests/ui/same_item_push.rs | 1 + .../tests/ui/semicolon_if_nothing_returned.rs | 2 - .../tests/ui/semicolon_if_nothing_returned.stderr | 10 +- src/tools/clippy/tests/ui/skip_while_next.rs | 2 +- src/tools/clippy/tests/ui/string_add.rs | 4 +- src/tools/clippy/tests/ui/string_add_assign.fixed | 4 +- src/tools/clippy/tests/ui/string_add_assign.rs | 4 +- src/tools/clippy/tests/ui/suspicious_to_owned.rs | 62 + .../clippy/tests/ui/suspicious_to_owned.stderr | 42 + src/tools/clippy/tests/ui/swap.fixed | 2 +- src/tools/clippy/tests/ui/swap.rs | 2 +- .../tests/ui/trait_duplication_in_bounds.fixed | 112 + .../clippy/tests/ui/trait_duplication_in_bounds.rs | 218 +- .../tests/ui/trait_duplication_in_bounds.stderr | 165 +- .../ui/trait_duplication_in_bounds_unfixable.rs | 166 + .../trait_duplication_in_bounds_unfixable.stderr | 71 + .../clippy/tests/ui/transmute_undefined_repr.rs | 12 + .../tests/ui/transmute_undefined_repr.stderr | 38 +- .../clippy/tests/ui/trivially_copy_pass_by_ref.rs | 2 +- src/tools/clippy/tests/ui/unicode.fixed | 48 +- src/tools/clippy/tests/ui/unicode.rs | 48 +- src/tools/clippy/tests/ui/unicode.stderr | 46 +- src/tools/clippy/tests/ui/uninit.rs | 2 +- src/tools/clippy/tests/ui/unit_arg.rs | 12 +- src/tools/clippy/tests/ui/unit_arg.stderr | 20 +- src/tools/clippy/tests/ui/unnecessary_cast.fixed | 9 + src/tools/clippy/tests/ui/unnecessary_cast.rs | 9 + src/tools/clippy/tests/ui/unnecessary_cast.stderr | 14 +- .../tests/ui/unnecessary_owned_empty_strings.fixed | 1 + .../tests/ui/unnecessary_owned_empty_strings.rs | 1 + .../ui/unnecessary_owned_empty_strings.stderr | 2 +- .../clippy/tests/ui/unnecessary_to_owned.fixed | 88 + src/tools/clippy/tests/ui/unnecessary_to_owned.rs | 88 + .../clippy/tests/ui/unnecessary_to_owned.stderr | 8 +- src/tools/clippy/tests/ui/unused_peekable.rs | 144 + src/tools/clippy/tests/ui/unused_peekable.stderr | 67 + src/tools/clippy/tests/ui/unwrap.rs | 3 +- src/tools/clippy/tests/ui/unwrap.stderr | 10 +- src/tools/clippy/tests/ui/unwrap_expect_used.rs | 35 + .../clippy/tests/ui/unwrap_expect_used.stderr | 52 + .../clippy/tests/ui/unwrap_or_else_default.fixed | 3 + .../clippy/tests/ui/unwrap_or_else_default.rs | 3 + .../clippy/tests/ui/unwrap_or_else_default.stderr | 8 +- .../clippy/tests/ui/used_underscore_binding.rs | 2 +- .../clippy/tests/ui/useless_conversion_try.rs | 4 +- .../clippy/tests/ui/useless_conversion_try.stderr | 2 +- src/tools/clippy/tests/ui/vec_resize_to_zero.rs | 12 +- .../clippy/tests/ui/vec_resize_to_zero.stderr | 10 +- src/tools/clippy/tests/ui/verbose_file_reads.rs | 2 +- src/tools/clippy/tests/workspace.rs | 14 +- src/tools/compiletest/Cargo.toml | 1 + src/tools/compiletest/src/common.rs | 132 + src/tools/compiletest/src/header.rs | 49 +- src/tools/compiletest/src/header/tests.rs | 193 +- src/tools/compiletest/src/main.rs | 9 +- src/tools/compiletest/src/runtest.rs | 26 +- src/tools/compiletest/src/util.rs | 152 - src/tools/compiletest/src/util/tests.rs | 37 - src/tools/error_index_generator/Cargo.toml | 5 +- src/tools/error_index_generator/book_config.toml | 19 + src/tools/error_index_generator/build.rs | 31 - src/tools/error_index_generator/error-index.css | 38 + src/tools/error_index_generator/error-index.js | 9 + src/tools/error_index_generator/main.rs | 377 +- src/tools/error_index_generator/redirect.js | 16 + src/tools/jsondocck/src/cache.rs | 70 +- src/tools/jsondocck/src/main.rs | 122 +- src/tools/jsondoclint/Cargo.toml | 12 + src/tools/jsondoclint/src/item_kind.rs | 184 + src/tools/jsondoclint/src/json_find.rs | 74 + src/tools/jsondoclint/src/main.rs | 64 + src/tools/jsondoclint/src/validator.rs | 442 +++ src/tools/lint-docs/src/groups.rs | 1 + src/tools/lld-wrapper/src/main.rs | 41 +- src/tools/publish_toolstate.py | 14 +- src/tools/replace-version-placeholder/Cargo.toml | 10 + src/tools/replace-version-placeholder/src/main.rs | 30 + src/tools/rust-analyzer/.vscode/launch.json | 2 +- src/tools/rust-analyzer/Cargo.lock | 241 +- src/tools/rust-analyzer/README.md | 2 +- .../rust-analyzer/bench_data/glorious_old_parser | 2 +- .../rust-analyzer/crates/base-db/src/input.rs | 42 +- src/tools/rust-analyzer/crates/base-db/src/lib.rs | 12 +- src/tools/rust-analyzer/crates/flycheck/src/lib.rs | 53 +- src/tools/rust-analyzer/crates/hir-def/src/body.rs | 24 +- .../rust-analyzer/crates/hir-def/src/body/lower.rs | 127 +- .../crates/hir-def/src/body/pretty.rs | 608 +++ .../rust-analyzer/crates/hir-def/src/body/scope.rs | 34 +- .../crates/hir-def/src/builtin_type.rs | 35 + src/tools/rust-analyzer/crates/hir-def/src/data.rs | 70 +- src/tools/rust-analyzer/crates/hir-def/src/db.rs | 9 +- src/tools/rust-analyzer/crates/hir-def/src/expr.rs | 12 +- .../rust-analyzer/crates/hir-def/src/generics.rs | 2 +- .../rust-analyzer/crates/hir-def/src/item_tree.rs | 2 +- .../crates/hir-def/src/item_tree/pretty.rs | 179 +- .../crates/hir-def/src/item_tree/tests.rs | 12 +- src/tools/rust-analyzer/crates/hir-def/src/lib.rs | 1 + .../src/macro_expansion_tests/builtin_fn_macro.rs | 4 +- .../hir-def/src/macro_expansion_tests/mbe.rs | 12 +- .../src/macro_expansion_tests/mbe/regression.rs | 4 +- .../src/macro_expansion_tests/mbe/tt_conversion.rs | 2 +- .../src/macro_expansion_tests/proc_macros.rs | 2 +- .../rust-analyzer/crates/hir-def/src/nameres.rs | 15 +- .../crates/hir-def/src/nameres/collector.rs | 24 +- .../crates/hir-def/src/nameres/diagnostics.rs | 2 +- .../crates/hir-def/src/nameres/mod_resolution.rs | 1 + .../crates/hir-def/src/nameres/path_resolution.rs | 32 +- .../crates/hir-def/src/nameres/proc_macro.rs | 2 +- .../hir-def/src/nameres/tests/mod_resolution.rs | 20 +- .../rust-analyzer/crates/hir-def/src/per_ns.rs | 12 + .../rust-analyzer/crates/hir-def/src/pretty.rs | 209 + .../rust-analyzer/crates/hir-def/src/resolver.rs | 253 +- .../rust-analyzer/crates/hir-def/src/test_db.rs | 4 +- .../rust-analyzer/crates/hir-def/src/type_ref.rs | 4 + .../rust-analyzer/crates/hir-def/src/visibility.rs | 2 +- .../crates/hir-expand/src/ast_id_map.rs | 21 +- .../crates/hir-expand/src/builtin_fn_macro.rs | 22 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 6 +- .../rust-analyzer/crates/hir-expand/src/fixup.rs | 298 +- .../rust-analyzer/crates/hir-expand/src/lib.rs | 5 +- .../crates/hir-expand/src/mod_path.rs | 17 +- .../rust-analyzer/crates/hir-expand/src/name.rs | 63 +- .../rust-analyzer/crates/hir-expand/src/quote.rs | 4 +- src/tools/rust-analyzer/crates/hir-ty/Cargo.toml | 6 +- .../rust-analyzer/crates/hir-ty/src/autoderef.rs | 3 +- .../rust-analyzer/crates/hir-ty/src/chalk_ext.rs | 2 + .../rust-analyzer/crates/hir-ty/src/consteval.rs | 1 - .../crates/hir-ty/src/diagnostics/expr.rs | 7 +- .../src/diagnostics/match_check/deconstruct_pat.rs | 16 +- .../src/diagnostics/match_check/usefulness.rs | 29 +- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 39 +- .../rust-analyzer/crates/hir-ty/src/infer/expr.rs | 244 +- .../rust-analyzer/crates/hir-ty/src/infer/pat.rs | 33 +- .../crates/hir-ty/src/inhabitedness.rs | 173 + src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 1 + src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 184 +- .../crates/hir-ty/src/method_resolution.rs | 193 +- .../rust-analyzer/crates/hir-ty/src/test_db.rs | 6 +- .../crates/hir-ty/src/tests/macros.rs | 14 +- .../crates/hir-ty/src/tests/method_resolution.rs | 43 + .../crates/hir-ty/src/tests/patterns.rs | 81 + .../crates/hir-ty/src/tests/regression.rs | 45 +- .../crates/hir-ty/src/tests/simple.rs | 15 +- .../crates/hir-ty/src/tests/traits.rs | 173 + src/tools/rust-analyzer/crates/hir-ty/src/utils.rs | 21 +- .../rust-analyzer/crates/hir/src/diagnostics.rs | 2 + src/tools/rust-analyzer/crates/hir/src/lib.rs | 72 +- .../rust-analyzer/crates/hir/src/semantics.rs | 40 + .../crates/hir/src/source_analyzer.rs | 159 +- .../crates/ide-assists/src/assist_context.rs | 157 +- .../src/handlers/add_missing_impl_members.rs | 2 +- .../src/handlers/add_missing_match_arms.rs | 1 + .../convert_tuple_struct_to_named_struct.rs | 10 +- .../convert_two_arm_bool_match_to_matches_macro.rs | 294 ++ .../src/handlers/destructure_tuple_binding.rs | 10 +- .../ide-assists/src/handlers/extract_module.rs | 6 +- .../handlers/extract_struct_from_enum_variant.rs | 119 +- .../ide-assists/src/handlers/extract_type_alias.rs | 44 + .../ide-assists/src/handlers/generate_deref.rs | 4 +- .../src/handlers/generate_enum_variant.rs | 375 +- .../ide-assists/src/handlers/generate_function.rs | 142 +- .../crates/ide-assists/src/handlers/inline_call.rs | 101 +- .../ide-assists/src/handlers/inline_type_alias.rs | 248 +- .../src/handlers/introduce_named_lifetime.rs | 4 +- .../ide-assists/src/handlers/merge_imports.rs | 8 +- .../crates/ide-assists/src/handlers/move_bounds.rs | 6 +- .../src/handlers/remove_unused_param.rs | 5 +- .../handlers/replace_derive_with_manual_impl.rs | 4 +- .../src/handlers/replace_or_with_or_else.rs | 364 ++ .../replace_turbofish_with_explicit_type.rs | 162 +- .../ide-assists/src/handlers/unmerge_match_arm.rs | 293 ++ .../crates/ide-assists/src/handlers/unmerge_use.rs | 2 +- .../rust-analyzer/crates/ide-assists/src/lib.rs | 8 + .../crates/ide-assists/src/tests/generated.rs | 111 + .../rust-analyzer/crates/ide-assists/src/utils.rs | 6 +- .../crates/ide-assists/src/utils/suggest_name.rs | 5 +- .../crates/ide-completion/src/completions.rs | 1 - .../crates/ide-completion/src/completions/dot.rs | 2 +- .../crates/ide-completion/src/completions/expr.rs | 124 +- .../src/completions/item_list/trait_impl.rs | 3 +- .../ide-completion/src/completions/keyword.rs | 70 +- .../crates/ide-completion/src/completions/mod_.rs | 20 + .../src/completions/postfix/format_like.rs | 4 +- .../ide-completion/src/completions/record.rs | 69 +- .../crates/ide-completion/src/context.rs | 4 + .../crates/ide-completion/src/context/analysis.rs | 3 + .../crates/ide-completion/src/render.rs | 42 +- .../crates/ide-completion/src/render/const_.rs | 2 +- .../crates/ide-completion/src/render/function.rs | 24 +- .../crates/ide-completion/src/render/literal.rs | 26 +- .../crates/ide-completion/src/render/macro_.rs | 2 +- .../crates/ide-completion/src/render/pattern.rs | 28 +- .../crates/ide-completion/src/render/type_alias.rs | 4 +- .../ide-completion/src/render/union_literal.rs | 21 +- .../crates/ide-completion/src/render/variant.rs | 13 +- .../crates/ide-completion/src/tests/expression.rs | 77 +- .../crates/ide-completion/src/tests/flyimport.rs | 2 +- .../crates/ide-completion/src/tests/pattern.rs | 2 +- .../crates/ide-completion/src/tests/record.rs | 54 +- .../crates/ide-db/src/active_parameter.rs | 8 +- .../crates/ide-db/src/apply_change.rs | 4 +- src/tools/rust-analyzer/crates/ide-db/src/defs.rs | 80 + .../crates/ide-db/src/imports/insert_use.rs | 31 +- src/tools/rust-analyzer/crates/ide-db/src/lib.rs | 3 +- .../rust-analyzer/crates/ide-db/src/line_index.rs | 6 +- .../rust-analyzer/crates/ide-db/src/rename.rs | 2 +- .../rust-analyzer/crates/ide-db/src/search.rs | 28 +- .../crates/ide-db/src/source_change.rs | 147 +- .../syntax_helpers/insert_whitespace_into_node.rs | 2 +- .../crates/ide-db/src/syntax_helpers/node_ext.rs | 1 - .../crates/ide-diagnostics/Cargo.toml | 1 + .../src/handlers/break_outside_of_loop.rs | 120 +- .../ide-diagnostics/src/handlers/inactive_code.rs | 7 +- .../src/handlers/json_is_not_rust.rs | 310 ++ .../ide-diagnostics/src/handlers/macro_error.rs | 2 +- .../src/handlers/missing_match_arms.rs | 46 +- .../ide-diagnostics/src/handlers/no_such_field.rs | 18 +- .../crates/ide-diagnostics/src/lib.rs | 33 +- .../crates/ide-diagnostics/src/tests.rs | 12 +- src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml | 1 + src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs | 12 +- .../rust-analyzer/crates/ide/src/call_hierarchy.rs | 4 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 2 +- .../rust-analyzer/crates/ide/src/expand_macro.rs | 4 +- .../crates/ide/src/goto_definition.rs | 158 +- .../crates/ide/src/goto_implementation.rs | 2 +- .../crates/ide/src/highlight_related.rs | 3 +- src/tools/rust-analyzer/crates/ide/src/hover.rs | 25 +- .../rust-analyzer/crates/ide/src/hover/render.rs | 23 +- .../rust-analyzer/crates/ide/src/hover/tests.rs | 134 +- .../rust-analyzer/crates/ide/src/inlay_hints.rs | 186 +- .../rust-analyzer/crates/ide/src/join_lines.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 24 +- .../rust-analyzer/crates/ide/src/matching_brace.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/moniker.rs | 133 +- .../rust-analyzer/crates/ide/src/move_item.rs | 4 +- .../rust-analyzer/crates/ide/src/parent_module.rs | 2 +- .../rust-analyzer/crates/ide/src/prime_caches.rs | 5 +- .../rust-analyzer/crates/ide/src/references.rs | 5 +- .../rust-analyzer/crates/ide/src/runnables.rs | 267 +- .../crates/ide/src/shuffle_crate_graph.rs | 2 +- .../rust-analyzer/crates/ide/src/static_index.rs | 9 +- src/tools/rust-analyzer/crates/ide/src/status.rs | 4 +- .../crates/ide/src/syntax_highlighting.rs | 74 +- .../crates/ide/src/syntax_highlighting/html.rs | 21 +- .../crates/ide/src/syntax_highlighting/inject.rs | 21 +- .../crates/ide/src/syntax_highlighting/tags.rs | 8 +- .../test_data/highlight_doctest.html | 2 +- .../crates/ide/src/syntax_highlighting/tests.rs | 30 +- .../rust-analyzer/crates/ide/src/syntax_tree.rs | 2 +- .../crates/ide/src/view_crate_graph.rs | 7 +- src/tools/rust-analyzer/crates/ide/src/view_hir.rs | 16 +- .../rust-analyzer/crates/ide/src/view_item_tree.rs | 2 +- .../crates/mbe/src/expander/matcher.rs | 2 +- .../rust-analyzer/crates/mbe/src/syntax_bridge.rs | 11 +- .../crates/parser/src/grammar/expressions.rs | 26 +- .../crates/parser/src/grammar/paths.rs | 5 + .../crates/parser/src/grammar/patterns.rs | 47 +- .../crates/parser/src/syntax_kind/generated.rs | 130 +- ...4_record_literal_missing_ellipsis_recovery.rast | 43 + ...014_record_literal_missing_ellipsis_recovery.rs | 3 + .../test_data/parser/inline/ok/0024_slice_pat.rast | 23 + .../test_data/parser/inline/ok/0024_slice_pat.rs | 1 + .../parser/inline/ok/0026_tuple_pat_fields.rast | 23 + .../parser/inline/ok/0026_tuple_pat_fields.rs | 1 + .../test_data/parser/inline/ok/0058_range_pat.rast | 116 + .../test_data/parser/inline/ok/0058_range_pat.rs | 10 + .../parser/inline/ok/0061_record_lit.rast | 49 + .../test_data/parser/inline/ok/0061_record_lit.rs | 2 + .../test_data/parser/inline/ok/0111_tuple_pat.rast | 40 + .../test_data/parser/inline/ok/0111_tuple_pat.rs | 1 + .../parser/inline/ok/0166_half_open_range_pat.rast | 23 +- .../parser/inline/ok/0166_half_open_range_pat.rs | 5 +- .../inline/ok/0202_typepathfn_with_coloncolon.rast | 43 + .../inline/ok/0202_typepathfn_with_coloncolon.rs | 1 + src/tools/rust-analyzer/crates/paths/src/lib.rs | 8 + .../rust-analyzer/crates/proc-macro-api/src/lib.rs | 2 +- .../crates/proc-macro-api/src/msg/flat.rs | 5 +- .../rust-analyzer/crates/proc-macro-srv/Cargo.toml | 1 - .../src/abis/abi_1_58/proc_macro/mod.rs | 4 +- .../proc-macro-srv/src/abis/abi_1_58/ra_server.rs | 1 - .../src/abis/abi_1_63/proc_macro/mod.rs | 4 +- .../proc-macro-srv/src/abis/abi_1_63/ra_server.rs | 1 - .../crates/proc-macro-srv/src/abis/abi_1_64/mod.rs | 105 - .../src/abis/abi_1_64/proc_macro/bridge/buffer.rs | 156 - .../src/abis/abi_1_64/proc_macro/bridge/client.rs | 529 --- .../src/abis/abi_1_64/proc_macro/bridge/closure.rs | 32 - .../src/abis/abi_1_64/proc_macro/bridge/handle.rs | 89 - .../src/abis/abi_1_64/proc_macro/bridge/mod.rs | 493 --- .../src/abis/abi_1_64/proc_macro/bridge/rpc.rs | 304 -- .../abis/abi_1_64/proc_macro/bridge/scoped_cell.rs | 81 - .../abi_1_64/proc_macro/bridge/selfless_reify.rs | 84 - .../src/abis/abi_1_64/proc_macro/bridge/server.rs | 339 -- .../src/abis/abi_1_64/proc_macro/diagnostic.rs | 166 - .../src/abis/abi_1_64/proc_macro/mod.rs | 1125 ------ .../src/abis/abi_1_64/proc_macro/quote.rs | 139 - .../proc-macro-srv/src/abis/abi_1_64/ra_server.rs | 792 ---- .../src/abis/abi_sysroot/ra_server.rs | 61 +- .../crates/proc-macro-srv/src/abis/mod.rs | 13 +- .../crates/proc-macro-srv/src/dylib.rs | 1 - .../rust-analyzer/crates/proc-macro-srv/src/lib.rs | 17 +- .../crates/proc-macro-srv/src/tests/mod.rs | 6 +- .../crates/project-model/src/build_scripts.rs | 26 +- .../crates/project-model/src/cargo_workspace.rs | 2 +- .../rust-analyzer/crates/project-model/src/lib.rs | 2 +- .../crates/project-model/src/tests.rs | 715 ++-- .../crates/project-model/src/workspace.rs | 24 +- .../rust-analyzer/crates/rust-analyzer/Cargo.toml | 5 +- .../crates/rust-analyzer/src/bin/logger.rs | 2 +- .../crates/rust-analyzer/src/bin/main.rs | 1 + .../crates/rust-analyzer/src/bin/rustc_wrapper.rs | 7 +- .../rust-analyzer/crates/rust-analyzer/src/cli.rs | 1 + .../crates/rust-analyzer/src/cli/diagnostics.rs | 2 +- .../crates/rust-analyzer/src/cli/flags.rs | 16 +- .../crates/rust-analyzer/src/cli/scip.rs | 448 +++ .../crates/rust-analyzer/src/config.rs | 61 +- .../crates/rust-analyzer/src/diagnostics.rs | 37 +- .../rust-analyzer/src/diagnostics/to_proto.rs | 2 +- .../crates/rust-analyzer/src/global_state.rs | 40 +- .../crates/rust-analyzer/src/handlers.rs | 67 +- .../rust-analyzer/src/integrated_benchmarks.rs | 4 +- .../crates/rust-analyzer/src/lsp_ext.rs | 8 + .../crates/rust-analyzer/src/main_loop.rs | 497 ++- .../crates/rust-analyzer/src/reload.rs | 79 +- .../crates/rust-analyzer/src/semantic_tokens.rs | 191 +- .../crates/rust-analyzer/src/to_proto.rs | 114 +- .../crates/rust-analyzer/tests/slow-tests/tidy.rs | 7 +- .../rust-analyzer/crates/sourcegen/src/lib.rs | 14 +- src/tools/rust-analyzer/crates/stdx/src/hash.rs | 80 + src/tools/rust-analyzer/crates/stdx/src/lib.rs | 1 + src/tools/rust-analyzer/crates/syntax/rust.ungram | 1 - .../crates/syntax/src/ast/edit_in_place.rs | 193 +- .../crates/syntax/src/ast/generated/nodes.rs | 415 +- .../rust-analyzer/crates/syntax/src/ast/make.rs | 264 +- .../crates/syntax/src/ast/operators.rs | 2 +- .../crates/syntax/src/ast/token_ext.rs | 21 +- src/tools/rust-analyzer/crates/syntax/src/fuzz.rs | 5 +- src/tools/rust-analyzer/crates/syntax/src/hacks.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/lib.rs | 2 +- .../crates/syntax/src/tests/sourcegen_ast.rs | 27 +- .../crates/test-utils/src/minicore.rs | 15 + .../rust-analyzer/crates/vfs-notify/Cargo.toml | 2 +- .../rust-analyzer/crates/vfs-notify/src/lib.rs | 18 +- src/tools/rust-analyzer/crates/vfs/Cargo.toml | 3 +- src/tools/rust-analyzer/crates/vfs/src/file_set.rs | 3 +- src/tools/rust-analyzer/crates/vfs/src/lib.rs | 11 +- src/tools/rust-analyzer/docs/dev/README.md | 8 +- src/tools/rust-analyzer/docs/dev/architecture.md | 4 +- src/tools/rust-analyzer/docs/dev/guide.md | 2 +- src/tools/rust-analyzer/docs/dev/lsp-extensions.md | 2 +- .../rust-analyzer/docs/user/generated_config.adoc | 56 + src/tools/rust-analyzer/docs/user/manual.adoc | 15 +- src/tools/rust-analyzer/lib/la-arena/src/lib.rs | 50 +- src/tools/rust-analyzer/lib/la-arena/src/map.rs | 169 +- .../rust-analyzer/lib/lsp-server/src/socket.rs | 2 +- src/tools/rust-analyzer/xtask/src/release.rs | 2 +- src/tools/rustc-workspace-hack/Cargo.toml | 14 +- src/tools/rustc-workspace-hack/README.md | 12 +- src/tools/rustdoc-gui/tester.js | 16 + src/tools/rustfmt/Processes.md | 4 - src/tools/rustfmt/README.md | 2 +- src/tools/rustfmt/atom.md | 4 +- src/tools/rustfmt/src/attr.rs | 5 +- src/tools/rustfmt/src/expr.rs | 8 +- src/tools/rustfmt/src/imports.rs | 4 +- src/tools/rustfmt/src/modules.rs | 8 +- src/tools/rustfmt/src/parse/parser.rs | 2 +- src/tools/rustfmt/src/parse/session.rs | 52 +- src/tools/rustfmt/src/patterns.rs | 12 +- src/tools/rustfmt/src/skip.rs | 4 +- src/tools/rustfmt/src/visitor.rs | 4 +- src/tools/rustfmt/tests/source/issue-3217.rs | 2 - src/tools/rustfmt/tests/source/issue_4257.rs | 3 - src/tools/rustfmt/tests/source/issue_4911.rs | 1 - src/tools/rustfmt/tests/source/issue_4943.rs | 2 - src/tools/rustfmt/tests/target/issue-3217.rs | 2 - src/tools/rustfmt/tests/target/issue_4257.rs | 3 - src/tools/rustfmt/tests/target/issue_4911.rs | 1 - src/tools/rustfmt/tests/target/issue_4943.rs | 2 - src/tools/tidy/Cargo.toml | 1 - src/tools/tidy/src/bins.rs | 10 +- src/tools/tidy/src/deps.rs | 16 +- src/tools/tidy/src/error_codes_check.rs | 2 +- src/tools/tidy/src/features.rs | 37 + src/tools/tidy/src/features/version.rs | 19 +- src/tools/tidy/src/lib.rs | 74 +- src/tools/tidy/src/main.rs | 7 +- src/tools/tidy/src/pal.rs | 2 + src/tools/tidy/src/style.rs | 15 +- src/tools/tidy/src/walk.rs | 66 + .../unicode-table-generator/src/cascading_map.rs | 78 + src/tools/unicode-table-generator/src/main.rs | 12 +- .../unicode-table-generator/src/range_search.rs | 15 +- .../unicode-table-generator/src/raw_emitter.rs | 32 +- .../src/unicode_download.rs | 31 +- src/tools/unstable-book-gen/src/main.rs | 33 +- src/version | 2 +- .../annotate-snippets-0.8.0/.cargo-checksum.json | 1 - vendor/annotate-snippets-0.8.0/CHANGELOG.md | 29 - vendor/annotate-snippets-0.8.0/Cargo.lock | 630 --- vendor/annotate-snippets-0.8.0/Cargo.toml | 62 - vendor/annotate-snippets-0.8.0/LICENSE-APACHE | 201 - vendor/annotate-snippets-0.8.0/LICENSE-MIT | 19 - vendor/annotate-snippets-0.8.0/README.md | 92 - vendor/annotate-snippets-0.8.0/benches/simple.rs | 74 - .../examples/expected_type.rs | 43 - vendor/annotate-snippets-0.8.0/examples/footer.rs | 39 - vendor/annotate-snippets-0.8.0/examples/format.rs | 61 - .../annotate-snippets-0.8.0/examples/multislice.rs | 38 - .../src/display_list/from_snippet.rs | 517 --- .../src/display_list/mod.rs | 37 - .../src/display_list/structs.rs | 191 - .../annotate-snippets-0.8.0/src/formatter/mod.rs | 397 -- .../annotate-snippets-0.8.0/src/formatter/style.rs | 52 - vendor/annotate-snippets-0.8.0/src/lib.rs | 54 - vendor/annotate-snippets-0.8.0/src/snippet.rs | 88 - .../src/stylesheets/color.rs | 50 - .../annotate-snippets-0.8.0/src/stylesheets/mod.rs | 11 - .../src/stylesheets/no_color.rs | 31 - vendor/annotate-snippets-0.8.0/tests/diff/mod.rs | 43 - .../tests/dl_from_snippet.rs | 401 -- .../fixtures/no-color/multiline_annotation.toml | 40 - .../fixtures/no-color/multiline_annotation.txt | 14 - .../fixtures/no-color/multiline_annotation2.toml | 18 - .../fixtures/no-color/multiline_annotation2.txt | 9 - .../fixtures/no-color/multiline_annotation3.toml | 18 - .../fixtures/no-color/multiline_annotation3.txt | 9 - .../fixtures/no-color/multiple_annotations.toml | 25 - .../fixtures/no-color/multiple_annotations.txt | 14 - .../tests/fixtures/no-color/simple.toml | 18 - .../tests/fixtures/no-color/simple.txt | 9 - .../annotate-snippets-0.8.0/tests/fixtures_test.rs | 45 - vendor/annotate-snippets-0.8.0/tests/formatter.rs | 552 --- .../annotate-snippets-0.8.0/tests/snippet/mod.rs | 167 - vendor/anyhow/.cargo-checksum.json | 2 +- vendor/anyhow/Cargo.toml | 2 +- vendor/anyhow/build.rs | 32 +- vendor/anyhow/src/backtrace.rs | 2 +- vendor/anyhow/src/context.rs | 25 +- vendor/anyhow/src/ensure.rs | 20 +- vendor/anyhow/src/error.rs | 40 +- vendor/anyhow/src/kind.rs | 4 +- vendor/anyhow/src/lib.rs | 6 +- vendor/anyhow/src/macros.rs | 32 +- vendor/anyhow/src/wrapper.rs | 13 +- vendor/anyhow/tests/test_ensure.rs | 2 +- vendor/anyhow/tests/ui/must-use.stderr | 2 +- vendor/anyhow/tests/ui/no-impl.stderr | 12 +- vendor/block-buffer-0.7.3/.cargo-checksum.json | 1 - vendor/block-buffer-0.7.3/Cargo.toml | 36 - vendor/block-buffer-0.7.3/LICENSE-APACHE | 201 - vendor/block-buffer-0.7.3/LICENSE-MIT | 25 - vendor/block-buffer-0.7.3/src/lib.rs | 210 - vendor/block-padding/.cargo-checksum.json | 1 - vendor/block-padding/Cargo.toml | 26 - vendor/block-padding/LICENSE-APACHE | 201 - vendor/block-padding/LICENSE-MIT | 25 - vendor/block-padding/src/lib.rs | 323 -- vendor/byte-tools/.cargo-checksum.json | 1 - vendor/byte-tools/Cargo.toml | 21 - vendor/byte-tools/LICENSE-APACHE | 201 - vendor/byte-tools/LICENSE-MIT | 25 - vendor/byte-tools/src/lib.rs | 29 - vendor/byteorder/.cargo-checksum.json | 1 - vendor/byteorder/CHANGELOG.md | 139 - vendor/byteorder/COPYING | 3 - vendor/byteorder/Cargo.toml | 43 - vendor/byteorder/LICENSE-MIT | 21 - vendor/byteorder/README.md | 63 - vendor/byteorder/UNLICENSE | 24 - vendor/byteorder/benches/bench.rs | 324 -- vendor/byteorder/rustfmt.toml | 2 - vendor/byteorder/src/io.rs | 1592 -------- vendor/byteorder/src/lib.rs | 4052 ------------------- vendor/camino/.cargo-checksum.json | 2 +- vendor/camino/CHANGELOG.md | 22 +- vendor/camino/Cargo.toml | 2 +- vendor/camino/build.rs | 27 +- vendor/camino/src/lib.rs | 137 + vendor/clap/.cargo-checksum.json | 2 +- vendor/clap/Cargo.lock | 159 +- vendor/clap/Cargo.toml | 36 +- vendor/clap/LICENSE-MIT | 2 +- vendor/clap/README.md | 146 +- vendor/clap/examples/README.md | 40 - vendor/clap/examples/cargo-example-derive.md | 2 - vendor/clap/examples/cargo-example-derive.rs | 4 +- vendor/clap/examples/cargo-example.md | 2 - vendor/clap/examples/cargo-example.rs | 2 - vendor/clap/examples/demo.md | 9 +- vendor/clap/examples/demo.rs | 2 - vendor/clap/examples/derive_ref/README.md | 440 --- vendor/clap/examples/derive_ref/augment_args.rs | 11 +- .../clap/examples/derive_ref/flatten_hand_args.rs | 8 +- vendor/clap/examples/escaped-positional-derive.md | 4 +- vendor/clap/examples/escaped-positional-derive.rs | 4 +- vendor/clap/examples/escaped-positional.md | 4 +- vendor/clap/examples/escaped-positional.rs | 9 +- vendor/clap/examples/git-derive.md | 4 +- vendor/clap/examples/git-derive.rs | 4 +- vendor/clap/examples/git.md | 2 - vendor/clap/examples/git.rs | 2 - vendor/clap/examples/multicall-busybox.md | 6 +- vendor/clap/examples/multicall-hostname.md | 6 +- vendor/clap/examples/pacman.md | 2 - vendor/clap/examples/pacman.rs | 5 +- vendor/clap/examples/tutorial_builder/01_quick.md | 37 + vendor/clap/examples/tutorial_builder/01_quick.rs | 4 +- .../examples/tutorial_builder/02_app_settings.md | 19 + .../examples/tutorial_builder/02_app_settings.rs | 4 +- vendor/clap/examples/tutorial_builder/02_apps.md | 19 + vendor/clap/examples/tutorial_builder/02_crate.md | 18 + vendor/clap/examples/tutorial_builder/02_crate.rs | 3 +- .../examples/tutorial_builder/03_01_flag_bool.md | 23 + .../examples/tutorial_builder/03_01_flag_bool.rs | 11 +- .../examples/tutorial_builder/03_01_flag_count.md | 23 + .../examples/tutorial_builder/03_01_flag_count.rs | 11 +- .../clap/examples/tutorial_builder/03_02_option.md | 32 + .../clap/examples/tutorial_builder/03_02_option.rs | 4 +- .../examples/tutorial_builder/03_03_positional.md | 22 + .../examples/tutorial_builder/03_03_positional.rs | 6 +- .../examples/tutorial_builder/03_04_subcommands.md | 64 + .../examples/tutorial_builder/03_04_subcommands.rs | 4 +- .../tutorial_builder/03_05_default_values.md | 22 + .../tutorial_builder/03_05_default_values.rs | 4 +- .../clap/examples/tutorial_builder/04_01_enum.md | 29 + .../clap/examples/tutorial_builder/04_01_enum.rs | 44 +- .../examples/tutorial_builder/04_01_possible.md | 29 + .../examples/tutorial_builder/04_01_possible.rs | 4 +- .../clap/examples/tutorial_builder/04_02_parse.md | 31 + .../clap/examples/tutorial_builder/04_02_parse.rs | 4 +- .../examples/tutorial_builder/04_02_validate.md | 31 + .../examples/tutorial_builder/04_02_validate.rs | 4 +- .../examples/tutorial_builder/04_03_relations.md | 58 + .../examples/tutorial_builder/04_03_relations.rs | 10 +- .../clap/examples/tutorial_builder/04_04_custom.md | 57 + .../clap/examples/tutorial_builder/04_04_custom.rs | 15 +- .../clap/examples/tutorial_builder/05_01_assert.rs | 15 +- vendor/clap/examples/tutorial_builder/README.md | 658 ---- vendor/clap/examples/tutorial_derive/01_quick.md | 37 + .../examples/tutorial_derive/02_app_settings.md | 19 + vendor/clap/examples/tutorial_derive/02_apps.md | 19 + vendor/clap/examples/tutorial_derive/02_crate.md | 18 + vendor/clap/examples/tutorial_derive/02_crate.rs | 2 +- .../examples/tutorial_derive/03_01_flag_bool.md | 23 + .../examples/tutorial_derive/03_01_flag_count.md | 23 + .../clap/examples/tutorial_derive/03_02_option.md | 32 + .../examples/tutorial_derive/03_03_positional.md | 22 + .../examples/tutorial_derive/03_04_subcommands.md | 64 + .../tutorial_derive/03_05_default_values.md | 22 + vendor/clap/examples/tutorial_derive/04_01_enum.md | 29 + vendor/clap/examples/tutorial_derive/04_01_enum.rs | 4 +- .../clap/examples/tutorial_derive/04_02_parse.md | 31 + .../examples/tutorial_derive/04_02_validate.md | 31 + .../examples/tutorial_derive/04_03_relations.md | 58 + .../examples/tutorial_derive/04_03_relations.rs | 2 +- .../clap/examples/tutorial_derive/04_04_custom.md | 57 + .../clap/examples/tutorial_derive/05_01_assert.rs | 2 +- vendor/clap/examples/tutorial_derive/README.md | 639 --- vendor/clap/examples/typed-derive.md | 4 +- vendor/clap/examples/typed-derive.rs | 4 +- vendor/clap/src/_cookbook/cargo_example.rs | 7 + vendor/clap/src/_cookbook/cargo_example_derive | 0 vendor/clap/src/_cookbook/cargo_example_derive.rs | 7 + vendor/clap/src/_cookbook/escaped_positional.rs | 7 + .../src/_cookbook/escaped_positional_derive.rs | 7 + vendor/clap/src/_cookbook/git.rs | 7 + vendor/clap/src/_cookbook/git_derive.rs | 7 + vendor/clap/src/_cookbook/mod.rs | 55 + vendor/clap/src/_cookbook/multicall_busybox.rs | 7 + vendor/clap/src/_cookbook/multicall_hostname.rs | 7 + vendor/clap/src/_cookbook/pacman.rs | 7 + vendor/clap/src/_cookbook/repl.rs | 5 + vendor/clap/src/_cookbook/typed_derive.rs | 7 + vendor/clap/src/_derive/_tutorial.rs | 205 + vendor/clap/src/_derive/mod.rs | 510 +++ vendor/clap/src/_faq.rs | 95 + vendor/clap/src/_features.rs | 27 + vendor/clap/src/_tutorial.rs | 204 + vendor/clap/src/builder/action.rs | 8 +- vendor/clap/src/builder/app_settings.rs | 32 +- vendor/clap/src/builder/arg.rs | 20 + vendor/clap/src/builder/arg_settings.rs | 27 +- vendor/clap/src/builder/command.rs | 106 +- vendor/clap/src/builder/value_parser.rs | 2 +- vendor/clap/src/derive.rs | 28 +- vendor/clap/src/error/kind.rs | 2 +- vendor/clap/src/error/mod.rs | 11 +- vendor/clap/src/lib.rs | 91 +- vendor/clap/src/macros.rs | 24 +- vendor/clap/src/output/usage.rs | 117 +- vendor/clap/src/parser/arg_matcher.rs | 4 +- vendor/clap/src/parser/error.rs | 11 + vendor/clap/src/parser/matches/arg_matches.rs | 74 +- vendor/clap/src/parser/parser.rs | 148 +- vendor/clap_derive/.cargo-checksum.json | 2 +- vendor/clap_derive/Cargo.toml | 5 +- vendor/clap_derive/LICENSE-MIT | 2 +- vendor/clap_derive/README.md | 4 +- vendor/clap_derive/src/attrs.rs | 159 +- vendor/clap_derive/src/derives/value_enum.rs | 2 +- vendor/clap_derive/src/parse.rs | 4 + vendor/compiler_builtins/.cargo-checksum.json | 2 +- vendor/compiler_builtins/Cargo.lock | 6 +- vendor/compiler_builtins/Cargo.toml | 3 +- vendor/compiler_builtins/build.rs | 10 +- vendor/compiler_builtins/libm/src/math/acosh.rs | 1 + vendor/compiler_builtins/libm/src/math/acoshf.rs | 1 + vendor/compiler_builtins/libm/src/math/asinh.rs | 1 + vendor/compiler_builtins/libm/src/math/asinhf.rs | 1 + vendor/compiler_builtins/libm/src/math/atanh.rs | 1 + vendor/compiler_builtins/libm/src/math/atanhf.rs | 1 + vendor/compiler_builtins/libm/src/math/copysign.rs | 1 + .../compiler_builtins/libm/src/math/copysignf.rs | 1 + vendor/compiler_builtins/libm/src/math/erf.rs | 1 + vendor/compiler_builtins/libm/src/math/erff.rs | 1 + vendor/compiler_builtins/libm/src/math/exp10.rs | 5 +- vendor/compiler_builtins/libm/src/math/exp10f.rs | 5 +- vendor/compiler_builtins/libm/src/math/fenv.rs | 6 - vendor/compiler_builtins/libm/src/math/fmaf.rs | 35 +- vendor/compiler_builtins/libm/src/math/ilogb.rs | 1 + vendor/compiler_builtins/libm/src/math/ilogbf.rs | 1 + vendor/compiler_builtins/libm/src/math/lgamma.rs | 1 + vendor/compiler_builtins/libm/src/math/lgamma_r.rs | 3 +- vendor/compiler_builtins/libm/src/math/lgammaf.rs | 1 + .../compiler_builtins/libm/src/math/lgammaf_r.rs | 3 +- .../libm/src/math/rem_pio2_large.rs | 2 +- vendor/compiler_builtins/libm/src/math/sincos.rs | 1 + vendor/compiler_builtins/libm/src/math/sincosf.rs | 1 + vendor/compiler_builtins/libm/src/math/tgamma.rs | 13 +- vendor/compiler_builtins/libm/src/math/tgammaf.rs | 1 + vendor/compiler_builtins/src/arm.rs | 4 + vendor/compiler_builtins/src/arm_linux.rs | 110 +- vendor/compiler_builtins/src/float/conv.rs | 8 +- vendor/compiler_builtins/src/lib.rs | 2 + vendor/compiler_builtins/src/macros.rs | 12 +- vendor/compiler_builtins/src/math.rs | 17 +- vendor/compiler_builtins/src/mem/impls.rs | 14 + vendor/compiler_builtins/src/mem/mod.rs | 11 +- vendor/compiler_builtins/src/mem/x86_64.rs | 150 +- vendor/crossbeam-channel/.cargo-checksum.json | 2 +- vendor/crossbeam-channel/CHANGELOG.md | 4 + vendor/crossbeam-channel/Cargo.lock | 10 +- vendor/crossbeam-channel/Cargo.toml | 4 +- vendor/crossbeam-channel/README.md | 4 +- vendor/crossbeam-channel/src/flavors/array.rs | 4 +- vendor/crossbeam-channel/src/flavors/list.rs | 18 +- vendor/crossbeam-channel/src/flavors/zero.rs | 10 +- vendor/crossbeam-channel/tests/array.rs | 6 +- vendor/crossbeam-channel/tests/golang.rs | 7 +- vendor/crossbeam-channel/tests/list.rs | 3 +- vendor/crossbeam-channel/tests/mpsc.rs | 15 +- vendor/crossbeam-channel/tests/select.rs | 1 - vendor/crossbeam-channel/tests/select_macro.rs | 1 - vendor/crossbeam-channel/tests/thread_locals.rs | 2 +- vendor/crossbeam-channel/tests/zero.rs | 8 +- vendor/crossbeam-deque/.cargo-checksum.json | 2 +- vendor/crossbeam-deque/CHANGELOG.md | 18 + vendor/crossbeam-deque/Cargo.toml | 26 +- vendor/crossbeam-deque/README.md | 4 +- vendor/crossbeam-deque/src/deque.rs | 76 +- vendor/crossbeam-deque/src/lib.rs | 1 + vendor/crossbeam-deque/tests/fifo.rs | 21 +- vendor/crossbeam-deque/tests/injector.rs | 28 +- vendor/crossbeam-deque/tests/lifo.rs | 23 +- vendor/crossbeam-epoch/.cargo-checksum.json | 2 +- vendor/crossbeam-epoch/CHANGELOG.md | 6 + vendor/crossbeam-epoch/Cargo.lock | 105 +- vendor/crossbeam-epoch/Cargo.toml | 4 +- vendor/crossbeam-epoch/README.md | 4 +- vendor/crossbeam-epoch/build.rs | 12 +- vendor/crossbeam-epoch/src/atomic.rs | 108 +- vendor/crossbeam-epoch/src/collector.rs | 6 +- vendor/crossbeam-epoch/src/deferred.rs | 19 +- vendor/crossbeam-epoch/src/guard.rs | 6 + vendor/crossbeam-epoch/src/internal.rs | 109 +- vendor/crossbeam-queue/.cargo-checksum.json | 1 - vendor/crossbeam-queue/CHANGELOG.md | 54 - vendor/crossbeam-queue/Cargo.toml | 51 - vendor/crossbeam-queue/LICENSE-APACHE | 201 - vendor/crossbeam-queue/LICENSE-MIT | 27 - vendor/crossbeam-queue/README.md | 54 - vendor/crossbeam-queue/build.rs | 41 - vendor/crossbeam-queue/no_atomic.rs | 73 - vendor/crossbeam-queue/src/array_queue.rs | 522 --- vendor/crossbeam-queue/src/lib.rs | 34 - vendor/crossbeam-queue/src/seg_queue.rs | 545 --- vendor/crossbeam-queue/tests/array_queue.rs | 359 -- vendor/crossbeam-queue/tests/seg_queue.rs | 190 - vendor/crossbeam-utils/.cargo-checksum.json | 2 +- vendor/crossbeam-utils/CHANGELOG.md | 4 + vendor/crossbeam-utils/Cargo.toml | 4 +- vendor/crossbeam-utils/README.md | 4 +- vendor/crossbeam-utils/build.rs | 7 +- vendor/crossbeam-utils/src/atomic/atomic_cell.rs | 17 +- vendor/crossbeam-utils/src/backoff.rs | 2 + vendor/crossbeam-utils/src/sync/parker.rs | 6 +- vendor/crossbeam-utils/tests/wait_group.rs | 5 +- vendor/crossbeam/.cargo-checksum.json | 1 - vendor/crossbeam/CHANGELOG.md | 93 - vendor/crossbeam/Cargo.toml | 59 - vendor/crossbeam/LICENSE-APACHE | 201 - vendor/crossbeam/LICENSE-MIT | 27 - vendor/crossbeam/README.md | 158 - vendor/crossbeam/no_atomic.rs | 59 - vendor/crossbeam/src/lib.rs | 96 - vendor/crossbeam/tests/subcrates.rs | 47 - vendor/digest-0.8.1/.cargo-checksum.json | 1 - vendor/digest-0.8.1/Cargo.toml | 36 - vendor/digest-0.8.1/LICENSE-APACHE | 201 - vendor/digest-0.8.1/LICENSE-MIT | 25 - vendor/digest-0.8.1/src/dev.rs | 218 -- vendor/digest-0.8.1/src/digest.rs | 86 - vendor/digest-0.8.1/src/dyn_digest.rs | 63 - vendor/digest-0.8.1/src/errors.rs | 20 - vendor/digest-0.8.1/src/lib.rs | 141 - vendor/either/.cargo-checksum.json | 2 +- vendor/either/Cargo.toml | 4 +- vendor/either/README.rst | 13 +- vendor/either/src/lib.rs | 71 + vendor/fake-simd/.cargo-checksum.json | 1 - vendor/fake-simd/Cargo.toml | 9 - vendor/fake-simd/LICENSE-APACHE | 201 - vendor/fake-simd/LICENSE-MIT | 26 - vendor/fake-simd/src/lib.rs | 108 - vendor/fortanix-sgx-abi/.cargo-checksum.json | 2 +- vendor/fortanix-sgx-abi/Cargo.toml | 36 +- vendor/fortanix-sgx-abi/src/lib.rs | 164 +- vendor/fs-err/.cargo-checksum.json | 2 +- vendor/fs-err/CHANGELOG.md | 19 +- vendor/fs-err/Cargo.toml | 45 +- vendor/fs-err/README.md | 2 +- vendor/fs-err/README.tpl | 28 - vendor/fs-err/src/dir.rs | 13 +- vendor/fs-err/src/errors.rs | 30 +- vendor/fs-err/src/file.rs | 76 +- vendor/fs-err/src/lib.rs | 43 +- vendor/fs-err/src/open_options.rs | 1 + vendor/fs-err/src/os/unix.rs | 6 +- vendor/fs-err/src/os/windows.rs | 4 +- vendor/fs-err/src/path.rs | 2 +- vendor/fs-err/tests/version-numbers.rs | 9 - vendor/generic-array-0.12.4/.cargo-checksum.json | 1 - vendor/generic-array-0.12.4/CHANGELOG.md | 51 - vendor/generic-array-0.12.4/Cargo.toml | 40 - vendor/generic-array-0.12.4/LICENSE | 21 - vendor/generic-array-0.12.4/README.md | 34 - vendor/generic-array-0.12.4/rustfmt.toml | 3 - vendor/generic-array-0.12.4/src/arr.rs | 126 - vendor/generic-array-0.12.4/src/functional.rs | 94 - vendor/generic-array-0.12.4/src/hex.rs | 102 - vendor/generic-array-0.12.4/src/impl_serde.rs | 108 - vendor/generic-array-0.12.4/src/impls.rs | 182 - vendor/generic-array-0.12.4/src/iter.rs | 190 - vendor/generic-array-0.12.4/src/lib.rs | 632 --- vendor/generic-array-0.12.4/src/sequence.rs | 320 -- vendor/generic-array-0.12.4/tests/arr.rs | 27 - vendor/generic-array-0.12.4/tests/generics.rs | 98 - vendor/generic-array-0.12.4/tests/hex.rs | 61 - vendor/generic-array-0.12.4/tests/import_name.rs | 10 - vendor/generic-array-0.12.4/tests/iter.rs | 164 - vendor/generic-array-0.12.4/tests/mod.rs | 287 -- vendor/getrandom/.cargo-checksum.json | 2 +- vendor/getrandom/CHANGELOG.md | 18 +- vendor/getrandom/Cargo.toml | 38 +- vendor/getrandom/src/bsd_arandom.rs | 1 + vendor/getrandom/src/dragonfly.rs | 1 + vendor/getrandom/src/error.rs | 4 - vendor/getrandom/src/lib.rs | 2 +- vendor/getrandom/src/linux_android.rs | 1 + vendor/getrandom/src/macos.rs | 1 + vendor/getrandom/src/openbsd.rs | 1 + vendor/getrandom/src/solaris_illumos.rs | 1 + vendor/getrandom/src/util_libc.rs | 57 +- vendor/getrandom/src/wasi.rs | 12 +- vendor/getrandom/src/windows.rs | 1 + vendor/gimli/.cargo-checksum.json | 2 +- vendor/gimli/CHANGELOG.md | 22 + vendor/gimli/Cargo.lock | 37 +- vendor/gimli/Cargo.toml | 79 +- vendor/gimli/README.md | 6 +- vendor/gimli/examples/dwarf-validate.rs | 2 +- vendor/gimli/examples/dwarfdump.rs | 45 +- vendor/gimli/examples/simple.rs | 2 +- vendor/gimli/examples/simple_line.rs | 13 +- vendor/gimli/fixtures/self/README.md | 2 +- vendor/gimli/src/constants.rs | 2 +- vendor/gimli/src/lib.rs | 2 +- vendor/gimli/src/read/abbrev.rs | 2 +- vendor/gimli/src/read/aranges.rs | 2 +- vendor/gimli/src/read/cfi.rs | 134 +- vendor/gimli/src/read/line.rs | 2 +- vendor/gimli/src/read/lists.rs | 1 + vendor/gimli/src/read/loclists.rs | 4 +- vendor/gimli/src/read/mod.rs | 2 +- vendor/gimli/src/read/op.rs | 21 +- vendor/gimli/src/read/pubnames.rs | 2 +- vendor/gimli/src/read/pubtypes.rs | 2 +- vendor/gimli/src/read/rnglists.rs | 4 +- vendor/gimli/src/read/str.rs | 4 +- vendor/gimli/src/read/unit.rs | 4 +- vendor/gimli/src/read/util.rs | 2 +- vendor/gimli/src/read/value.rs | 2 - vendor/gimli/src/write/cfi.rs | 15 +- vendor/gimli/src/write/op.rs | 6 +- vendor/gimli/tests/convert_self.rs | 2 +- vendor/handlebars/.cargo-checksum.json | 2 +- vendor/handlebars/CHANGELOG.md | 75 + vendor/handlebars/Cargo.lock | 1384 ++----- vendor/handlebars/Cargo.toml | 89 +- vendor/handlebars/README.md | 26 +- vendor/handlebars/examples/dev_mode.rs | 24 +- vendor/handlebars/examples/error.rs | 52 +- vendor/handlebars/examples/helper_macro.rs | 63 + vendor/handlebars/examples/partials.rs | 19 +- vendor/handlebars/examples/script.rs | 7 - vendor/handlebars/release.toml | 2 + vendor/handlebars/src/context.rs | 19 +- vendor/handlebars/src/decorators/mod.rs | 12 +- vendor/handlebars/src/error.rs | 98 +- vendor/handlebars/src/grammar.pest | 27 +- vendor/handlebars/src/grammar.rs | 29 +- vendor/handlebars/src/helpers/helper_each.rs | 94 +- vendor/handlebars/src/helpers/helper_if.rs | 40 +- vendor/handlebars/src/helpers/helper_lookup.rs | 12 +- vendor/handlebars/src/helpers/helper_with.rs | 15 +- vendor/handlebars/src/helpers/mod.rs | 3 +- vendor/handlebars/src/helpers/scripting.rs | 14 +- vendor/handlebars/src/json/path.rs | 4 +- vendor/handlebars/src/lib.rs | 21 +- vendor/handlebars/src/macros.rs | 7 +- vendor/handlebars/src/output.rs | 6 + vendor/handlebars/src/partial.rs | 363 +- vendor/handlebars/src/registry.rs | 272 +- vendor/handlebars/src/render.rs | 93 +- vendor/handlebars/src/support.rs | 58 + vendor/handlebars/src/template.rs | 233 +- vendor/handlebars/tests/embed.rs | 29 + vendor/handlebars/tests/escape.rs | 42 +- vendor/handlebars/tests/helper_macro.rs | 13 + vendor/handlebars/tests/helper_with_space.rs | 54 + vendor/handlebars/tests/templates/hello.hbs | 1 + vendor/handlebars/tests/whitespace.rs | 24 + vendor/hermit-abi/.cargo-checksum.json | 2 +- vendor/hermit-abi/Cargo.toml | 31 +- vendor/hermit-abi/src/errno.rs | 397 ++ vendor/hermit-abi/src/lib.rs | 74 +- vendor/itoa/.cargo-checksum.json | 2 +- vendor/itoa/Cargo.toml | 8 +- vendor/itoa/README.md | 2 +- vendor/itoa/src/lib.rs | 4 +- vendor/lazycell/.cargo-checksum.json | 1 + vendor/lazycell/CHANGELOG.md | 197 + vendor/lazycell/Cargo.toml | 34 + vendor/lazycell/LICENSE-APACHE | 201 + vendor/lazycell/LICENSE-MIT | 26 + vendor/lazycell/README.md | 73 + vendor/lazycell/src/lib.rs | 680 ++++ vendor/lazycell/src/serde_impl.rs | 86 + vendor/libc/.cargo-checksum.json | 2 +- vendor/libc/CONTRIBUTING.md | 4 + vendor/libc/Cargo.toml | 2 +- vendor/libc/README.md | 8 +- vendor/libc/build.rs | 15 +- vendor/libc/src/fuchsia/mod.rs | 11 + vendor/libc/src/lib.rs | 10 +- vendor/libc/src/macros.rs | 16 - .../libc/src/unix/bsd/apple/b64/aarch64/align.rs | 1 + vendor/libc/src/unix/bsd/apple/mod.rs | 59 +- .../libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs | 69 + .../libc/src/unix/bsd/freebsdlike/freebsd/mod.rs | 103 +- vendor/libc/src/unix/bsd/freebsdlike/mod.rs | 42 + vendor/libc/src/unix/bsd/mod.rs | 6 + vendor/libc/src/unix/bsd/netbsdlike/mod.rs | 11 - vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs | 160 +- vendor/libc/src/unix/bsd/netbsdlike/openbsd/mod.rs | 11 + vendor/libc/src/unix/haiku/mod.rs | 92 +- vendor/libc/src/unix/linux_like/android/b64/mod.rs | 3 + .../unix/linux_like/android/b64/riscv64/align.rs | 7 + .../src/unix/linux_like/android/b64/riscv64/mod.rs | 342 ++ .../src/unix/linux_like/android/b64/x86_64/mod.rs | 2 + vendor/libc/src/unix/linux_like/android/mod.rs | 212 + vendor/libc/src/unix/linux_like/emscripten/mod.rs | 2 + .../unix/linux_like/linux/gnu/b64/aarch64/align.rs | 22 + .../unix/linux_like/linux/gnu/b64/aarch64/mod.rs | 16 + .../unix/linux_like/linux/gnu/b64/x86_64/align.rs | 17 + .../unix/linux_like/linux/gnu/b64/x86_64/mod.rs | 13 + vendor/libc/src/unix/linux_like/linux/gnu/mod.rs | 8 + vendor/libc/src/unix/linux_like/linux/mod.rs | 14 + .../linux_like/linux/musl/b64/aarch64/align.rs | 15 + .../src/unix/linux_like/linux/musl/b64/mips64.rs | 2 +- .../src/unix/linux_like/linux/musl/b64/s390x.rs | 1 + .../unix/linux_like/linux/musl/b64/x86_64/align.rs | 18 + vendor/libc/src/unix/linux_like/linux/musl/mod.rs | 2 + .../libc/src/unix/linux_like/linux/uclibc/mod.rs | 2 + vendor/libc/src/unix/linux_like/mod.rs | 13 +- vendor/libc/src/unix/mod.rs | 16 +- vendor/libc/src/unix/newlib/espidf/mod.rs | 5 + vendor/libc/src/unix/solarish/mod.rs | 2 + vendor/libc/src/windows/mod.rs | 12 +- vendor/lsp-types/.cargo-checksum.json | 2 +- vendor/lsp-types/CHANGELOG.md | 6 + vendor/lsp-types/Cargo.toml | 3 +- vendor/lsp-types/README.md | 2 +- vendor/lsp-types/src/lib.rs | 5 +- vendor/lsp-types/src/semantic_tokens.rs | 32 +- vendor/memmap2/.cargo-checksum.json | 2 +- vendor/memmap2/CHANGELOG.md | 22 +- vendor/memmap2/Cargo.lock | 2 +- vendor/memmap2/Cargo.toml | 3 +- vendor/memmap2/src/lib.rs | 149 +- vendor/memmap2/src/unix.rs | 42 +- vendor/memmap2/src/windows.rs | 43 +- vendor/minifier/.cargo-checksum.json | 2 +- vendor/minifier/Cargo.lock | 2 +- vendor/minifier/Cargo.toml | 2 +- vendor/minifier/src/css/token.rs | 51 +- vendor/once_cell/.cargo-checksum.json | 2 +- vendor/once_cell/CHANGELOG.md | 5 + vendor/once_cell/Cargo.lock | 164 +- vendor/once_cell/Cargo.toml | 4 +- vendor/once_cell/src/imp_std.rs | 93 +- vendor/opaque-debug/.cargo-checksum.json | 1 - vendor/opaque-debug/Cargo.toml | 22 - vendor/opaque-debug/LICENSE-APACHE | 201 - vendor/opaque-debug/LICENSE-MIT | 25 - vendor/opaque-debug/src/lib.rs | 24 - vendor/pest/.cargo-checksum.json | 2 +- vendor/pest/Cargo.lock | 80 +- vendor/pest/Cargo.toml | 45 +- vendor/pest/_README.md | 23 +- vendor/pest/examples/parens.rs | 4 +- vendor/pest/src/error.rs | 172 +- vendor/pest/src/iterators/flat_pairs.rs | 9 +- vendor/pest/src/iterators/pair.rs | 22 +- vendor/pest/src/iterators/pairs.rs | 19 +- vendor/pest/src/iterators/tokens.rs | 14 +- vendor/pest/src/lib.rs | 20 +- vendor/pest/src/macros.rs | 114 +- vendor/pest/src/parser.rs | 6 +- vendor/pest/src/parser_state.rs | 132 +- vendor/pest/src/position.rs | 81 +- vendor/pest/src/prec_climber.rs | 171 +- vendor/pest/src/span.rs | 189 +- vendor/pest/src/stack.rs | 4 +- vendor/pest/src/token.rs | 2 +- vendor/pest/src/unicode/binary.rs | 3210 ++++++++++------ vendor/pest/src/unicode/category.rs | 2175 ++++++----- vendor/pest/src/unicode/mod.rs | 2 + vendor/pest/tests/calculator.rs | 18 +- vendor/pest/tests/json.rs | 75 +- vendor/pest_derive/.cargo-checksum.json | 2 +- vendor/pest_derive/Cargo.toml | 40 +- vendor/pest_derive/_README.md | 37 +- vendor/pest_derive/src/lib.rs | 7 +- vendor/pest_derive/tests/grammar.pest | 4 + vendor/pest_derive/tests/grammar.rs | 31 + vendor/pest_derive/tests/grammar_inline.rs | 4 + vendor/pest_derive/tests/lists.rs | 4 + vendor/pest_derive/tests/reporting.rs | 4 + vendor/pest_generator/.cargo-checksum.json | 2 +- vendor/pest_generator/Cargo.toml | 34 +- vendor/pest_generator/_README.md | 23 +- vendor/pest_generator/src/generator.rs | 72 +- vendor/pest_generator/src/macros.rs | 14 +- vendor/pest_meta/.cargo-checksum.json | 2 +- vendor/pest_meta/Cargo.toml | 46 +- vendor/pest_meta/_README.md | 23 +- vendor/pest_meta/src/ast.rs | 2 +- vendor/pest_meta/src/grammar.pest | 2 +- vendor/pest_meta/src/grammar.rs | 2 +- vendor/pest_meta/src/lib.rs | 20 +- vendor/pest_meta/src/optimizer/concatenator.rs | 39 +- vendor/pest_meta/src/optimizer/factorizer.rs | 61 +- vendor/pest_meta/src/optimizer/lister.rs | 42 + vendor/pest_meta/src/optimizer/mod.rs | 104 +- vendor/pest_meta/src/optimizer/restorer.rs | 14 +- vendor/pest_meta/src/optimizer/rotater.rs | 13 +- vendor/pest_meta/src/optimizer/skipper.rs | 39 +- vendor/pest_meta/src/optimizer/unroller.rs | 107 +- vendor/pest_meta/src/parser.rs | 93 +- vendor/pest_meta/src/validator.rs | 222 +- .../pretty_assertions-0.7.2/.cargo-checksum.json | 1 - vendor/pretty_assertions-0.7.2/CHANGELOG.md | 38 - vendor/pretty_assertions-0.7.2/Cargo.lock | 102 - vendor/pretty_assertions-0.7.2/Cargo.toml | 36 - vendor/pretty_assertions-0.7.2/LICENSE-APACHE | 202 - vendor/pretty_assertions-0.7.2/LICENSE-MIT | 21 - vendor/pretty_assertions-0.7.2/README.md | 91 - .../examples/pretty_assertion.png | Bin 21419 -> 0 bytes .../examples/pretty_assertion.rs | 3 - .../examples/pretty_assertion_v0_6_1.png | Bin 21236 -> 0 bytes .../examples/standard_assertion.png | Bin 21727 -> 0 bytes .../examples/standard_assertion.rs | 21 - vendor/pretty_assertions-0.7.2/scripts/check | 9 - vendor/pretty_assertions-0.7.2/scripts/install | 6 - vendor/pretty_assertions-0.7.2/scripts/publish | 11 - vendor/pretty_assertions-0.7.2/src/lib.rs | 475 --- vendor/pretty_assertions-0.7.2/src/printer.rs | 474 --- vendor/pretty_assertions/.cargo-checksum.json | 1 + vendor/pretty_assertions/CHANGELOG.md | 38 + vendor/pretty_assertions/Cargo.lock | 102 + vendor/pretty_assertions/Cargo.toml | 36 + vendor/pretty_assertions/LICENSE-APACHE | 202 + vendor/pretty_assertions/LICENSE-MIT | 21 + vendor/pretty_assertions/README.md | 91 + .../examples/pretty_assertion.png | Bin 0 -> 21419 bytes .../pretty_assertions/examples/pretty_assertion.rs | 3 + .../examples/pretty_assertion_v0_6_1.png | Bin 0 -> 21236 bytes .../examples/standard_assertion.png | Bin 0 -> 21727 bytes .../examples/standard_assertion.rs | 21 + vendor/pretty_assertions/scripts/check | 9 + vendor/pretty_assertions/scripts/install | 6 + vendor/pretty_assertions/scripts/publish | 11 + vendor/pretty_assertions/src/lib.rs | 475 +++ vendor/pretty_assertions/src/printer.rs | 474 +++ vendor/proc-macro2/.cargo-checksum.json | 2 +- vendor/proc-macro2/Cargo.toml | 12 +- vendor/proc-macro2/src/detection.rs | 2 +- vendor/proc-macro2/src/fallback.rs | 169 +- vendor/proc-macro2/src/lib.rs | 40 +- vendor/proc-macro2/src/marker.rs | 4 +- vendor/proc-macro2/src/parse.rs | 64 +- vendor/proc-macro2/src/rcvec.rs | 142 + vendor/proc-macro2/src/wrapper.rs | 14 +- vendor/proc-macro2/tests/comments.rs | 2 + vendor/proc-macro2/tests/test.rs | 9 +- vendor/quick-error-1.2.3/.cargo-checksum.json | 1 - vendor/quick-error-1.2.3/Cargo.lock | 6 - vendor/quick-error-1.2.3/Cargo.toml | 23 - vendor/quick-error-1.2.3/LICENSE-APACHE | 202 - vendor/quick-error-1.2.3/LICENSE-MIT | 19 - vendor/quick-error-1.2.3/README.rst | 66 - vendor/quick-error-1.2.3/bulk.yaml | 8 - vendor/quick-error-1.2.3/examples/context.rs | 48 - vendor/quick-error-1.2.3/src/lib.rs | 1262 ------ vendor/quick-error-1.2.3/vagga.yaml | 36 - vendor/quick-error/.cargo-checksum.json | 2 +- vendor/quick-error/Cargo.lock | 3 +- vendor/quick-error/Cargo.toml | 3 +- vendor/quick-error/README.rst | 6 +- vendor/quick-error/examples/context.rs | 21 +- vendor/quick-error/src/lib.rs | 292 +- vendor/quick-error/vagga.yaml | 6 +- vendor/quote/.cargo-checksum.json | 2 +- vendor/quote/Cargo.toml | 7 +- vendor/quote/src/ext.rs | 4 +- vendor/quote/src/ident_fragment.rs | 2 +- vendor/quote/src/lib.rs | 2 +- vendor/quote/src/runtime.rs | 10 +- vendor/quote/src/to_tokens.rs | 6 +- .../ui/does-not-have-iter-interpolated-dup.stderr | 2 +- .../ui/does-not-have-iter-interpolated.stderr | 2 +- .../tests/ui/does-not-have-iter-separated.stderr | 2 +- vendor/quote/tests/ui/does-not-have-iter.stderr | 2 +- vendor/quote/tests/ui/not-repeatable.stderr | 76 +- vendor/redox_syscall/.cargo-checksum.json | 2 +- vendor/redox_syscall/Cargo.toml | 2 +- vendor/redox_syscall/src/arch/x86.rs | 105 + vendor/redox_syscall/src/io/mod.rs | 4 +- vendor/redox_syscall/src/lib.rs | 2 +- vendor/regex-syntax/.cargo-checksum.json | 2 +- vendor/regex-syntax/Cargo.toml | 2 +- vendor/regex-syntax/src/ast/mod.rs | 6 +- vendor/regex-syntax/src/ast/parse.rs | 144 +- vendor/regex-syntax/src/ast/visitor.rs | 12 +- vendor/regex-syntax/src/error.rs | 4 +- vendor/regex-syntax/src/hir/interval.rs | 4 +- vendor/regex-syntax/src/hir/literal/mod.rs | 28 +- vendor/regex-syntax/src/hir/mod.rs | 18 +- vendor/regex-syntax/src/hir/translate.rs | 20 +- vendor/regex-syntax/src/lib.rs | 2 +- vendor/regex-syntax/src/parser.rs | 2 +- vendor/regex-syntax/src/unicode.rs | 7 +- vendor/regex-syntax/src/unicode_tables/age.rs | 198 +- .../src/unicode_tables/case_folding_simple.rs | 98 +- .../src/unicode_tables/general_category.rs | 747 ++-- .../src/unicode_tables/grapheme_cluster_break.rs | 49 +- .../src/unicode_tables/perl_decimal.rs | 11 +- .../regex-syntax/src/unicode_tables/perl_space.rs | 6 +- .../regex-syntax/src/unicode_tables/perl_word.rs | 128 +- .../src/unicode_tables/property_bool.rs | 1128 ++++-- .../src/unicode_tables/property_names.rs | 6 +- .../src/unicode_tables/property_values.rs | 26 +- vendor/regex-syntax/src/unicode_tables/script.rs | 222 +- .../src/unicode_tables/script_extension.rs | 229 +- .../src/unicode_tables/sentence_break.rs | 182 +- .../regex-syntax/src/unicode_tables/word_break.rs | 134 +- vendor/regex-syntax/src/utf8.rs | 6 +- vendor/regex/.cargo-checksum.json | 2 +- vendor/regex/CHANGELOG.md | 21 + vendor/regex/Cargo.lock | 18 +- vendor/regex/Cargo.toml | 4 +- vendor/regex/src/backtrack.rs | 12 +- vendor/regex/src/compile.rs | 57 +- vendor/regex/src/dfa.rs | 38 +- vendor/regex/src/exec.rs | 14 +- vendor/regex/src/expand.rs | 8 +- vendor/regex/src/input.rs | 4 +- vendor/regex/src/lib.rs | 1 - vendor/regex/src/literal/imp.rs | 4 +- vendor/regex/src/pattern.rs | 2 +- vendor/regex/src/pikevm.rs | 2 +- vendor/regex/src/prog.rs | 2 +- vendor/regex/src/re_bytes.rs | 12 +- vendor/regex/src/re_set.rs | 44 +- vendor/regex/src/re_trait.rs | 13 +- vendor/regex/src/re_unicode.rs | 24 +- vendor/regex/src/utf8.rs | 2 +- vendor/regex/tests/unicode.rs | 17 + vendor/rustc_tools_util/.cargo-checksum.json | 1 - vendor/rustc_tools_util/Cargo.toml | 25 - vendor/rustc_tools_util/README.md | 62 - vendor/rustc_tools_util/src/lib.rs | 158 - vendor/ryu/.cargo-checksum.json | 2 +- vendor/ryu/Cargo.lock | 54 +- vendor/ryu/Cargo.toml | 8 +- vendor/ryu/README.md | 2 +- vendor/ryu/src/lib.rs | 4 +- vendor/semver/.cargo-checksum.json | 2 +- vendor/semver/Cargo.toml | 7 +- vendor/semver/build.rs | 2 +- vendor/semver/src/lib.rs | 2 +- vendor/serde/.cargo-checksum.json | 2 +- vendor/serde/Cargo.toml | 10 +- vendor/serde/src/de/mod.rs | 14 +- vendor/serde/src/lib.rs | 9 +- vendor/serde/src/ser/mod.rs | 8 +- vendor/serde_derive/.cargo-checksum.json | 2 +- vendor/serde_derive/Cargo.toml | 5 +- vendor/serde_derive/src/lib.rs | 2 +- vendor/serde_json/.cargo-checksum.json | 2 +- vendor/serde_json/Cargo.toml | 11 +- vendor/serde_json/src/lib.rs | 3 +- vendor/serde_json/src/number.rs | 35 +- vendor/serde_json/src/value/mod.rs | 22 +- vendor/serde_json/tests/debug.rs | 43 +- vendor/serde_json/tests/regression/issue795.rs | 2 + vendor/serde_json/tests/stream.rs | 1 + vendor/serde_json/tests/test.rs | 1 + vendor/serde_json/tests/ui/missing_colon.stderr | 2 +- vendor/serde_json/tests/ui/missing_value.stderr | 2 +- vendor/serde_repr/.cargo-checksum.json | 2 +- vendor/serde_repr/Cargo.toml | 11 +- vendor/serde_repr/README.md | 2 +- vendor/serde_repr/src/lib.rs | 2 +- vendor/serde_repr/tests/test.rs | 1 + vendor/sha-1-0.8.2/.cargo-checksum.json | 1 - vendor/sha-1-0.8.2/Cargo.lock | 148 - vendor/sha-1-0.8.2/Cargo.toml | 58 - vendor/sha-1-0.8.2/LICENSE-APACHE | 201 - vendor/sha-1-0.8.2/LICENSE-MIT | 27 - vendor/sha-1-0.8.2/benches/lib.rs | 7 - vendor/sha-1-0.8.2/examples/sha1sum.rs | 49 - vendor/sha-1-0.8.2/src/aarch64.rs | 9 - vendor/sha-1-0.8.2/src/consts.rs | 19 - vendor/sha-1-0.8.2/src/lib.rs | 141 - vendor/sha-1-0.8.2/src/utils.rs | 300 -- vendor/sha-1-0.8.2/tests/data/one_million_a.bin | 1 - vendor/sha-1-0.8.2/tests/data/sha1.blb | 1 - vendor/sha-1-0.8.2/tests/lib.rs | 14 - vendor/syn/.cargo-checksum.json | 2 +- vendor/syn/Cargo.toml | 11 +- vendor/syn/benches/file.rs | 34 +- vendor/syn/src/buffer.rs | 102 +- vendor/syn/src/lib.rs | 4 +- vendor/syn/tests/common/eq.rs | 47 +- vendor/syn/tests/test_derive_input.rs | 2 +- vendor/syn/tests/test_stmt.rs | 2 +- vendor/thin-vec/.cargo-checksum.json | 1 + vendor/thin-vec/Cargo.toml | 33 + vendor/thin-vec/README.md | 9 + vendor/thin-vec/src/lib.rs | 3117 +++++++++++++++ vendor/thiserror-impl/.cargo-checksum.json | 2 +- vendor/thiserror-impl/Cargo.toml | 4 +- vendor/thiserror-impl/src/expand.rs | 108 +- vendor/thiserror-impl/src/generics.rs | 1 + vendor/thiserror-impl/src/lib.rs | 5 +- vendor/thiserror-impl/src/valid.rs | 6 +- vendor/thiserror/.cargo-checksum.json | 2 +- vendor/thiserror/Cargo.toml | 12 +- vendor/thiserror/README.md | 2 +- vendor/thiserror/src/lib.rs | 5 +- vendor/thiserror/tests/compiletest.rs | 3 +- vendor/thiserror/tests/test_backtrace.rs | 41 +- vendor/thiserror/tests/test_display.rs | 2 - vendor/thiserror/tests/test_error.rs | 1 - vendor/thiserror/tests/test_expr.rs | 3 +- vendor/thiserror/tests/test_from.rs | 2 - vendor/thiserror/tests/test_generics.rs | 2 +- vendor/thiserror/tests/test_option.rs | 6 +- vendor/thiserror/tests/test_path.rs | 2 - vendor/thiserror/tests/test_source.rs | 2 - vendor/thiserror/tests/test_transparent.rs | 2 - vendor/thiserror/tests/ui/concat-display.stderr | 2 +- .../thiserror/tests/ui/from-backtrace-backtrace.rs | 10 + .../tests/ui/from-backtrace-backtrace.stderr | 5 + vendor/thiserror/tests/ui/no-display.stderr | 12 +- .../tests/ui/source-enum-not-error.stderr | 44 +- .../tests/ui/source-struct-not-error.stderr | 42 +- vendor/tracing-core/.cargo-checksum.json | 2 +- vendor/tracing-core/CHANGELOG.md | 23 + vendor/tracing-core/Cargo.toml | 6 +- vendor/tracing-core/README.md | 26 +- vendor/tracing-core/src/callsite.rs | 9 + vendor/tracing-core/src/dispatcher.rs | 15 +- vendor/tracing-core/src/field.rs | 44 + vendor/tracing-core/src/metadata.rs | 89 +- vendor/tracing-subscriber/.cargo-checksum.json | 2 +- vendor/tracing-subscriber/CHANGELOG.md | 13 + vendor/tracing-subscriber/Cargo.toml | 2 +- vendor/tracing-subscriber/README.md | 2 +- vendor/tracing-subscriber/src/lib.rs | 2 +- vendor/tracing-subscriber/src/reload.rs | 12 +- vendor/tracing-subscriber/tests/reload.rs | 32 +- vendor/tracing/.cargo-checksum.json | 2 +- vendor/tracing/CHANGELOG.md | 30 + vendor/tracing/Cargo.toml | 48 +- vendor/tracing/README.md | 10 +- vendor/tracing/benches/baseline.rs | 24 + vendor/tracing/benches/dispatch_get_clone.rs | 15 + vendor/tracing/benches/dispatch_get_ref.rs | 16 + vendor/tracing/benches/empty_span.rs | 43 + vendor/tracing/benches/enter_span.rs | 16 + vendor/tracing/benches/event.rs | 12 + vendor/tracing/benches/global_subscriber.rs | 136 - vendor/tracing/benches/no_subscriber.rs | 101 - vendor/tracing/benches/shared.rs | 160 + vendor/tracing/benches/span_fields.rs | 23 + vendor/tracing/benches/span_no_fields.rs | 13 + vendor/tracing/benches/span_repeated.rs | 20 + vendor/tracing/benches/subscriber.rs | 189 - vendor/tracing/src/lib.rs | 6 +- vendor/tracing/src/span.rs | 18 +- vendor/tracing/src/subscriber.rs | 17 +- vendor/tracing/tests/event.rs | 24 + .../.cargo-checksum.json | 1 - .../CODE_OF_CONDUCT.md | 49 - .../CONTRIBUTING.md | 8 - .../wasi-0.10.2+wasi-snapshot-preview1/Cargo.toml | 43 - .../LICENSE-APACHE | 201 - .../LICENSE-Apache-2.0_WITH_LLVM-exception | 220 -- .../wasi-0.10.2+wasi-snapshot-preview1/LICENSE-MIT | 23 - .../ORG_CODE_OF_CONDUCT.md | 143 - .../wasi-0.10.2+wasi-snapshot-preview1/README.md | 94 - .../wasi-0.10.2+wasi-snapshot-preview1/SECURITY.md | 29 - .../src/error.rs | 52 - .../wasi-0.10.2+wasi-snapshot-preview1/src/lib.rs | 48 - .../src/lib_generated.rs | 1940 ---------- version | 2 +- x.py | 30 +- 6829 files changed, 156072 insertions(+), 106101 deletions(-) create mode 100644 compiler/rustc_ast_lowering/src/errors.rs create mode 100644 compiler/rustc_ast_passes/src/errors.rs create mode 100644 compiler/rustc_attr/src/session_diagnostics.rs create mode 100644 compiler/rustc_codegen_cranelift/build_system/abi_checker.rs create mode 100644 compiler/rustc_codegen_cranelift/build_system/tests.rs create mode 100644 compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch delete mode 100755 compiler/rustc_codegen_cranelift/scripts/tests.sh create mode 100644 compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs create mode 100644 compiler/rustc_codegen_cranelift/src/global_asm.rs delete mode 100644 compiler/rustc_data_structures/src/thin_vec.rs delete mode 100644 compiler/rustc_data_structures/src/thin_vec/tests.rs create mode 100644 compiler/rustc_driver/src/session_diagnostics.rs create mode 100644 compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/ast_passes.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/attr.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/driver.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/infer.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/interface.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/metadata.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/middle.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/monomorphize.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/query_system.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/save_analysis.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/session.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/trait_selection.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/ty_utils.ftl create mode 100644 compiler/rustc_errors/src/translation.rs create mode 100644 compiler/rustc_expand/src/errors.rs create mode 100644 compiler/rustc_hir/src/errors.rs create mode 100644 compiler/rustc_infer/src/errors/mod.rs create mode 100644 compiler/rustc_infer/src/errors/note_and_explain.rs create mode 100644 compiler/rustc_interface/src/errors.rs create mode 100644 compiler/rustc_lint/src/errors.rs create mode 100644 compiler/rustc_lint/src/let_underscore.rs create mode 100644 compiler/rustc_metadata/src/errors.rs create mode 100644 compiler/rustc_middle/src/error.rs create mode 100644 compiler/rustc_middle/src/ty/layout_sanity_check.rs create mode 100644 compiler/rustc_middle/src/values.rs create mode 100644 compiler/rustc_mir_dataflow/src/errors.rs create mode 100644 compiler/rustc_monomorphize/src/errors.rs create mode 100644 compiler/rustc_plugin_impl/src/errors.rs delete mode 100644 compiler/rustc_query_impl/src/values.rs create mode 100644 compiler/rustc_query_system/src/error.rs create mode 100644 compiler/rustc_query_system/src/values.rs create mode 100644 compiler/rustc_save_analysis/src/errors.rs create mode 100644 compiler/rustc_session/src/config/sigpipe.rs create mode 100644 compiler/rustc_session/src/errors.rs create mode 100644 compiler/rustc_symbol_mangling/src/errors.rs delete mode 100644 compiler/rustc_target/src/abi/call/nvptx.rs create mode 100644 compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs create mode 100644 compiler/rustc_target/src/spec/armv4t_none_eabi.rs create mode 100644 compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs create mode 100644 compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs create mode 100644 compiler/rustc_trait_selection/src/errors.rs create mode 100644 compiler/rustc_trait_selection/src/traits/outlives_bounds.rs create mode 100644 compiler/rustc_ty_utils/src/errors.rs create mode 100644 compiler/rustc_ty_utils/src/implied_bounds.rs delete mode 100644 compiler/rustc_typeck/src/check/regionck.rs delete mode 100644 compiler/rustc_typeck/src/outlives/outlives_bounds.rs delete mode 100644 debian/libstd-rust-1.64.install delete mode 100644 debian/libstd-rust-1.64.lintian-overrides create mode 100644 debian/libstd-rust-1.65.install create mode 100644 debian/libstd-rust-1.65.lintian-overrides delete mode 100644 debian/patches/u-arm-compiler-builtins-add-sync-builtin-fallbacks.patch create mode 100644 debian/patches/u-fix-backtrace-tests.patch delete mode 100644 debian/patches/u-ignore-bpf-test.patch create mode 100644 debian/patches/u-make-compiletest-work-without-rpath.patch delete mode 100644 debian/patches/ubuntu-Revert-Use-constant-eval-to-do-strict-validity-check.patch create mode 100644 library/core/src/error.md create mode 100644 library/core/src/error.rs create mode 100644 library/core/src/iter/adapters/array_chunks.rs create mode 100644 library/core/tests/iter/adapters/array_chunks.rs create mode 100644 library/core/tests/iter/adapters/by_ref_sized.rs delete mode 100644 library/panic_unwind/src/dwarf/eh.rs delete mode 100644 library/panic_unwind/src/dwarf/mod.rs delete mode 100644 library/panic_unwind/src/dwarf/tests.rs delete mode 100644 library/std/src/net/addr.rs delete mode 100644 library/std/src/net/addr/tests.rs create mode 100644 library/std/src/net/display_buffer.rs delete mode 100644 library/std/src/net/ip.rs delete mode 100644 library/std/src/net/ip/tests.rs create mode 100644 library/std/src/net/ip_addr.rs create mode 100644 library/std/src/net/ip_addr/tests.rs create mode 100644 library/std/src/net/socket_addr.rs create mode 100644 library/std/src/net/socket_addr/tests.rs create mode 100644 library/std/src/os/android/net.rs create mode 100644 library/std/src/os/linux/net.rs create mode 100644 library/std/src/os/net/mod.rs create mode 100644 library/std/src/os/net/tcp.rs create mode 100644 library/std/src/os/net/tests.rs create mode 100644 library/std/src/personality.rs create mode 100644 library/std/src/personality/dwarf/eh.rs create mode 100644 library/std/src/personality/dwarf/mod.rs create mode 100644 library/std/src/personality/dwarf/tests.rs create mode 100644 library/std/src/personality/emcc.rs create mode 100644 library/std/src/personality/gcc.rs delete mode 100644 library/std/src/sys/hermit/condvar.rs create mode 100644 library/std/src/sys/hermit/futex.rs delete mode 100644 library/std/src/sys/hermit/mutex.rs delete mode 100644 library/std/src/sys/hermit/rwlock.rs delete mode 100644 library/std/src/sys/unix/thread_parker.rs create mode 100644 library/std/src/sys/unix/thread_parker/mod.rs create mode 100644 library/std/src/sys/unix/thread_parker/netbsd.rs create mode 100644 library/std/src/sys/unix/thread_parker/pthread.rs delete mode 100644 library/stdarch/crates/core_arch/build.rs create mode 100644 src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in create mode 100644 src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt delete mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-12-stage1/Dockerfile delete mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile create mode 100644 src/ci/docker/static/gitconfig delete mode 100644 src/doc/book/2018-edition/src/theme/2018-edition.css delete mode 100644 src/doc/book/2018-edition/src/theme/index.hbs create mode 100644 src/doc/rust-by-example/src/meta/playground.md delete mode 100644 src/doc/rust-by-example/src/meta/playpen.md create mode 100644 src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md create mode 100644 src/doc/rustc/src/platform-support/armv4t-none-eabi.md create mode 100644 src/doc/unstable-book/src/language-features/unix-sigpipe.md delete mode 100644 src/etc/check_missing_items.py create mode 100644 src/librustdoc/json/import_finder.rs create mode 100644 src/test/assembly/x86_64-floating-point-clamp.rs delete mode 100644 src/test/codegen/atomic-operations-llvm-12.rs create mode 100644 src/test/codegen/instrument-coverage.rs create mode 100644 src/test/codegen/intrinsics/mask.rs create mode 100644 src/test/codegen/issue-85872-multiple-reverse.rs create mode 100644 src/test/codegen/issue-96274.rs create mode 100644 src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs create mode 100644 src/test/codegen/layout-size-checks.rs create mode 100644 src/test/codegen/mir-inlined-line-numbers.rs create mode 100644 src/test/codegen/some-abis-do-extend-params-to-32-bits.rs create mode 100644 src/test/codegen/try_question_mark_nop.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-no-attr.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-with-attr-flag.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-with-attr.rs create mode 100644 src/test/incremental/issue-100521-change-struct-name-assocty.rs delete mode 100644 src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir delete mode 100644 src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir create mode 100644 src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir delete mode 100644 src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff delete mode 100644 src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff create mode 100644 src/test/mir-opt/combine_array_len.norm2.InstCombine.diff delete mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff delete mode 100644 src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff delete mode 100644 src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff create mode 100644 src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff create mode 100644 src/test/mir-opt/inline/polymorphic-recursion.rs create mode 100644 src/test/mir-opt/issue-101867.rs create mode 100644 src/test/mir-opt/issue-101973.rs create mode 100644 src/test/mir-opt/issue-91633.rs create mode 100644 src/test/mir-opt/issue_101867.main.mir_map.0.mir create mode 100644 src/test/mir-opt/issue_101973.inner.ConstProp.diff delete mode 100644 src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir delete mode 100644 src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir create mode 100644 src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir delete mode 100644 src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/issue_72181.bar.mir_map.0.mir delete mode 100644 src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/issue_72181.foo.mir_map.0.mir delete mode 100644 src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/issue_72181.main.mir_map.0.mir delete mode 100644 src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff delete mode 100644 src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff delete mode 100644 src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff delete mode 100644 src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff create mode 100644 src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff create mode 100644 src/test/mir-opt/issue_91633.bar.mir_map.0.mir create mode 100644 src/test/mir-opt/issue_91633.foo.mir_map.0.mir create mode 100644 src/test/mir-opt/issue_91633.fun.mir_map.0.mir create mode 100644 src/test/mir-opt/issue_91633.hey.mir_map.0.mir delete mode 100644 src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.rs create mode 100644 src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff delete mode 100644 src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir delete mode 100644 src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir create mode 100644 src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_intrinsics_e2e.rs delete mode 100644 src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff delete mode 100644 src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff create mode 100644 src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff create mode 100644 src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir delete mode 100644 src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff delete mode 100644 src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff create mode 100644 src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff create mode 100644 src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff create mode 100644 src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff delete mode 100644 src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir delete mode 100644 src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir create mode 100644 src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir delete mode 100644 src/test/mir-opt/separate_const_switch.identity.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir delete mode 100644 src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/simple_match.match_bool.mir_map.0.mir delete mode 100644 src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff delete mode 100644 src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff delete mode 100644 src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff delete mode 100644 src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff delete mode 100644 src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff delete mode 100644 src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff delete mode 100644 src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff delete mode 100644 src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff create mode 100644 src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/simplify_try.rs delete mode 100644 src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir delete mode 100644 src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir create mode 100644 src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir create mode 100644 src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir create mode 100644 src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir create mode 100644 src/test/mir-opt/try_identity_e2e.rs delete mode 100644 src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir delete mode 100644 src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir delete mode 100644 src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir delete mode 100644 src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir create mode 100644 src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir delete mode 100644 src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir delete mode 100644 src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir create mode 100644 src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff create mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir create mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/Makefile create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/bad.c create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs create mode 100644 src/test/run-make/issue-85401-static-mir/Makefile create mode 100644 src/test/run-make/issue-85401-static-mir/bar.rs create mode 100644 src/test/run-make/issue-85401-static-mir/baz.rs create mode 100644 src/test/run-make/issue-85401-static-mir/foo.rs create mode 100644 src/test/run-make/raw-dylib-import-name-type/Makefile create mode 100644 src/test/run-make/raw-dylib-import-name-type/driver.rs create mode 100644 src/test/run-make/raw-dylib-import-name-type/extern.c create mode 100644 src/test/run-make/raw-dylib-import-name-type/extern.gnu.def create mode 100644 src/test/run-make/raw-dylib-import-name-type/extern.msvc.def create mode 100644 src/test/run-make/raw-dylib-import-name-type/output.txt create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/Makefile create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/driver.rs create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/extern_1.c create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/extern_2.c create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/lib.rs create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/lib_wrapper.rs create mode 100644 src/test/run-make/raw-dylib-inline-cross-dylib/output.txt create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs-2/Makefile create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs-2/main.rs create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs-2/native_dep.rs create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs-2/rust_dep.rs create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/Makefile create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/main.rs create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/native_dep_1.c create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/native_dep_2.c create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/native_dep_3.c create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/rust_dep_local.rs create mode 100644 src/test/run-make/rlib-format-packed-bundled-libs/rust_dep_up.rs create mode 100644 src/test/run-make/track-pgo-dep-info/Makefile create mode 100644 src/test/run-make/track-pgo-dep-info/main.rs delete mode 100644 src/test/run-make/translation/basic-translation.ftl delete mode 100644 src/test/run-make/translation/basic-translation.rs create mode 100644 src/test/run-make/translation/broken.ftl create mode 100644 src/test/run-make/translation/missing.ftl create mode 100644 src/test/run-make/translation/test.rs create mode 100644 src/test/run-make/translation/working.ftl create mode 100644 src/test/rustdoc-gui/codeblock-tooltip.goml create mode 100644 src/test/rustdoc-gui/docblock-table.goml create mode 100644 src/test/rustdoc-gui/item-info-alignment.goml create mode 100644 src/test/rustdoc-gui/links-color.goml create mode 100644 src/test/rustdoc-gui/search-form-elements.goml delete mode 100644 src/test/rustdoc-gui/search-input.goml create mode 100644 src/test/rustdoc-gui/sidebar-mobile-scroll.goml create mode 100644 src/test/rustdoc-gui/where-whitespace.goml create mode 100644 src/test/rustdoc-json/enums/discriminant/basic.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/expr.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/limits.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs create mode 100644 src/test/rustdoc-json/enums/field_hidden.rs create mode 100644 src/test/rustdoc-json/enums/kind.rs create mode 100644 src/test/rustdoc-json/enums/struct_field_hidden.rs create mode 100644 src/test/rustdoc-json/enums/tuple_fields_hidden.rs create mode 100644 src/test/rustdoc-json/fns/async_return.rs create mode 100644 src/test/rustdoc-json/impls/auto.rs create mode 100644 src/test/rustdoc-json/impls/auxiliary/foreign_struct.rs create mode 100644 src/test/rustdoc-json/impls/auxiliary/foreign_trait.rs create mode 100644 src/test/rustdoc-json/impls/foreign_for_local.rs create mode 100644 src/test/rustdoc-json/impls/import_from_private.rs create mode 100644 src/test/rustdoc-json/impls/local_for_foreign.rs create mode 100644 src/test/rustdoc-json/impls/local_for_local.rs create mode 100644 src/test/rustdoc-json/impls/local_for_local_primitive.rs create mode 100644 src/test/rustdoc-json/impls/local_for_primitive.rs create mode 100644 src/test/rustdoc-json/intra-doc-links/non_page.rs create mode 100644 src/test/rustdoc-json/intra-doc-links/user_written.rs create mode 100644 src/test/rustdoc-json/reexport/export_extern_crate_as_self.rs create mode 100644 src/test/rustdoc-json/reexport/glob_collision.rs create mode 100644 src/test/rustdoc-json/reexport/glob_empty_mod.rs create mode 100644 src/test/rustdoc-json/reexport/mod_not_included.rs create mode 100644 src/test/rustdoc-json/structs/plain_all_pub.rs create mode 100644 src/test/rustdoc-json/structs/plain_doc_hidden.rs create mode 100644 src/test/rustdoc-json/structs/plain_pub_priv.rs create mode 100644 src/test/rustdoc-json/structs/tuple_empty.rs create mode 100644 src/test/rustdoc-json/structs/tuple_pub_priv.rs create mode 100644 src/test/rustdoc-json/traits/uses_extern_trait.rs create mode 100644 src/test/rustdoc-json/type/extern.rs create mode 100644 src/test/rustdoc-json/type/hrtb.rs create mode 100644 src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.rs create mode 100644 src/test/rustdoc-ui/feature-gate-rustdoc_missing_doc_code_examples.stderr create mode 100644 src/test/rustdoc-ui/issue-101076.rs create mode 100644 src/test/rustdoc/auxiliary/incoherent-impl-types.rs create mode 100644 src/test/rustdoc/cfg_doc_reexport.rs create mode 100644 src/test/rustdoc/doc_auto_cfg_nested_impl.rs create mode 100644 src/test/rustdoc/empty-impl-block-private-with-doc.rs create mode 100644 src/test/rustdoc/empty-impl-block-private.rs create mode 100644 src/test/rustdoc/glob-shadowing-const.rs create mode 100644 src/test/rustdoc/glob-shadowing.rs create mode 100644 src/test/rustdoc/impossible-default.rs create mode 100644 src/test/rustdoc/intra-doc/assoc-reexport-super.rs create mode 100644 src/test/rustdoc/issue-100620.rs create mode 100644 src/test/rustdoc/issue-100679-sidebar-links-deref.rs create mode 100644 src/test/rustdoc/issue-101743-bold-tag.rs create mode 100644 src/test/rustdoc/issue-41783.codeblock.html create mode 100644 src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs create mode 100644 src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs create mode 100644 src/test/rustdoc/primitive-reference.rs create mode 100644 src/test/rustdoc/rustc-incoherent-impls.rs create mode 100644 src/test/ui-fulldeps/fluent-messages/duplicate-a-b.ftl delete mode 100644 src/test/ui-fulldeps/fluent-messages/duplicate-b.ftl create mode 100644 src/test/ui-fulldeps/fluent-messages/label-with-hyphens.ftl create mode 100644 src/test/ui-fulldeps/fluent-messages/missing-crate-name.ftl create mode 100644 src/test/ui-fulldeps/fluent-messages/slug-with-hyphens.ftl delete mode 100644 src/test/ui-fulldeps/issue-15778-pass.rs delete mode 100644 src/test/ui-fulldeps/issue-15778-pass.stderr create mode 100644 src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs create mode 100644 src/test/ui/argument-suggestions/issue-100478.rs create mode 100644 src/test/ui/argument-suggestions/issue-100478.stderr create mode 100644 src/test/ui/argument-suggestions/issue-101097.rs create mode 100644 src/test/ui/argument-suggestions/issue-101097.stderr create mode 100644 src/test/ui/argument-suggestions/too-long.rs create mode 100644 src/test/ui/argument-suggestions/too-long.stderr create mode 100644 src/test/ui/argument-suggestions/two-mismatch-notes.rs create mode 100644 src/test/ui/argument-suggestions/two-mismatch-notes.stderr create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.fixed create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.rs create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.stderr create mode 100644 src/test/ui/asm/unpretty-expanded.rs create mode 100644 src/test/ui/asm/unpretty-expanded.stdout create mode 100644 src/test/ui/associated-consts/issue-102335-const.rs create mode 100644 src/test/ui/associated-consts/issue-102335-const.stderr create mode 100644 src/test/ui/associated-type-bounds/issue-102335-ty.rs create mode 100644 src/test/ui/associated-type-bounds/issue-102335-ty.stderr delete mode 100644 src/test/ui/associated-types/higher-ranked-projection.badbase.stderr delete mode 100644 src/test/ui/associated-types/higher-ranked-projection.badnll.stderr create mode 100644 src/test/ui/async-await/async-await-let-else.drop-tracking.stderr create mode 100644 src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr delete mode 100644 src/test/ui/async-await/async-await-let-else.stderr create mode 100644 src/test/ui/async-await/issue-101715.rs create mode 100644 src/test/ui/async-await/issue-101715.stderr create mode 100644 src/test/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr create mode 100644 src/test/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr delete mode 100644 src/test/ui/async-await/issue-64130-4-async-move.stderr create mode 100644 src/test/ui/async-await/issue-68112.drop_tracking.stderr create mode 100644 src/test/ui/async-await/issue-68112.no_drop_tracking.stderr delete mode 100644 src/test/ui/async-await/issue-68112.stderr create mode 100644 src/test/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr delete mode 100644 src/test/ui/async-await/issue-70935-complex-spans.normal.stderr create mode 100644 src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr delete mode 100644 src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr create mode 100644 src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr create mode 100644 src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr delete mode 100644 src/test/ui/async-await/partial-drop-partial-reinit.stderr create mode 100644 src/test/ui/attributes/collapse-debuginfo-invalid.rs create mode 100644 src/test/ui/attributes/collapse-debuginfo-invalid.stderr create mode 100644 src/test/ui/attributes/issue-100631.rs create mode 100644 src/test/ui/attributes/issue-100631.stderr delete mode 100644 src/test/ui/attributes/register-attr-tool-fail.rs delete mode 100644 src/test/ui/attributes/register-attr-tool-fail.stderr delete mode 100644 src/test/ui/attributes/register-attr-tool-import.rs delete mode 100644 src/test/ui/attributes/register-attr-tool-import.stderr delete mode 100644 src/test/ui/attributes/register-attr-tool-prelude.rs delete mode 100644 src/test/ui/attributes/register-attr-tool-prelude.stderr delete mode 100644 src/test/ui/attributes/register-attr-tool-unused.rs delete mode 100644 src/test/ui/attributes/register-attr-tool-unused.stderr delete mode 100644 src/test/ui/attributes/register-attr-tool.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-only-feature.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs create mode 100644 src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr create mode 100644 src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs create mode 100644 src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr create mode 100644 src/test/ui/borrowck/issue-101119.rs create mode 100644 src/test/ui/borrowck/issue-101119.stderr create mode 100644 src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs create mode 100644 src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr create mode 100644 src/test/ui/btreemap/btreemap-index-mut.rs create mode 100644 src/test/ui/btreemap/btreemap-index-mut.stderr create mode 100644 src/test/ui/check-cfg/allow-at-crate-level.rs create mode 100644 src/test/ui/closures/binder/disallow-const.rs create mode 100644 src/test/ui/closures/binder/disallow-const.stderr create mode 100644 src/test/ui/closures/binder/disallow-ty.rs create mode 100644 src/test/ui/closures/binder/disallow-ty.stderr create mode 100644 src/test/ui/codegen/issue-101585-128bit-repeat.rs create mode 100644 src/test/ui/codegen/issue-99551.rs create mode 100644 src/test/ui/coercion/issue-101066.rs create mode 100644 src/test/ui/coherence/auxiliary/trait-with-const-param.rs delete mode 100644 src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr create mode 100644 src/test/ui/coherence/coherence-negative-outlives-lifetimes.stock.stderr create mode 100644 src/test/ui/coherence/const-generics-orphan-check-ok.rs create mode 100644 src/test/ui/coherence/issue-100191-2.rs create mode 100644 src/test/ui/coherence/issue-100191-2.stderr create mode 100644 src/test/ui/coherence/issue-100191.rs create mode 100644 src/test/ui/coherence/issue-100191.stderr create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-100217.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-100360.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-73298.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-82268.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-83972.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-84669.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-86710.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/issue-89851.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/obligation-cause.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/obligation-cause.stderr create mode 100644 src/test/ui/const-generics/issue-103243.rs create mode 100644 src/test/ui/const-generics/issues/issue-100313.rs create mode 100644 src/test/ui/const-generics/issues/issue-100313.stderr create mode 100644 src/test/ui/consts/const_in_pattern/incomplete-slice.rs create mode 100644 src/test/ui/consts/const_in_pattern/incomplete-slice.stderr create mode 100644 src/test/ui/consts/extra-const-ub/detect-extra-ub.rs create mode 100644 src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr create mode 100644 src/test/ui/consts/extra-const-ub/issue-100771.rs create mode 100644 src/test/ui/consts/extra-const-ub/issue-101034.rs create mode 100644 src/test/ui/consts/unnormalized-param-env.rs create mode 100644 src/test/ui/deriving/issue-103157.rs create mode 100644 src/test/ui/deriving/issue-103157.stderr create mode 100644 src/test/ui/drop/drop-foreign-fundamental.rs create mode 100644 src/test/ui/drop/drop-foreign-fundamental.stderr create mode 100644 src/test/ui/drop/drop_order.rs create mode 100644 src/test/ui/dyn-star/const.rs create mode 100644 src/test/ui/dyn-star/drop.rs create mode 100644 src/test/ui/dyn-star/drop.run.stdout create mode 100644 src/test/ui/dyn-star/error.rs create mode 100644 src/test/ui/dyn-star/error.stderr create mode 100644 src/test/ui/dyn-star/feature-gate-dyn_star.rs create mode 100644 src/test/ui/dyn-star/feature-gate-dyn_star.stderr create mode 100644 src/test/ui/dyn-star/make-dyn-star.rs create mode 100644 src/test/ui/dyn-star/method.rs create mode 100644 src/test/ui/dyn-star/syntax.rs create mode 100644 src/test/ui/feature-gates/feature-gate-collapse_debuginfo.rs create mode 100644 src/test/ui/feature-gates/feature-gate-collapse_debuginfo.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-label_break_value.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-label_break_value.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-let_else.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-let_else.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs create mode 100644 src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-register_attr.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-register_attr.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs create mode 100644 src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-unix_sigpipe.rs create mode 100644 src/test/ui/feature-gates/feature-gate-unix_sigpipe.stderr create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr delete mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr create mode 100644 src/test/ui/generator/clone-impl-async.rs create mode 100644 src/test/ui/generator/clone-impl-async.stderr create mode 100644 src/test/ui/generator/clone-impl-static.rs create mode 100644 src/test/ui/generator/clone-impl-static.stderr create mode 100644 src/test/ui/generator/clone-impl.rs create mode 100644 src/test/ui/generator/clone-impl.stderr create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-2.stderr create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs create mode 100644 src/test/ui/generic-associated-types/bugs/hrtb-implied-3.stderr delete mode 100644 src/test/ui/generic-associated-types/bugs/issue-87748.rs delete mode 100644 src/test/ui/generic-associated-types/bugs/issue-87748.stderr create mode 100644 src/test/ui/generic-associated-types/bugs/issue-91762.rs create mode 100644 src/test/ui/generic-associated-types/bugs/issue-91762.stderr delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.rs delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.stderr delete mode 100644 src/test/ui/generic-associated-types/gat-incomplete-warning.rs create mode 100644 src/test/ui/generic-associated-types/issue-101020.rs create mode 100644 src/test/ui/generic-associated-types/issue-101020.stderr create mode 100644 src/test/ui/generic-associated-types/issue-102333.rs create mode 100644 src/test/ui/generic-associated-types/issue-102335-gat.rs create mode 100644 src/test/ui/generic-associated-types/issue-102335-gat.stderr delete mode 100644 src/test/ui/generic-associated-types/issue-67424.stderr create mode 100644 src/test/ui/generic-associated-types/issue-87748.rs delete mode 100644 src/test/ui/generic-associated-types/issue-91762.rs delete mode 100644 src/test/ui/generic-associated-types/issue-91762.stderr create mode 100644 src/test/ui/generic-associated-types/type-param-defaults.rs create mode 100644 src/test/ui/generic-associated-types/type-param-defaults.stderr create mode 100644 src/test/ui/hashmap/hashmap-index-mut.rs create mode 100644 src/test/ui/hashmap/hashmap-index-mut.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/complex.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/due-to-where-clause.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/due-to-where-clause.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-30786.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-30786.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-46989.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-46989.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-57639.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-58451.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-58451.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-88446.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-90177.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-95034.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-95034.stderr create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-95230.rs delete mode 100644 src/test/ui/hrtb/complex.rs delete mode 100644 src/test/ui/hrtb/due-to-where-clause.rs delete mode 100644 src/test/ui/hrtb/due-to-where-clause.stderr delete mode 100644 src/test/ui/hrtb/hrtb-cache-issue-54302.rs delete mode 100644 src/test/ui/hrtb/hrtb-cache-issue-54302.stderr delete mode 100644 src/test/ui/hrtb/hrtb-conflate-regions.rs delete mode 100644 src/test/ui/hrtb/hrtb-conflate-regions.stderr delete mode 100644 src/test/ui/hrtb/hrtb-debruijn-in-receiver.rs delete mode 100644 src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-fn.rs delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-fn.stderr delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr delete mode 100644 src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.rs delete mode 100644 src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr delete mode 100644 src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs delete mode 100644 src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr delete mode 100644 src/test/ui/hrtb/hrtb-identity-fn-borrows.rs delete mode 100644 src/test/ui/hrtb/hrtb-identity-fn-borrows.stderr delete mode 100644 src/test/ui/hrtb/hrtb-just-for-static.rs delete mode 100644 src/test/ui/hrtb/hrtb-just-for-static.stderr delete mode 100644 src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr delete mode 100644 src/test/ui/hrtb/hrtb-perfect-forwarding.rs delete mode 100644 src/test/ui/hrtb/hrtb-perfect-forwarding.stderr delete mode 100644 src/test/ui/hrtb/issue-30786.rs delete mode 100644 src/test/ui/hrtb/issue-30786.stderr delete mode 100644 src/test/ui/hrtb/issue-46989.rs delete mode 100644 src/test/ui/hrtb/issue-46989.stderr delete mode 100644 src/test/ui/hrtb/issue-57639.rs delete mode 100644 src/test/ui/hrtb/issue-58451.rs delete mode 100644 src/test/ui/hrtb/issue-58451.stderr delete mode 100644 src/test/ui/hrtb/issue-62203-hrtb-ice.rs delete mode 100644 src/test/ui/hrtb/issue-62203-hrtb-ice.stderr delete mode 100644 src/test/ui/hrtb/issue-88446.rs delete mode 100644 src/test/ui/hrtb/issue-90177.rs delete mode 100644 src/test/ui/hrtb/issue-95034.rs delete mode 100644 src/test/ui/hrtb/issue-95034.stderr delete mode 100644 src/test/ui/hrtb/issue-95230.rs create mode 100644 src/test/ui/impl-trait/in-trait/deep-match-works.rs create mode 100644 src/test/ui/impl-trait/in-trait/deep-match.rs create mode 100644 src/test/ui/impl-trait/in-trait/deep-match.stderr create mode 100644 src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs create mode 100644 src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr create mode 100644 src/test/ui/impl-trait/in-trait/encode.rs create mode 100644 src/test/ui/impl-trait/in-trait/nested-rpitit.rs create mode 100644 src/test/ui/impl-trait/in-trait/object-safety.rs create mode 100644 src/test/ui/impl-trait/in-trait/object-safety.stderr create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl.rs create mode 100644 src/test/ui/impl-trait/in-trait/reveal.rs create mode 100644 src/test/ui/impl-trait/in-trait/success.rs create mode 100644 src/test/ui/impl-trait/in-trait/wf-bounds.rs create mode 100644 src/test/ui/impl-trait/in-trait/wf-bounds.stderr create mode 100644 src/test/ui/impl-trait/issue-100075-2.rs create mode 100644 src/test/ui/impl-trait/issue-100075-2.stderr create mode 100644 src/test/ui/impl-trait/issue-100075.rs create mode 100644 src/test/ui/impl-trait/issue-100075.stderr create mode 100644 src/test/ui/impl-trait/issue-103599.rs create mode 100644 src/test/ui/impl-trait/issue-103599.stderr create mode 100644 src/test/ui/impl-trait/issue-99914.rs create mode 100644 src/test/ui/impl-trait/issue-99914.stderr create mode 100644 src/test/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs create mode 100644 src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs create mode 100644 src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr create mode 100644 src/test/ui/implied-bounds/impl-header-unnormalized-types.rs create mode 100644 src/test/ui/implied-bounds/impl-header-unnormalized-types.stderr create mode 100644 src/test/ui/implied-bounds/issue-100690.rs create mode 100644 src/test/ui/implied-bounds/issue-100690.stderr create mode 100644 src/test/ui/implied-bounds/issue-101951.rs create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace-std.rs create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace.rs create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr delete mode 100644 src/test/ui/issues/issue-100550-normalization-ice-exposed-by-mir-inlining.rs create mode 100644 src/test/ui/issues/issue-100605.rs create mode 100644 src/test/ui/issues/issue-100605.stderr delete mode 100644 src/test/ui/issues/issue-15524.rs delete mode 100644 src/test/ui/issues/issue-15524.stderr create mode 100644 src/test/ui/issues/issue-99875.rs create mode 100644 src/test/ui/issues/issue-99875.stderr delete mode 100644 src/test/ui/json-and-color.rs delete mode 100644 src/test/ui/json-and-color.stderr delete mode 100644 src/test/ui/json-and-error-format.rs delete mode 100644 src/test/ui/json-and-error-format.stderr delete mode 100644 src/test/ui/json-bom-plus-crlf-multifile-aux.rs delete mode 100644 src/test/ui/json-bom-plus-crlf-multifile.rs delete mode 100644 src/test/ui/json-bom-plus-crlf-multifile.stderr delete mode 100644 src/test/ui/json-bom-plus-crlf.rs delete mode 100644 src/test/ui/json-bom-plus-crlf.stderr delete mode 100644 src/test/ui/json-invalid.rs delete mode 100644 src/test/ui/json-invalid.stderr delete mode 100644 src/test/ui/json-multiple.polonius.stderr delete mode 100644 src/test/ui/json-multiple.rs delete mode 100644 src/test/ui/json-multiple.stderr delete mode 100644 src/test/ui/json-options.polonius.stderr delete mode 100644 src/test/ui/json-options.rs delete mode 100644 src/test/ui/json-options.stderr delete mode 100644 src/test/ui/json-short.rs delete mode 100644 src/test/ui/json-short.stderr create mode 100644 src/test/ui/json/json-and-color.rs create mode 100644 src/test/ui/json/json-and-color.stderr create mode 100644 src/test/ui/json/json-and-error-format.rs create mode 100644 src/test/ui/json/json-and-error-format.stderr create mode 100644 src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs create mode 100644 src/test/ui/json/json-bom-plus-crlf-multifile.rs create mode 100644 src/test/ui/json/json-bom-plus-crlf-multifile.stderr create mode 100644 src/test/ui/json/json-bom-plus-crlf.rs create mode 100644 src/test/ui/json/json-bom-plus-crlf.stderr create mode 100644 src/test/ui/json/json-invalid.rs create mode 100644 src/test/ui/json/json-invalid.stderr create mode 100644 src/test/ui/json/json-multiple.polonius.stderr create mode 100644 src/test/ui/json/json-multiple.rs create mode 100644 src/test/ui/json/json-multiple.stderr create mode 100644 src/test/ui/json/json-options.polonius.stderr create mode 100644 src/test/ui/json/json-options.rs create mode 100644 src/test/ui/json/json-options.stderr create mode 100644 src/test/ui/json/json-short.rs create mode 100644 src/test/ui/json/json-short.stderr create mode 100644 src/test/ui/let-else/const-fn.rs create mode 100644 src/test/ui/let-else/issue-100103.rs create mode 100644 src/test/ui/let-else/issue-102317.rs create mode 100644 src/test/ui/let-else/issue-94176.rs create mode 100644 src/test/ui/let-else/issue-94176.stderr create mode 100644 src/test/ui/let-else/issue-99975.rs create mode 100644 src/test/ui/let-else/let-else-drop-order.rs create mode 100644 src/test/ui/let-else/let-else-drop-order.run.stdout create mode 100644 src/test/ui/let-else/let-else-then-diverge.rs create mode 100644 src/test/ui/let-else/let-else-then-diverge.stderr create mode 100644 src/test/ui/let-else/let-else.rs create mode 100644 src/test/ui/lifetimes/fullwidth-ampersand.rs create mode 100644 src/test/ui/lifetimes/fullwidth-ampersand.stderr create mode 100644 src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs create mode 100644 src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr create mode 100644 src/test/ui/lint/issue-101284.rs create mode 100644 src/test/ui/lint/let_underscore/let_underscore_drop.rs create mode 100644 src/test/ui/lint/let_underscore/let_underscore_drop.stderr create mode 100644 src/test/ui/lint/let_underscore/let_underscore_lock.rs create mode 100644 src/test/ui/lint/let_underscore/let_underscore_lock.stderr create mode 100644 src/test/ui/lint/lint-attr-everywhere-early.rs create mode 100644 src/test/ui/lint/lint-attr-everywhere-early.stderr create mode 100644 src/test/ui/lint/lint-attr-everywhere-late.rs create mode 100644 src/test/ui/lint/lint-attr-everywhere-late.stderr create mode 100644 src/test/ui/lint/must_not_suspend/ref-drop-tracking.rs create mode 100644 src/test/ui/lint/must_not_suspend/ref-drop-tracking.stderr create mode 100644 src/test/ui/lint/must_not_suspend/ref.drop_tracking.stderr create mode 100644 src/test/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr delete mode 100644 src/test/ui/lint/must_not_suspend/ref.stderr create mode 100644 src/test/ui/lint/unused_parens_multibyte_recovery.rs create mode 100644 src/test/ui/lint/unused_parens_multibyte_recovery.stderr create mode 100644 src/test/ui/lowering/issue-96847.rs delete mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nllleak.stderr delete mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nllnoleak.stderr create mode 100644 src/test/ui/macros/auxiliary/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.stderr delete mode 100644 src/test/ui/mir/issue-100476-recursion-check-blewup.rs create mode 100644 src/test/ui/mir/issue-101844.rs create mode 100644 src/test/ui/mir/issue-102389.rs create mode 100644 src/test/ui/mir/issue-102389.stderr create mode 100644 src/test/ui/mir/issue-99852.rs create mode 100644 src/test/ui/mir/issue-99866.rs create mode 100644 src/test/ui/mir/mir-inlining/ice-issue-100550-unnormalized-projection.rs create mode 100644 src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs create mode 100644 src/test/ui/mismatched_types/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.stderr create mode 100644 src/test/ui/mismatched_types/dont-point-return-on-E0308.rs create mode 100644 src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr create mode 100644 src/test/ui/mismatched_types/normalize-fn-sig.rs create mode 100644 src/test/ui/mismatched_types/normalize-fn-sig.stderr create mode 100644 src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed create mode 100644 src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs create mode 100644 src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr create mode 100644 src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.fixed create mode 100644 src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.rs create mode 100644 src/test/ui/mismatched_types/suggest-boxed-trait-objects-instead-of-impl-trait.stderr create mode 100644 src/test/ui/modules/auxiliary/dummy_lib.rs create mode 100644 src/test/ui/modules/special_module_name.rs create mode 100644 src/test/ui/modules/special_module_name.stderr create mode 100644 src/test/ui/modules/special_module_name_ignore.rs delete mode 100644 src/test/ui/on-unimplemented/enclosing-scope.rs delete mode 100644 src/test/ui/on-unimplemented/enclosing-scope.stderr create mode 100644 src/test/ui/on-unimplemented/parent-label.rs create mode 100644 src/test/ui/on-unimplemented/parent-label.stderr create mode 100644 src/test/ui/or-patterns/inner-or-pat.or3.stderr create mode 100644 src/test/ui/or-patterns/inner-or-pat.or4.stderr create mode 100644 src/test/ui/or-patterns/inner-or-pat.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr create mode 100644 src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-before-array.rs create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr create mode 100644 src/test/ui/parser/fn-defined-using-def.rs create mode 100644 src/test/ui/parser/fn-defined-using-def.stderr create mode 100644 src/test/ui/parser/fn-defined-using-fun.rs create mode 100644 src/test/ui/parser/fn-defined-using-fun.stderr create mode 100644 src/test/ui/parser/fn-defined-using-func.rs create mode 100644 src/test/ui/parser/fn-defined-using-func.stderr create mode 100644 src/test/ui/parser/fn-defined-using-function.rs create mode 100644 src/test/ui/parser/fn-defined-using-function.stderr create mode 100644 src/test/ui/parser/issue-100197-mut-let.fixed create mode 100644 src/test/ui/parser/issue-100197-mut-let.rs create mode 100644 src/test/ui/parser/issue-100197-mut-let.stderr create mode 100644 src/test/ui/parser/issue-101477-enum.fixed create mode 100644 src/test/ui/parser/issue-101477-enum.rs create mode 100644 src/test/ui/parser/issue-101477-enum.stderr create mode 100644 src/test/ui/parser/issue-101477-let.fixed create mode 100644 src/test/ui/parser/issue-101477-let.rs create mode 100644 src/test/ui/parser/issue-101477-let.stderr create mode 100644 src/test/ui/parser/issue-99910-const-let-mutually-exclusive.fixed create mode 100644 src/test/ui/parser/issue-99910-const-let-mutually-exclusive.rs create mode 100644 src/test/ui/parser/issue-99910-const-let-mutually-exclusive.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-enum.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-enum.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-fn-def.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-fn-def.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-impl.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-impl.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-path.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-path.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-struct.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-struct.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-trait.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-trait.stderr create mode 100644 src/test/ui/parser/issues/issue-14303.rs create mode 100644 src/test/ui/parser/issues/issue-14303.stderr create mode 100644 src/test/ui/parser/kw-in-trait-bounds.rs create mode 100644 src/test/ui/parser/kw-in-trait-bounds.stderr create mode 100644 src/test/ui/parser/public-instead-of-pub-1.fixed create mode 100644 src/test/ui/parser/public-instead-of-pub-1.rs create mode 100644 src/test/ui/parser/public-instead-of-pub-1.stderr create mode 100644 src/test/ui/parser/public-instead-of-pub-2.rs create mode 100644 src/test/ui/parser/public-instead-of-pub-2.stderr create mode 100644 src/test/ui/parser/public-instead-of-pub-3.fixed create mode 100644 src/test/ui/parser/public-instead-of-pub-3.rs create mode 100644 src/test/ui/parser/public-instead-of-pub-3.stderr create mode 100644 src/test/ui/parser/recover-field-semi.rs create mode 100644 src/test/ui/parser/recover-field-semi.stderr create mode 100644 src/test/ui/parser/recover-missing-semi-before-item.fixed create mode 100644 src/test/ui/parser/recover-missing-semi-before-item.rs create mode 100644 src/test/ui/parser/recover-missing-semi-before-item.stderr create mode 100644 src/test/ui/parser/struct-filed-with-attr.fixed create mode 100644 src/test/ui/parser/struct-filed-with-attr.rs create mode 100644 src/test/ui/parser/struct-filed-with-attr.stderr create mode 100644 src/test/ui/parser/suggest-assoc-const.fixed create mode 100644 src/test/ui/parser/suggest-assoc-const.rs create mode 100644 src/test/ui/parser/suggest-assoc-const.stderr create mode 100644 src/test/ui/parser/suggest-const-for-global-var.rs create mode 100644 src/test/ui/parser/suggest-const-for-global-var.stderr create mode 100644 src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed create mode 100644 src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs create mode 100644 src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr create mode 100644 src/test/ui/parser/suggest-semicolon-before-array.fixed create mode 100644 src/test/ui/parser/suggest-semicolon-before-array.rs create mode 100644 src/test/ui/parser/suggest-semicolon-before-array.stderr create mode 100644 src/test/ui/parser/unnecessary-let.rs create mode 100644 src/test/ui/parser/unnecessary-let.stderr create mode 100644 src/test/ui/pattern/rest-pat-syntactic.stderr create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr create mode 100644 src/test/ui/privacy/access_levels.rs create mode 100644 src/test/ui/privacy/access_levels.stderr create mode 100644 src/test/ui/proc-macro/auxiliary/re-export.rs create mode 100644 src/test/ui/proc-macro/dollar-crate-issue-101211.rs delete mode 100644 src/test/ui/proc-macro/expand-to-unstable-2.rs delete mode 100644 src/test/ui/proc-macro/expand-to-unstable-2.stderr delete mode 100644 src/test/ui/proc-macro/issue-41211.rs delete mode 100644 src/test/ui/proc-macro/issue-41211.stderr create mode 100644 src/test/ui/proc-macro/issue-79148.rs create mode 100644 src/test/ui/proc-macro/issue-79148.stderr create mode 100644 src/test/ui/recursion/issue-95134.rs create mode 100644 src/test/ui/recursion/issue-95134.stderr create mode 100644 src/test/ui/regions/do-not-suggest-adding-bound-to-opaque-type.rs create mode 100644 src/test/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr create mode 100644 src/test/ui/regions/outlives-with-missing.rs create mode 100644 src/test/ui/regions/outlives-with-missing.stderr create mode 100644 src/test/ui/repr/invalid_repr_list_help.rs create mode 100644 src/test/ui/repr/invalid_repr_list_help.stderr create mode 100644 src/test/ui/resolve/issue-100365.rs create mode 100644 src/test/ui/resolve/issue-100365.stderr create mode 100644 src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.rs create mode 100644 src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr create mode 100644 src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs create mode 100644 src/test/ui/sanitize/memory-eager.rs create mode 100644 src/test/ui/simd/intrinsic/ptr-cast.rs delete mode 100644 src/test/ui/span/issue-36530.rs delete mode 100644 src/test/ui/span/issue-36530.stderr create mode 100644 src/test/ui/stability-attribute/auxiliary/ctor-stability.rs create mode 100644 src/test/ui/stability-attribute/auxiliary/default_body.rs create mode 100644 src/test/ui/stability-attribute/ctor-stability.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.stderr create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-enables.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-impls.rs create mode 100644 src/test/ui/stats/hir-stats.rs create mode 100644 src/test/ui/stats/hir-stats.stderr delete mode 100644 src/test/ui/suggestions/as-ref-2.fixed create mode 100644 src/test/ui/suggestions/bool_typo_err_suggest.rs create mode 100644 src/test/ui/suggestions/bool_typo_err_suggest.stderr create mode 100644 src/test/ui/suggestions/call-boxed.rs create mode 100644 src/test/ui/suggestions/call-boxed.stderr create mode 100644 src/test/ui/suggestions/call-on-missing.rs create mode 100644 src/test/ui/suggestions/call-on-missing.stderr create mode 100644 src/test/ui/suggestions/copied-and-cloned.fixed create mode 100644 src/test/ui/suggestions/copied-and-cloned.rs create mode 100644 src/test/ui/suggestions/copied-and-cloned.stderr create mode 100644 src/test/ui/suggestions/deref-path-method.rs create mode 100644 src/test/ui/suggestions/deref-path-method.stderr create mode 100644 src/test/ui/suggestions/dont-try-removing-the-field.rs create mode 100644 src/test/ui/suggestions/dont-try-removing-the-field.stderr create mode 100644 src/test/ui/suggestions/field-access-considering-privacy.rs create mode 100644 src/test/ui/suggestions/field-access-considering-privacy.stderr create mode 100644 src/test/ui/suggestions/issue-101421.rs create mode 100644 src/test/ui/suggestions/issue-101421.stderr create mode 100644 src/test/ui/suggestions/issue-101465.rs create mode 100644 src/test/ui/suggestions/issue-101465.stderr create mode 100644 src/test/ui/suggestions/issue-101984.rs create mode 100644 src/test/ui/suggestions/issue-101984.stderr create mode 100644 src/test/ui/suggestions/issue-89064.rs create mode 100644 src/test/ui/suggestions/issue-89064.stderr create mode 100644 src/test/ui/suggestions/many-type-ascription.rs create mode 100644 src/test/ui/suggestions/many-type-ascription.stderr create mode 100644 src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs create mode 100644 src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr delete mode 100644 src/test/ui/suggestions/option-content-move.fixed create mode 100644 src/test/ui/suggestions/restrict-type-not-param.rs create mode 100644 src/test/ui/suggestions/restrict-type-not-param.stderr create mode 100644 src/test/ui/suggestions/return-closures.rs create mode 100644 src/test/ui/suggestions/return-closures.stderr create mode 100644 src/test/ui/suggestions/return-cycle-2.rs create mode 100644 src/test/ui/suggestions/return-cycle-2.stderr create mode 100644 src/test/ui/suggestions/return-cycle.rs create mode 100644 src/test/ui/suggestions/return-cycle.stderr create mode 100644 src/test/ui/suggestions/sugg_with_positional_args_and_debug_fmt.rs create mode 100644 src/test/ui/suggestions/sugg_with_positional_args_and_debug_fmt.stderr create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr create mode 100644 src/test/ui/suggestions/too-many-field-suggestions.rs create mode 100644 src/test/ui/suggestions/too-many-field-suggestions.stderr create mode 100644 src/test/ui/suggestions/try-removing-the-field.rs create mode 100644 src/test/ui/suggestions/try-removing-the-field.stderr create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.rs create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.stderr delete mode 100644 src/test/ui/tag-variant-disr-dup.rs delete mode 100644 src/test/ui/tag-variant-disr-dup.stderr create mode 100644 src/test/ui/traits/alias/generic-default-in-dyn.rs create mode 100644 src/test/ui/traits/alias/generic-default-in-dyn.stderr create mode 100644 src/test/ui/traits/alias/self-in-const-generics.rs create mode 100644 src/test/ui/traits/alias/self-in-const-generics.stderr create mode 100644 src/test/ui/traits/alias/self-in-generics.rs create mode 100644 src/test/ui/traits/alias/self-in-generics.stderr create mode 100644 src/test/ui/traits/unspecified-self-in-trait-ref.rs create mode 100644 src/test/ui/traits/unspecified-self-in-trait-ref.stderr create mode 100644 src/test/ui/tuple/builtin-fail.rs create mode 100644 src/test/ui/tuple/builtin-fail.stderr create mode 100644 src/test/ui/tuple/builtin.rs create mode 100644 src/test/ui/type-alias-impl-trait/closure_args.rs create mode 100644 src/test/ui/type-alias-impl-trait/closure_args2.rs create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs.stderr create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr create mode 100644 src/test/ui/type/issue-100584.rs create mode 100644 src/test/ui/type/issue-100584.stderr create mode 100644 src/test/ui/typeck/assign-non-lval-needs-deref.rs create mode 100644 src/test/ui/typeck/assign-non-lval-needs-deref.stderr create mode 100644 src/test/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.rs create mode 100644 src/test/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr create mode 100644 src/test/ui/typeck/issue-100164.fixed create mode 100644 src/test/ui/typeck/issue-100164.rs create mode 100644 src/test/ui/typeck/issue-100164.stderr create mode 100644 src/test/ui/typeck/issue-100246.rs create mode 100644 src/test/ui/typeck/issue-100246.stderr create mode 100644 src/test/ui/typeck/issue-100285.rs create mode 100644 src/test/ui/typeck/issue-100285.stderr create mode 100644 src/test/ui/typeck/issue-91633.rs create mode 100644 src/test/ui/typeck/issue-98982.rs create mode 100644 src/test/ui/typeck/issue-98982.stderr create mode 100644 src/test/ui/typeck/point-at-type-param-in-path-expr.rs create mode 100644 src/test/ui/typeck/point-at-type-param-in-path-expr.stderr create mode 100644 src/test/ui/typeof/issue-100183.rs create mode 100644 src/test/ui/typeof/issue-100183.stderr create mode 100644 src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs create mode 100644 src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr create mode 100644 src/test/ui/unpretty/avoid-crash.rs create mode 100644 src/test/ui/unpretty/avoid-crash.stderr create mode 100644 src/test/ui/unpretty/bad-literal.rs create mode 100644 src/test/ui/unpretty/bad-literal.stderr create mode 100644 src/test/ui/unpretty/bad-literal.stdout create mode 100644 src/test/ui/unpretty/pretty-let-else.rs create mode 100644 src/test/ui/unpretty/pretty-let-else.stdout create mode 100644 src/test/ui/unsized/issue-75899-but-gats.rs create mode 100644 src/test/ui/unsized/issue-75899.rs delete mode 100644 src/test/ui/unspecified-self-in-trait-ref.rs delete mode 100644 src/test/ui/unspecified-self-in-trait-ref.stderr delete mode 100644 src/tools/clippy/clippy_lints/src/as_underscore.rs delete mode 100644 src/tools/clippy/clippy_lints/src/blacklisted_name.rs create mode 100644 src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs delete mode 100644 src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs delete mode 100644 src/tools/clippy/clippy_lints/src/bytecount.rs delete mode 100644 src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs delete mode 100644 src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs create mode 100644 src/tools/clippy/clippy_lints/src/casts/as_underscore.rs create mode 100644 src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs create mode 100644 src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs create mode 100644 src/tools/clippy/clippy_lints/src/disallowed_names.rs create mode 100644 src/tools/clippy/clippy_lints/src/functions/result.rs delete mode 100644 src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs delete mode 100644 src/tools/clippy/clippy_lints/src/get_first.rs create mode 100644 src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs delete mode 100644 src/tools/clippy/clippy_lints/src/manual_ok_or.rs create mode 100644 src/tools/clippy/clippy_lints/src/manual_string_new.rs delete mode 100644 src/tools/clippy/clippy_lints/src/map_clone.rs delete mode 100644 src/tools/clippy/clippy_lints/src/map_err_ignore.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/bytecount.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/get_first.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/map_clone.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/open_options.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/repeat_once.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/unit_hash.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs create mode 100644 src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs create mode 100644 src/tools/clippy/clippy_lints/src/multi_assignments.rs delete mode 100644 src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs delete mode 100644 src/tools/clippy/clippy_lints/src/open_options.rs delete mode 100644 src/tools/clippy/clippy_lints/src/operators/arithmetic.rs create mode 100644 src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs create mode 100644 src/tools/clippy/clippy_lints/src/partialeq_to_none.rs delete mode 100644 src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs delete mode 100644 src/tools/clippy/clippy_lints/src/repeat_once.rs delete mode 100644 src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs create mode 100644 src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs delete mode 100644 src/tools/clippy/clippy_lints/src/transmuting_null.rs delete mode 100644 src/tools/clippy/clippy_lints/src/unit_hash.rs delete mode 100644 src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs create mode 100644 src/tools/clippy/clippy_lints/src/unused_peekable.rs delete mode 100644 src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs delete mode 100644 src/tools/clippy/clippy_lints/src/verbose_file_reads.rs create mode 100644 src/tools/clippy/clippy_utils/src/check_proc_macro.rs create mode 100644 src/tools/clippy/src/docs.rs create mode 100644 src/tools/clippy/src/docs/absurd_extreme_comparisons.txt create mode 100644 src/tools/clippy/src/docs/alloc_instead_of_core.txt create mode 100644 src/tools/clippy/src/docs/allow_attributes_without_reason.txt create mode 100644 src/tools/clippy/src/docs/almost_complete_letter_range.txt create mode 100644 src/tools/clippy/src/docs/almost_swapped.txt create mode 100644 src/tools/clippy/src/docs/approx_constant.txt create mode 100644 src/tools/clippy/src/docs/arithmetic_side_effects.txt create mode 100644 src/tools/clippy/src/docs/as_conversions.txt create mode 100644 src/tools/clippy/src/docs/as_underscore.txt create mode 100644 src/tools/clippy/src/docs/assertions_on_constants.txt create mode 100644 src/tools/clippy/src/docs/assertions_on_result_states.txt create mode 100644 src/tools/clippy/src/docs/assign_op_pattern.txt create mode 100644 src/tools/clippy/src/docs/async_yields_async.txt create mode 100644 src/tools/clippy/src/docs/await_holding_invalid_type.txt create mode 100644 src/tools/clippy/src/docs/await_holding_lock.txt create mode 100644 src/tools/clippy/src/docs/await_holding_refcell_ref.txt create mode 100644 src/tools/clippy/src/docs/bad_bit_mask.txt create mode 100644 src/tools/clippy/src/docs/bind_instead_of_map.txt create mode 100644 src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt create mode 100644 src/tools/clippy/src/docs/blocks_in_if_conditions.txt create mode 100644 src/tools/clippy/src/docs/bool_assert_comparison.txt create mode 100644 src/tools/clippy/src/docs/bool_comparison.txt create mode 100644 src/tools/clippy/src/docs/bool_to_int_with_if.txt create mode 100644 src/tools/clippy/src/docs/borrow_as_ptr.txt create mode 100644 src/tools/clippy/src/docs/borrow_deref_ref.txt create mode 100644 src/tools/clippy/src/docs/borrow_interior_mutable_const.txt create mode 100644 src/tools/clippy/src/docs/borrowed_box.txt create mode 100644 src/tools/clippy/src/docs/box_collection.txt create mode 100644 src/tools/clippy/src/docs/boxed_local.txt create mode 100644 src/tools/clippy/src/docs/branches_sharing_code.txt create mode 100644 src/tools/clippy/src/docs/builtin_type_shadow.txt create mode 100644 src/tools/clippy/src/docs/bytes_count_to_len.txt create mode 100644 src/tools/clippy/src/docs/bytes_nth.txt create mode 100644 src/tools/clippy/src/docs/cargo_common_metadata.txt create mode 100644 src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt create mode 100644 src/tools/clippy/src/docs/cast_abs_to_unsigned.txt create mode 100644 src/tools/clippy/src/docs/cast_enum_constructor.txt create mode 100644 src/tools/clippy/src/docs/cast_enum_truncation.txt create mode 100644 src/tools/clippy/src/docs/cast_lossless.txt create mode 100644 src/tools/clippy/src/docs/cast_possible_truncation.txt create mode 100644 src/tools/clippy/src/docs/cast_possible_wrap.txt create mode 100644 src/tools/clippy/src/docs/cast_precision_loss.txt create mode 100644 src/tools/clippy/src/docs/cast_ptr_alignment.txt create mode 100644 src/tools/clippy/src/docs/cast_ref_to_mut.txt create mode 100644 src/tools/clippy/src/docs/cast_sign_loss.txt create mode 100644 src/tools/clippy/src/docs/cast_slice_different_sizes.txt create mode 100644 src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt create mode 100644 src/tools/clippy/src/docs/char_lit_as_u8.txt create mode 100644 src/tools/clippy/src/docs/chars_last_cmp.txt create mode 100644 src/tools/clippy/src/docs/chars_next_cmp.txt create mode 100644 src/tools/clippy/src/docs/checked_conversions.txt create mode 100644 src/tools/clippy/src/docs/clone_double_ref.txt create mode 100644 src/tools/clippy/src/docs/clone_on_copy.txt create mode 100644 src/tools/clippy/src/docs/clone_on_ref_ptr.txt create mode 100644 src/tools/clippy/src/docs/cloned_instead_of_copied.txt create mode 100644 src/tools/clippy/src/docs/cmp_nan.txt create mode 100644 src/tools/clippy/src/docs/cmp_null.txt create mode 100644 src/tools/clippy/src/docs/cmp_owned.txt create mode 100644 src/tools/clippy/src/docs/cognitive_complexity.txt create mode 100644 src/tools/clippy/src/docs/collapsible_else_if.txt create mode 100644 src/tools/clippy/src/docs/collapsible_if.txt create mode 100644 src/tools/clippy/src/docs/collapsible_match.txt create mode 100644 src/tools/clippy/src/docs/collapsible_str_replace.txt create mode 100644 src/tools/clippy/src/docs/comparison_chain.txt create mode 100644 src/tools/clippy/src/docs/comparison_to_empty.txt create mode 100644 src/tools/clippy/src/docs/copy_iterator.txt create mode 100644 src/tools/clippy/src/docs/crate_in_macro_def.txt create mode 100644 src/tools/clippy/src/docs/create_dir.txt create mode 100644 src/tools/clippy/src/docs/crosspointer_transmute.txt create mode 100644 src/tools/clippy/src/docs/dbg_macro.txt create mode 100644 src/tools/clippy/src/docs/debug_assert_with_mut_call.txt create mode 100644 src/tools/clippy/src/docs/decimal_literal_representation.txt create mode 100644 src/tools/clippy/src/docs/declare_interior_mutable_const.txt create mode 100644 src/tools/clippy/src/docs/default_instead_of_iter_empty.txt create mode 100644 src/tools/clippy/src/docs/default_numeric_fallback.txt create mode 100644 src/tools/clippy/src/docs/default_trait_access.txt create mode 100644 src/tools/clippy/src/docs/default_union_representation.txt create mode 100644 src/tools/clippy/src/docs/deprecated_cfg_attr.txt create mode 100644 src/tools/clippy/src/docs/deprecated_semver.txt create mode 100644 src/tools/clippy/src/docs/deref_addrof.txt create mode 100644 src/tools/clippy/src/docs/deref_by_slicing.txt create mode 100644 src/tools/clippy/src/docs/derivable_impls.txt create mode 100644 src/tools/clippy/src/docs/derive_hash_xor_eq.txt create mode 100644 src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt create mode 100644 src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt create mode 100644 src/tools/clippy/src/docs/disallowed_methods.txt create mode 100644 src/tools/clippy/src/docs/disallowed_names.txt create mode 100644 src/tools/clippy/src/docs/disallowed_script_idents.txt create mode 100644 src/tools/clippy/src/docs/disallowed_types.txt create mode 100644 src/tools/clippy/src/docs/diverging_sub_expression.txt create mode 100644 src/tools/clippy/src/docs/doc_link_with_quotes.txt create mode 100644 src/tools/clippy/src/docs/doc_markdown.txt create mode 100644 src/tools/clippy/src/docs/double_comparisons.txt create mode 100644 src/tools/clippy/src/docs/double_must_use.txt create mode 100644 src/tools/clippy/src/docs/double_neg.txt create mode 100644 src/tools/clippy/src/docs/double_parens.txt create mode 100644 src/tools/clippy/src/docs/drop_copy.txt create mode 100644 src/tools/clippy/src/docs/drop_non_drop.txt create mode 100644 src/tools/clippy/src/docs/drop_ref.txt create mode 100644 src/tools/clippy/src/docs/duplicate_mod.txt create mode 100644 src/tools/clippy/src/docs/duplicate_underscore_argument.txt create mode 100644 src/tools/clippy/src/docs/duration_subsec.txt create mode 100644 src/tools/clippy/src/docs/else_if_without_else.txt create mode 100644 src/tools/clippy/src/docs/empty_drop.txt create mode 100644 src/tools/clippy/src/docs/empty_enum.txt create mode 100644 src/tools/clippy/src/docs/empty_line_after_outer_attr.txt create mode 100644 src/tools/clippy/src/docs/empty_loop.txt create mode 100644 src/tools/clippy/src/docs/empty_structs_with_brackets.txt create mode 100644 src/tools/clippy/src/docs/enum_clike_unportable_variant.txt create mode 100644 src/tools/clippy/src/docs/enum_glob_use.txt create mode 100644 src/tools/clippy/src/docs/enum_variant_names.txt create mode 100644 src/tools/clippy/src/docs/eq_op.txt create mode 100644 src/tools/clippy/src/docs/equatable_if_let.txt create mode 100644 src/tools/clippy/src/docs/erasing_op.txt create mode 100644 src/tools/clippy/src/docs/err_expect.txt create mode 100644 src/tools/clippy/src/docs/excessive_precision.txt create mode 100644 src/tools/clippy/src/docs/exhaustive_enums.txt create mode 100644 src/tools/clippy/src/docs/exhaustive_structs.txt create mode 100644 src/tools/clippy/src/docs/exit.txt create mode 100644 src/tools/clippy/src/docs/expect_fun_call.txt create mode 100644 src/tools/clippy/src/docs/expect_used.txt create mode 100644 src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt create mode 100644 src/tools/clippy/src/docs/explicit_auto_deref.txt create mode 100644 src/tools/clippy/src/docs/explicit_counter_loop.txt create mode 100644 src/tools/clippy/src/docs/explicit_deref_methods.txt create mode 100644 src/tools/clippy/src/docs/explicit_into_iter_loop.txt create mode 100644 src/tools/clippy/src/docs/explicit_iter_loop.txt create mode 100644 src/tools/clippy/src/docs/explicit_write.txt create mode 100644 src/tools/clippy/src/docs/extend_with_drain.txt create mode 100644 src/tools/clippy/src/docs/extra_unused_lifetimes.txt create mode 100644 src/tools/clippy/src/docs/fallible_impl_from.txt create mode 100644 src/tools/clippy/src/docs/field_reassign_with_default.txt create mode 100644 src/tools/clippy/src/docs/filetype_is_file.txt create mode 100644 src/tools/clippy/src/docs/filter_map_identity.txt create mode 100644 src/tools/clippy/src/docs/filter_map_next.txt create mode 100644 src/tools/clippy/src/docs/filter_next.txt create mode 100644 src/tools/clippy/src/docs/flat_map_identity.txt create mode 100644 src/tools/clippy/src/docs/flat_map_option.txt create mode 100644 src/tools/clippy/src/docs/float_arithmetic.txt create mode 100644 src/tools/clippy/src/docs/float_cmp.txt create mode 100644 src/tools/clippy/src/docs/float_cmp_const.txt create mode 100644 src/tools/clippy/src/docs/float_equality_without_abs.txt create mode 100644 src/tools/clippy/src/docs/fn_address_comparisons.txt create mode 100644 src/tools/clippy/src/docs/fn_params_excessive_bools.txt create mode 100644 src/tools/clippy/src/docs/fn_to_numeric_cast.txt create mode 100644 src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt create mode 100644 src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt create mode 100644 src/tools/clippy/src/docs/for_kv_map.txt create mode 100644 src/tools/clippy/src/docs/for_loops_over_fallibles.txt create mode 100644 src/tools/clippy/src/docs/forget_copy.txt create mode 100644 src/tools/clippy/src/docs/forget_non_drop.txt create mode 100644 src/tools/clippy/src/docs/forget_ref.txt create mode 100644 src/tools/clippy/src/docs/format_in_format_args.txt create mode 100644 src/tools/clippy/src/docs/format_push_string.txt create mode 100644 src/tools/clippy/src/docs/from_iter_instead_of_collect.txt create mode 100644 src/tools/clippy/src/docs/from_over_into.txt create mode 100644 src/tools/clippy/src/docs/from_str_radix_10.txt create mode 100644 src/tools/clippy/src/docs/future_not_send.txt create mode 100644 src/tools/clippy/src/docs/get_first.txt create mode 100644 src/tools/clippy/src/docs/get_last_with_len.txt create mode 100644 src/tools/clippy/src/docs/get_unwrap.txt create mode 100644 src/tools/clippy/src/docs/identity_op.txt create mode 100644 src/tools/clippy/src/docs/if_let_mutex.txt create mode 100644 src/tools/clippy/src/docs/if_not_else.txt create mode 100644 src/tools/clippy/src/docs/if_same_then_else.txt create mode 100644 src/tools/clippy/src/docs/if_then_some_else_none.txt create mode 100644 src/tools/clippy/src/docs/ifs_same_cond.txt create mode 100644 src/tools/clippy/src/docs/implicit_clone.txt create mode 100644 src/tools/clippy/src/docs/implicit_hasher.txt create mode 100644 src/tools/clippy/src/docs/implicit_return.txt create mode 100644 src/tools/clippy/src/docs/implicit_saturating_sub.txt create mode 100644 src/tools/clippy/src/docs/imprecise_flops.txt create mode 100644 src/tools/clippy/src/docs/inconsistent_digit_grouping.txt create mode 100644 src/tools/clippy/src/docs/inconsistent_struct_constructor.txt create mode 100644 src/tools/clippy/src/docs/index_refutable_slice.txt create mode 100644 src/tools/clippy/src/docs/indexing_slicing.txt create mode 100644 src/tools/clippy/src/docs/ineffective_bit_mask.txt create mode 100644 src/tools/clippy/src/docs/inefficient_to_string.txt create mode 100644 src/tools/clippy/src/docs/infallible_destructuring_match.txt create mode 100644 src/tools/clippy/src/docs/infinite_iter.txt create mode 100644 src/tools/clippy/src/docs/inherent_to_string.txt create mode 100644 src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt create mode 100644 src/tools/clippy/src/docs/init_numbered_fields.txt create mode 100644 src/tools/clippy/src/docs/inline_always.txt create mode 100644 src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt create mode 100644 src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt create mode 100644 src/tools/clippy/src/docs/inline_fn_without_body.txt create mode 100644 src/tools/clippy/src/docs/inspect_for_each.txt create mode 100644 src/tools/clippy/src/docs/int_plus_one.txt create mode 100644 src/tools/clippy/src/docs/integer_arithmetic.txt create mode 100644 src/tools/clippy/src/docs/integer_division.txt create mode 100644 src/tools/clippy/src/docs/into_iter_on_ref.txt create mode 100644 src/tools/clippy/src/docs/invalid_null_ptr_usage.txt create mode 100644 src/tools/clippy/src/docs/invalid_regex.txt create mode 100644 src/tools/clippy/src/docs/invalid_upcast_comparisons.txt create mode 100644 src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt create mode 100644 src/tools/clippy/src/docs/invisible_characters.txt create mode 100644 src/tools/clippy/src/docs/is_digit_ascii_radix.txt create mode 100644 src/tools/clippy/src/docs/items_after_statements.txt create mode 100644 src/tools/clippy/src/docs/iter_cloned_collect.txt create mode 100644 src/tools/clippy/src/docs/iter_count.txt create mode 100644 src/tools/clippy/src/docs/iter_next_loop.txt create mode 100644 src/tools/clippy/src/docs/iter_next_slice.txt create mode 100644 src/tools/clippy/src/docs/iter_not_returning_iterator.txt create mode 100644 src/tools/clippy/src/docs/iter_nth.txt create mode 100644 src/tools/clippy/src/docs/iter_nth_zero.txt create mode 100644 src/tools/clippy/src/docs/iter_on_empty_collections.txt create mode 100644 src/tools/clippy/src/docs/iter_on_single_items.txt create mode 100644 src/tools/clippy/src/docs/iter_overeager_cloned.txt create mode 100644 src/tools/clippy/src/docs/iter_skip_next.txt create mode 100644 src/tools/clippy/src/docs/iter_with_drain.txt create mode 100644 src/tools/clippy/src/docs/iterator_step_by_zero.txt create mode 100644 src/tools/clippy/src/docs/just_underscores_and_digits.txt create mode 100644 src/tools/clippy/src/docs/large_const_arrays.txt create mode 100644 src/tools/clippy/src/docs/large_digit_groups.txt create mode 100644 src/tools/clippy/src/docs/large_enum_variant.txt create mode 100644 src/tools/clippy/src/docs/large_include_file.txt create mode 100644 src/tools/clippy/src/docs/large_stack_arrays.txt create mode 100644 src/tools/clippy/src/docs/large_types_passed_by_value.txt create mode 100644 src/tools/clippy/src/docs/len_without_is_empty.txt create mode 100644 src/tools/clippy/src/docs/len_zero.txt create mode 100644 src/tools/clippy/src/docs/let_and_return.txt create mode 100644 src/tools/clippy/src/docs/let_underscore_drop.txt create mode 100644 src/tools/clippy/src/docs/let_underscore_lock.txt create mode 100644 src/tools/clippy/src/docs/let_underscore_must_use.txt create mode 100644 src/tools/clippy/src/docs/let_unit_value.txt create mode 100644 src/tools/clippy/src/docs/linkedlist.txt create mode 100644 src/tools/clippy/src/docs/lossy_float_literal.txt create mode 100644 src/tools/clippy/src/docs/macro_use_imports.txt create mode 100644 src/tools/clippy/src/docs/main_recursion.txt create mode 100644 src/tools/clippy/src/docs/manual_assert.txt create mode 100644 src/tools/clippy/src/docs/manual_async_fn.txt create mode 100644 src/tools/clippy/src/docs/manual_bits.txt create mode 100644 src/tools/clippy/src/docs/manual_filter_map.txt create mode 100644 src/tools/clippy/src/docs/manual_find.txt create mode 100644 src/tools/clippy/src/docs/manual_find_map.txt create mode 100644 src/tools/clippy/src/docs/manual_flatten.txt create mode 100644 src/tools/clippy/src/docs/manual_instant_elapsed.txt create mode 100644 src/tools/clippy/src/docs/manual_map.txt create mode 100644 src/tools/clippy/src/docs/manual_memcpy.txt create mode 100644 src/tools/clippy/src/docs/manual_non_exhaustive.txt create mode 100644 src/tools/clippy/src/docs/manual_ok_or.txt create mode 100644 src/tools/clippy/src/docs/manual_range_contains.txt create mode 100644 src/tools/clippy/src/docs/manual_rem_euclid.txt create mode 100644 src/tools/clippy/src/docs/manual_retain.txt create mode 100644 src/tools/clippy/src/docs/manual_saturating_arithmetic.txt create mode 100644 src/tools/clippy/src/docs/manual_split_once.txt create mode 100644 src/tools/clippy/src/docs/manual_str_repeat.txt create mode 100644 src/tools/clippy/src/docs/manual_string_new.txt create mode 100644 src/tools/clippy/src/docs/manual_strip.txt create mode 100644 src/tools/clippy/src/docs/manual_swap.txt create mode 100644 src/tools/clippy/src/docs/manual_unwrap_or.txt create mode 100644 src/tools/clippy/src/docs/many_single_char_names.txt create mode 100644 src/tools/clippy/src/docs/map_clone.txt create mode 100644 src/tools/clippy/src/docs/map_collect_result_unit.txt create mode 100644 src/tools/clippy/src/docs/map_entry.txt create mode 100644 src/tools/clippy/src/docs/map_err_ignore.txt create mode 100644 src/tools/clippy/src/docs/map_flatten.txt create mode 100644 src/tools/clippy/src/docs/map_identity.txt create mode 100644 src/tools/clippy/src/docs/map_unwrap_or.txt create mode 100644 src/tools/clippy/src/docs/match_as_ref.txt create mode 100644 src/tools/clippy/src/docs/match_bool.txt create mode 100644 src/tools/clippy/src/docs/match_like_matches_macro.txt create mode 100644 src/tools/clippy/src/docs/match_on_vec_items.txt create mode 100644 src/tools/clippy/src/docs/match_overlapping_arm.txt create mode 100644 src/tools/clippy/src/docs/match_ref_pats.txt create mode 100644 src/tools/clippy/src/docs/match_result_ok.txt create mode 100644 src/tools/clippy/src/docs/match_same_arms.txt create mode 100644 src/tools/clippy/src/docs/match_single_binding.txt create mode 100644 src/tools/clippy/src/docs/match_str_case_mismatch.txt create mode 100644 src/tools/clippy/src/docs/match_wild_err_arm.txt create mode 100644 src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt create mode 100644 src/tools/clippy/src/docs/maybe_infinite_iter.txt create mode 100644 src/tools/clippy/src/docs/mem_forget.txt create mode 100644 src/tools/clippy/src/docs/mem_replace_option_with_none.txt create mode 100644 src/tools/clippy/src/docs/mem_replace_with_default.txt create mode 100644 src/tools/clippy/src/docs/mem_replace_with_uninit.txt create mode 100644 src/tools/clippy/src/docs/min_max.txt create mode 100644 src/tools/clippy/src/docs/mismatched_target_os.txt create mode 100644 src/tools/clippy/src/docs/mismatching_type_param_order.txt create mode 100644 src/tools/clippy/src/docs/misrefactored_assign_op.txt create mode 100644 src/tools/clippy/src/docs/missing_const_for_fn.txt create mode 100644 src/tools/clippy/src/docs/missing_docs_in_private_items.txt create mode 100644 src/tools/clippy/src/docs/missing_enforced_import_renames.txt create mode 100644 src/tools/clippy/src/docs/missing_errors_doc.txt create mode 100644 src/tools/clippy/src/docs/missing_inline_in_public_items.txt create mode 100644 src/tools/clippy/src/docs/missing_panics_doc.txt create mode 100644 src/tools/clippy/src/docs/missing_safety_doc.txt create mode 100644 src/tools/clippy/src/docs/missing_spin_loop.txt create mode 100644 src/tools/clippy/src/docs/mistyped_literal_suffixes.txt create mode 100644 src/tools/clippy/src/docs/mixed_case_hex_literals.txt create mode 100644 src/tools/clippy/src/docs/mixed_read_write_in_expression.txt create mode 100644 src/tools/clippy/src/docs/mod_module_files.txt create mode 100644 src/tools/clippy/src/docs/module_inception.txt create mode 100644 src/tools/clippy/src/docs/module_name_repetitions.txt create mode 100644 src/tools/clippy/src/docs/modulo_arithmetic.txt create mode 100644 src/tools/clippy/src/docs/modulo_one.txt create mode 100644 src/tools/clippy/src/docs/multi_assignments.txt create mode 100644 src/tools/clippy/src/docs/multiple_crate_versions.txt create mode 100644 src/tools/clippy/src/docs/multiple_inherent_impl.txt create mode 100644 src/tools/clippy/src/docs/must_use_candidate.txt create mode 100644 src/tools/clippy/src/docs/must_use_unit.txt create mode 100644 src/tools/clippy/src/docs/mut_from_ref.txt create mode 100644 src/tools/clippy/src/docs/mut_mut.txt create mode 100644 src/tools/clippy/src/docs/mut_mutex_lock.txt create mode 100644 src/tools/clippy/src/docs/mut_range_bound.txt create mode 100644 src/tools/clippy/src/docs/mutable_key_type.txt create mode 100644 src/tools/clippy/src/docs/mutex_atomic.txt create mode 100644 src/tools/clippy/src/docs/mutex_integer.txt create mode 100644 src/tools/clippy/src/docs/naive_bytecount.txt create mode 100644 src/tools/clippy/src/docs/needless_arbitrary_self_type.txt create mode 100644 src/tools/clippy/src/docs/needless_bitwise_bool.txt create mode 100644 src/tools/clippy/src/docs/needless_bool.txt create mode 100644 src/tools/clippy/src/docs/needless_borrow.txt create mode 100644 src/tools/clippy/src/docs/needless_borrowed_reference.txt create mode 100644 src/tools/clippy/src/docs/needless_collect.txt create mode 100644 src/tools/clippy/src/docs/needless_continue.txt create mode 100644 src/tools/clippy/src/docs/needless_doctest_main.txt create mode 100644 src/tools/clippy/src/docs/needless_for_each.txt create mode 100644 src/tools/clippy/src/docs/needless_late_init.txt create mode 100644 src/tools/clippy/src/docs/needless_lifetimes.txt create mode 100644 src/tools/clippy/src/docs/needless_match.txt create mode 100644 src/tools/clippy/src/docs/needless_option_as_deref.txt create mode 100644 src/tools/clippy/src/docs/needless_option_take.txt create mode 100644 src/tools/clippy/src/docs/needless_parens_on_range_literals.txt create mode 100644 src/tools/clippy/src/docs/needless_pass_by_value.txt create mode 100644 src/tools/clippy/src/docs/needless_question_mark.txt create mode 100644 src/tools/clippy/src/docs/needless_range_loop.txt create mode 100644 src/tools/clippy/src/docs/needless_return.txt create mode 100644 src/tools/clippy/src/docs/needless_splitn.txt create mode 100644 src/tools/clippy/src/docs/needless_update.txt create mode 100644 src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt create mode 100644 src/tools/clippy/src/docs/neg_multiply.txt create mode 100644 src/tools/clippy/src/docs/negative_feature_names.txt create mode 100644 src/tools/clippy/src/docs/never_loop.txt create mode 100644 src/tools/clippy/src/docs/new_ret_no_self.txt create mode 100644 src/tools/clippy/src/docs/new_without_default.txt create mode 100644 src/tools/clippy/src/docs/no_effect.txt create mode 100644 src/tools/clippy/src/docs/no_effect_replace.txt create mode 100644 src/tools/clippy/src/docs/no_effect_underscore_binding.txt create mode 100644 src/tools/clippy/src/docs/non_ascii_literal.txt create mode 100644 src/tools/clippy/src/docs/non_octal_unix_permissions.txt create mode 100644 src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt create mode 100644 src/tools/clippy/src/docs/nonminimal_bool.txt create mode 100644 src/tools/clippy/src/docs/nonsensical_open_options.txt create mode 100644 src/tools/clippy/src/docs/nonstandard_macro_braces.txt create mode 100644 src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt create mode 100644 src/tools/clippy/src/docs/obfuscated_if_else.txt create mode 100644 src/tools/clippy/src/docs/octal_escapes.txt create mode 100644 src/tools/clippy/src/docs/ok_expect.txt create mode 100644 src/tools/clippy/src/docs/only_used_in_recursion.txt create mode 100644 src/tools/clippy/src/docs/op_ref.txt create mode 100644 src/tools/clippy/src/docs/option_as_ref_deref.txt create mode 100644 src/tools/clippy/src/docs/option_env_unwrap.txt create mode 100644 src/tools/clippy/src/docs/option_filter_map.txt create mode 100644 src/tools/clippy/src/docs/option_if_let_else.txt create mode 100644 src/tools/clippy/src/docs/option_map_or_none.txt create mode 100644 src/tools/clippy/src/docs/option_map_unit_fn.txt create mode 100644 src/tools/clippy/src/docs/option_option.txt create mode 100644 src/tools/clippy/src/docs/or_fun_call.txt create mode 100644 src/tools/clippy/src/docs/or_then_unwrap.txt create mode 100644 src/tools/clippy/src/docs/out_of_bounds_indexing.txt create mode 100644 src/tools/clippy/src/docs/overflow_check_conditional.txt create mode 100644 src/tools/clippy/src/docs/overly_complex_bool_expr.txt create mode 100644 src/tools/clippy/src/docs/panic.txt create mode 100644 src/tools/clippy/src/docs/panic_in_result_fn.txt create mode 100644 src/tools/clippy/src/docs/panicking_unwrap.txt create mode 100644 src/tools/clippy/src/docs/partialeq_ne_impl.txt create mode 100644 src/tools/clippy/src/docs/partialeq_to_none.txt create mode 100644 src/tools/clippy/src/docs/path_buf_push_overwrite.txt create mode 100644 src/tools/clippy/src/docs/pattern_type_mismatch.txt create mode 100644 src/tools/clippy/src/docs/positional_named_format_parameters.txt create mode 100644 src/tools/clippy/src/docs/possible_missing_comma.txt create mode 100644 src/tools/clippy/src/docs/precedence.txt create mode 100644 src/tools/clippy/src/docs/print_in_format_impl.txt create mode 100644 src/tools/clippy/src/docs/print_literal.txt create mode 100644 src/tools/clippy/src/docs/print_stderr.txt create mode 100644 src/tools/clippy/src/docs/print_stdout.txt create mode 100644 src/tools/clippy/src/docs/print_with_newline.txt create mode 100644 src/tools/clippy/src/docs/println_empty_string.txt create mode 100644 src/tools/clippy/src/docs/ptr_arg.txt create mode 100644 src/tools/clippy/src/docs/ptr_as_ptr.txt create mode 100644 src/tools/clippy/src/docs/ptr_eq.txt create mode 100644 src/tools/clippy/src/docs/ptr_offset_with_cast.txt create mode 100644 src/tools/clippy/src/docs/pub_use.txt create mode 100644 src/tools/clippy/src/docs/question_mark.txt create mode 100644 src/tools/clippy/src/docs/range_minus_one.txt create mode 100644 src/tools/clippy/src/docs/range_plus_one.txt create mode 100644 src/tools/clippy/src/docs/range_zip_with_len.txt create mode 100644 src/tools/clippy/src/docs/rc_buffer.txt create mode 100644 src/tools/clippy/src/docs/rc_clone_in_vec_init.txt create mode 100644 src/tools/clippy/src/docs/rc_mutex.txt create mode 100644 src/tools/clippy/src/docs/read_zero_byte_vec.txt create mode 100644 src/tools/clippy/src/docs/recursive_format_impl.txt create mode 100644 src/tools/clippy/src/docs/redundant_allocation.txt create mode 100644 src/tools/clippy/src/docs/redundant_clone.txt create mode 100644 src/tools/clippy/src/docs/redundant_closure.txt create mode 100644 src/tools/clippy/src/docs/redundant_closure_call.txt create mode 100644 src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt create mode 100644 src/tools/clippy/src/docs/redundant_else.txt create mode 100644 src/tools/clippy/src/docs/redundant_feature_names.txt create mode 100644 src/tools/clippy/src/docs/redundant_field_names.txt create mode 100644 src/tools/clippy/src/docs/redundant_pattern.txt create mode 100644 src/tools/clippy/src/docs/redundant_pattern_matching.txt create mode 100644 src/tools/clippy/src/docs/redundant_pub_crate.txt create mode 100644 src/tools/clippy/src/docs/redundant_slicing.txt create mode 100644 src/tools/clippy/src/docs/redundant_static_lifetimes.txt create mode 100644 src/tools/clippy/src/docs/ref_binding_to_reference.txt create mode 100644 src/tools/clippy/src/docs/ref_option_ref.txt create mode 100644 src/tools/clippy/src/docs/repeat_once.txt create mode 100644 src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt create mode 100644 src/tools/clippy/src/docs/result_large_err.txt create mode 100644 src/tools/clippy/src/docs/result_map_or_into_option.txt create mode 100644 src/tools/clippy/src/docs/result_map_unit_fn.txt create mode 100644 src/tools/clippy/src/docs/result_unit_err.txt create mode 100644 src/tools/clippy/src/docs/return_self_not_must_use.txt create mode 100644 src/tools/clippy/src/docs/reversed_empty_ranges.txt create mode 100644 src/tools/clippy/src/docs/same_functions_in_if_condition.txt create mode 100644 src/tools/clippy/src/docs/same_item_push.txt create mode 100644 src/tools/clippy/src/docs/same_name_method.txt create mode 100644 src/tools/clippy/src/docs/search_is_some.txt create mode 100644 src/tools/clippy/src/docs/self_assignment.txt create mode 100644 src/tools/clippy/src/docs/self_named_constructors.txt create mode 100644 src/tools/clippy/src/docs/self_named_module_files.txt create mode 100644 src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt create mode 100644 src/tools/clippy/src/docs/separated_literal_suffix.txt create mode 100644 src/tools/clippy/src/docs/serde_api_misuse.txt create mode 100644 src/tools/clippy/src/docs/shadow_reuse.txt create mode 100644 src/tools/clippy/src/docs/shadow_same.txt create mode 100644 src/tools/clippy/src/docs/shadow_unrelated.txt create mode 100644 src/tools/clippy/src/docs/short_circuit_statement.txt create mode 100644 src/tools/clippy/src/docs/should_implement_trait.txt create mode 100644 src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt create mode 100644 src/tools/clippy/src/docs/similar_names.txt create mode 100644 src/tools/clippy/src/docs/single_char_add_str.txt create mode 100644 src/tools/clippy/src/docs/single_char_lifetime_names.txt create mode 100644 src/tools/clippy/src/docs/single_char_pattern.txt create mode 100644 src/tools/clippy/src/docs/single_component_path_imports.txt create mode 100644 src/tools/clippy/src/docs/single_element_loop.txt create mode 100644 src/tools/clippy/src/docs/single_match.txt create mode 100644 src/tools/clippy/src/docs/single_match_else.txt create mode 100644 src/tools/clippy/src/docs/size_of_in_element_count.txt create mode 100644 src/tools/clippy/src/docs/skip_while_next.txt create mode 100644 src/tools/clippy/src/docs/slow_vector_initialization.txt create mode 100644 src/tools/clippy/src/docs/stable_sort_primitive.txt create mode 100644 src/tools/clippy/src/docs/std_instead_of_alloc.txt create mode 100644 src/tools/clippy/src/docs/std_instead_of_core.txt create mode 100644 src/tools/clippy/src/docs/str_to_string.txt create mode 100644 src/tools/clippy/src/docs/string_add.txt create mode 100644 src/tools/clippy/src/docs/string_add_assign.txt create mode 100644 src/tools/clippy/src/docs/string_extend_chars.txt create mode 100644 src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt create mode 100644 src/tools/clippy/src/docs/string_lit_as_bytes.txt create mode 100644 src/tools/clippy/src/docs/string_slice.txt create mode 100644 src/tools/clippy/src/docs/string_to_string.txt create mode 100644 src/tools/clippy/src/docs/strlen_on_c_strings.txt create mode 100644 src/tools/clippy/src/docs/struct_excessive_bools.txt create mode 100644 src/tools/clippy/src/docs/suboptimal_flops.txt create mode 100644 src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt create mode 100644 src/tools/clippy/src/docs/suspicious_assignment_formatting.txt create mode 100644 src/tools/clippy/src/docs/suspicious_else_formatting.txt create mode 100644 src/tools/clippy/src/docs/suspicious_map.txt create mode 100644 src/tools/clippy/src/docs/suspicious_op_assign_impl.txt create mode 100644 src/tools/clippy/src/docs/suspicious_operation_groupings.txt create mode 100644 src/tools/clippy/src/docs/suspicious_splitn.txt create mode 100644 src/tools/clippy/src/docs/suspicious_to_owned.txt create mode 100644 src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt create mode 100644 src/tools/clippy/src/docs/swap_ptr_to_ref.txt create mode 100644 src/tools/clippy/src/docs/tabs_in_doc_comments.txt create mode 100644 src/tools/clippy/src/docs/temporary_assignment.txt create mode 100644 src/tools/clippy/src/docs/to_digit_is_some.txt create mode 100644 src/tools/clippy/src/docs/to_string_in_format_args.txt create mode 100644 src/tools/clippy/src/docs/todo.txt create mode 100644 src/tools/clippy/src/docs/too_many_arguments.txt create mode 100644 src/tools/clippy/src/docs/too_many_lines.txt create mode 100644 src/tools/clippy/src/docs/toplevel_ref_arg.txt create mode 100644 src/tools/clippy/src/docs/trailing_empty_array.txt create mode 100644 src/tools/clippy/src/docs/trait_duplication_in_bounds.txt create mode 100644 src/tools/clippy/src/docs/transmute_bytes_to_str.txt create mode 100644 src/tools/clippy/src/docs/transmute_float_to_int.txt create mode 100644 src/tools/clippy/src/docs/transmute_int_to_bool.txt create mode 100644 src/tools/clippy/src/docs/transmute_int_to_char.txt create mode 100644 src/tools/clippy/src/docs/transmute_int_to_float.txt create mode 100644 src/tools/clippy/src/docs/transmute_num_to_bytes.txt create mode 100644 src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt create mode 100644 src/tools/clippy/src/docs/transmute_ptr_to_ref.txt create mode 100644 src/tools/clippy/src/docs/transmute_undefined_repr.txt create mode 100644 src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt create mode 100644 src/tools/clippy/src/docs/transmuting_null.txt create mode 100644 src/tools/clippy/src/docs/trim_split_whitespace.txt create mode 100644 src/tools/clippy/src/docs/trivial_regex.txt create mode 100644 src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt create mode 100644 src/tools/clippy/src/docs/try_err.txt create mode 100644 src/tools/clippy/src/docs/type_complexity.txt create mode 100644 src/tools/clippy/src/docs/type_repetition_in_bounds.txt create mode 100644 src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt create mode 100644 src/tools/clippy/src/docs/undropped_manually_drops.txt create mode 100644 src/tools/clippy/src/docs/unicode_not_nfc.txt create mode 100644 src/tools/clippy/src/docs/unimplemented.txt create mode 100644 src/tools/clippy/src/docs/uninit_assumed_init.txt create mode 100644 src/tools/clippy/src/docs/uninit_vec.txt create mode 100644 src/tools/clippy/src/docs/unit_arg.txt create mode 100644 src/tools/clippy/src/docs/unit_cmp.txt create mode 100644 src/tools/clippy/src/docs/unit_hash.txt create mode 100644 src/tools/clippy/src/docs/unit_return_expecting_ord.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_cast.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_filter_map.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_find_map.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_fold.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_join.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_mut_passed.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_operation.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_self_imports.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_sort_by.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_to_owned.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_unwrap.txt create mode 100644 src/tools/clippy/src/docs/unnecessary_wraps.txt create mode 100644 src/tools/clippy/src/docs/unneeded_field_pattern.txt create mode 100644 src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt create mode 100644 src/tools/clippy/src/docs/unnested_or_patterns.txt create mode 100644 src/tools/clippy/src/docs/unreachable.txt create mode 100644 src/tools/clippy/src/docs/unreadable_literal.txt create mode 100644 src/tools/clippy/src/docs/unsafe_derive_deserialize.txt create mode 100644 src/tools/clippy/src/docs/unsafe_removed_from_name.txt create mode 100644 src/tools/clippy/src/docs/unseparated_literal_suffix.txt create mode 100644 src/tools/clippy/src/docs/unsound_collection_transmute.txt create mode 100644 src/tools/clippy/src/docs/unused_async.txt create mode 100644 src/tools/clippy/src/docs/unused_io_amount.txt create mode 100644 src/tools/clippy/src/docs/unused_peekable.txt create mode 100644 src/tools/clippy/src/docs/unused_rounding.txt create mode 100644 src/tools/clippy/src/docs/unused_self.txt create mode 100644 src/tools/clippy/src/docs/unused_unit.txt create mode 100644 src/tools/clippy/src/docs/unusual_byte_groupings.txt create mode 100644 src/tools/clippy/src/docs/unwrap_in_result.txt create mode 100644 src/tools/clippy/src/docs/unwrap_or_else_default.txt create mode 100644 src/tools/clippy/src/docs/unwrap_used.txt create mode 100644 src/tools/clippy/src/docs/upper_case_acronyms.txt create mode 100644 src/tools/clippy/src/docs/use_debug.txt create mode 100644 src/tools/clippy/src/docs/use_self.txt create mode 100644 src/tools/clippy/src/docs/used_underscore_binding.txt create mode 100644 src/tools/clippy/src/docs/useless_asref.txt create mode 100644 src/tools/clippy/src/docs/useless_attribute.txt create mode 100644 src/tools/clippy/src/docs/useless_conversion.txt create mode 100644 src/tools/clippy/src/docs/useless_format.txt create mode 100644 src/tools/clippy/src/docs/useless_let_if_seq.txt create mode 100644 src/tools/clippy/src/docs/useless_transmute.txt create mode 100644 src/tools/clippy/src/docs/useless_vec.txt create mode 100644 src/tools/clippy/src/docs/vec_box.txt create mode 100644 src/tools/clippy/src/docs/vec_init_then_push.txt create mode 100644 src/tools/clippy/src/docs/vec_resize_to_zero.txt create mode 100644 src/tools/clippy/src/docs/verbose_bit_mask.txt create mode 100644 src/tools/clippy/src/docs/verbose_file_reads.txt create mode 100644 src/tools/clippy/src/docs/vtable_address_comparisons.txt create mode 100644 src/tools/clippy/src/docs/while_immutable_condition.txt create mode 100644 src/tools/clippy/src/docs/while_let_loop.txt create mode 100644 src/tools/clippy/src/docs/while_let_on_iterator.txt create mode 100644 src/tools/clippy/src/docs/wildcard_dependencies.txt create mode 100644 src/tools/clippy/src/docs/wildcard_enum_match_arm.txt create mode 100644 src/tools/clippy/src/docs/wildcard_imports.txt create mode 100644 src/tools/clippy/src/docs/wildcard_in_or_patterns.txt create mode 100644 src/tools/clippy/src/docs/write_literal.txt create mode 100644 src/tools/clippy/src/docs/write_with_newline.txt create mode 100644 src/tools/clippy/src/docs/writeln_empty_string.txt create mode 100644 src/tools/clippy/src/docs/wrong_self_convention.txt create mode 100644 src/tools/clippy/src/docs/wrong_transmute.txt create mode 100644 src/tools/clippy/src/docs/zero_divided_by_zero.txt create mode 100644 src/tools/clippy/src/docs/zero_prefixed_literal.txt create mode 100644 src/tools/clippy/src/docs/zero_ptr.txt create mode 100644 src/tools/clippy/src/docs/zero_sized_map_values.txt create mode 100644 src/tools/clippy/src/docs/zst_offset.txt delete mode 100644 src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs delete mode 100644 src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs create mode 100644 src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr delete mode 100644 src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs create mode 100644 src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr create mode 100644 src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs create mode 100644 src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr delete mode 100644 src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml delete mode 100644 src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs delete mode 100644 src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr create mode 100644 src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml create mode 100644 src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs create mode 100644 src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr delete mode 100644 src/tools/clippy/tests/ui/arithmetic.fixed delete mode 100644 src/tools/clippy/tests/ui/arithmetic.rs create mode 100644 src/tools/clippy/tests/ui/arithmetic_side_effects.rs create mode 100644 src/tools/clippy/tests/ui/arithmetic_side_effects.stderr delete mode 100644 src/tools/clippy/tests/ui/blacklisted_name.rs delete mode 100644 src/tools/clippy/tests/ui/blacklisted_name.stderr create mode 100644 src/tools/clippy/tests/ui/bool_to_int_with_if.fixed create mode 100644 src/tools/clippy/tests/ui/bool_to_int_with_if.rs create mode 100644 src/tools/clippy/tests/ui/bool_to_int_with_if.stderr create mode 100644 src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed create mode 100644 src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs create mode 100644 src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr create mode 100644 src/tools/clippy/tests/ui/collapsible_str_replace.fixed create mode 100644 src/tools/clippy/tests/ui/collapsible_str_replace.rs create mode 100644 src/tools/clippy/tests/ui/collapsible_str_replace.stderr create mode 100644 src/tools/clippy/tests/ui/crashes/ice-9405.rs create mode 100644 src/tools/clippy/tests/ui/crashes/ice-9405.stderr create mode 100644 src/tools/clippy/tests/ui/crashes/ice-9414.rs create mode 100644 src/tools/clippy/tests/ui/disallowed_names.rs create mode 100644 src/tools/clippy/tests/ui/disallowed_names.stderr create mode 100644 src/tools/clippy/tests/ui/iter_on_empty_collections.fixed create mode 100644 src/tools/clippy/tests/ui/iter_on_empty_collections.rs create mode 100644 src/tools/clippy/tests/ui/iter_on_empty_collections.stderr create mode 100644 src/tools/clippy/tests/ui/iter_on_single_items.fixed create mode 100644 src/tools/clippy/tests/ui/iter_on_single_items.rs create mode 100644 src/tools/clippy/tests/ui/iter_on_single_items.stderr delete mode 100644 src/tools/clippy/tests/ui/logic_bug.rs delete mode 100644 src/tools/clippy/tests/ui/logic_bug.stderr create mode 100644 src/tools/clippy/tests/ui/manual_instant_elapsed.fixed create mode 100644 src/tools/clippy/tests/ui/manual_instant_elapsed.rs create mode 100644 src/tools/clippy/tests/ui/manual_instant_elapsed.stderr create mode 100644 src/tools/clippy/tests/ui/manual_string_new.fixed create mode 100644 src/tools/clippy/tests/ui/manual_string_new.rs create mode 100644 src/tools/clippy/tests/ui/manual_string_new.stderr delete mode 100644 src/tools/clippy/tests/ui/missing-doc-crate-missing.rs delete mode 100644 src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr delete mode 100644 src/tools/clippy/tests/ui/missing-doc-crate.rs delete mode 100644 src/tools/clippy/tests/ui/missing-doc-impl.rs delete mode 100644 src/tools/clippy/tests/ui/missing-doc-impl.stderr delete mode 100644 src/tools/clippy/tests/ui/missing-doc.rs delete mode 100644 src/tools/clippy/tests/ui/missing-doc.stderr create mode 100644 src/tools/clippy/tests/ui/missing_doc.rs create mode 100644 src/tools/clippy/tests/ui/missing_doc.stderr create mode 100644 src/tools/clippy/tests/ui/missing_doc_crate.rs create mode 100644 src/tools/clippy/tests/ui/missing_doc_crate_missing.rs create mode 100644 src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr create mode 100644 src/tools/clippy/tests/ui/missing_doc_impl.rs create mode 100644 src/tools/clippy/tests/ui/missing_doc_impl.stderr create mode 100644 src/tools/clippy/tests/ui/multi_assignments.rs create mode 100644 src/tools/clippy/tests/ui/multi_assignments.stderr create mode 100644 src/tools/clippy/tests/ui/only_used_in_recursion2.rs create mode 100644 src/tools/clippy/tests/ui/only_used_in_recursion2.stderr create mode 100644 src/tools/clippy/tests/ui/overly_complex_bool_expr.rs create mode 100644 src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr create mode 100644 src/tools/clippy/tests/ui/partialeq_to_none.fixed create mode 100644 src/tools/clippy/tests/ui/partialeq_to_none.rs create mode 100644 src/tools/clippy/tests/ui/partialeq_to_none.stderr create mode 100644 src/tools/clippy/tests/ui/positional_named_format_parameters.fixed create mode 100644 src/tools/clippy/tests/ui/positional_named_format_parameters.rs create mode 100644 src/tools/clippy/tests/ui/positional_named_format_parameters.stderr create mode 100644 src/tools/clippy/tests/ui/result_large_err.rs create mode 100644 src/tools/clippy/tests/ui/result_large_err.stderr create mode 100644 src/tools/clippy/tests/ui/suspicious_to_owned.rs create mode 100644 src/tools/clippy/tests/ui/suspicious_to_owned.stderr create mode 100644 src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed create mode 100644 src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs create mode 100644 src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr create mode 100644 src/tools/clippy/tests/ui/unused_peekable.rs create mode 100644 src/tools/clippy/tests/ui/unused_peekable.stderr create mode 100644 src/tools/clippy/tests/ui/unwrap_expect_used.rs create mode 100644 src/tools/clippy/tests/ui/unwrap_expect_used.stderr create mode 100644 src/tools/error_index_generator/book_config.toml delete mode 100644 src/tools/error_index_generator/build.rs create mode 100644 src/tools/error_index_generator/error-index.css create mode 100644 src/tools/error_index_generator/error-index.js create mode 100644 src/tools/error_index_generator/redirect.js create mode 100644 src/tools/jsondoclint/Cargo.toml create mode 100644 src/tools/jsondoclint/src/item_kind.rs create mode 100644 src/tools/jsondoclint/src/json_find.rs create mode 100644 src/tools/jsondoclint/src/main.rs create mode 100644 src/tools/jsondoclint/src/validator.rs create mode 100644 src/tools/replace-version-placeholder/Cargo.toml create mode 100644 src/tools/replace-version-placeholder/src/main.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/pretty.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs create mode 100644 src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs create mode 100644 src/tools/rust-analyzer/crates/stdx/src/hash.rs create mode 100644 src/tools/tidy/src/walk.rs create mode 100644 src/tools/unicode-table-generator/src/cascading_map.rs delete mode 100644 vendor/annotate-snippets-0.8.0/.cargo-checksum.json delete mode 100644 vendor/annotate-snippets-0.8.0/CHANGELOG.md delete mode 100644 vendor/annotate-snippets-0.8.0/Cargo.lock delete mode 100644 vendor/annotate-snippets-0.8.0/Cargo.toml delete mode 100644 vendor/annotate-snippets-0.8.0/LICENSE-APACHE delete mode 100644 vendor/annotate-snippets-0.8.0/LICENSE-MIT delete mode 100644 vendor/annotate-snippets-0.8.0/README.md delete mode 100644 vendor/annotate-snippets-0.8.0/benches/simple.rs delete mode 100644 vendor/annotate-snippets-0.8.0/examples/expected_type.rs delete mode 100644 vendor/annotate-snippets-0.8.0/examples/footer.rs delete mode 100644 vendor/annotate-snippets-0.8.0/examples/format.rs delete mode 100644 vendor/annotate-snippets-0.8.0/examples/multislice.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/mod.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/structs.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/formatter/mod.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/formatter/style.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/lib.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/snippet.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs delete mode 100644 vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs delete mode 100644 vendor/annotate-snippets-0.8.0/tests/diff/mod.rs delete mode 100644 vendor/annotate-snippets-0.8.0/tests/dl_from_snippet.rs delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.toml delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.txt delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.toml delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.txt delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.toml delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.txt delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.toml delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.txt delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.toml delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.txt delete mode 100644 vendor/annotate-snippets-0.8.0/tests/fixtures_test.rs delete mode 100644 vendor/annotate-snippets-0.8.0/tests/formatter.rs delete mode 100644 vendor/annotate-snippets-0.8.0/tests/snippet/mod.rs delete mode 100644 vendor/block-buffer-0.7.3/.cargo-checksum.json delete mode 100644 vendor/block-buffer-0.7.3/Cargo.toml delete mode 100644 vendor/block-buffer-0.7.3/LICENSE-APACHE delete mode 100644 vendor/block-buffer-0.7.3/LICENSE-MIT delete mode 100644 vendor/block-buffer-0.7.3/src/lib.rs delete mode 100644 vendor/block-padding/.cargo-checksum.json delete mode 100644 vendor/block-padding/Cargo.toml delete mode 100644 vendor/block-padding/LICENSE-APACHE delete mode 100644 vendor/block-padding/LICENSE-MIT delete mode 100644 vendor/block-padding/src/lib.rs delete mode 100644 vendor/byte-tools/.cargo-checksum.json delete mode 100644 vendor/byte-tools/Cargo.toml delete mode 100644 vendor/byte-tools/LICENSE-APACHE delete mode 100644 vendor/byte-tools/LICENSE-MIT delete mode 100644 vendor/byte-tools/src/lib.rs delete mode 100644 vendor/byteorder/.cargo-checksum.json delete mode 100644 vendor/byteorder/CHANGELOG.md delete mode 100644 vendor/byteorder/COPYING delete mode 100644 vendor/byteorder/Cargo.toml delete mode 100644 vendor/byteorder/LICENSE-MIT delete mode 100644 vendor/byteorder/README.md delete mode 100644 vendor/byteorder/UNLICENSE delete mode 100644 vendor/byteorder/benches/bench.rs delete mode 100644 vendor/byteorder/rustfmt.toml delete mode 100644 vendor/byteorder/src/io.rs delete mode 100644 vendor/byteorder/src/lib.rs delete mode 100644 vendor/clap/examples/README.md delete mode 100644 vendor/clap/examples/derive_ref/README.md create mode 100644 vendor/clap/examples/tutorial_builder/01_quick.md create mode 100644 vendor/clap/examples/tutorial_builder/02_app_settings.md create mode 100644 vendor/clap/examples/tutorial_builder/02_apps.md create mode 100644 vendor/clap/examples/tutorial_builder/02_crate.md create mode 100644 vendor/clap/examples/tutorial_builder/03_01_flag_bool.md create mode 100644 vendor/clap/examples/tutorial_builder/03_01_flag_count.md create mode 100644 vendor/clap/examples/tutorial_builder/03_02_option.md create mode 100644 vendor/clap/examples/tutorial_builder/03_03_positional.md create mode 100644 vendor/clap/examples/tutorial_builder/03_04_subcommands.md create mode 100644 vendor/clap/examples/tutorial_builder/03_05_default_values.md create mode 100644 vendor/clap/examples/tutorial_builder/04_01_enum.md create mode 100644 vendor/clap/examples/tutorial_builder/04_01_possible.md create mode 100644 vendor/clap/examples/tutorial_builder/04_02_parse.md create mode 100644 vendor/clap/examples/tutorial_builder/04_02_validate.md create mode 100644 vendor/clap/examples/tutorial_builder/04_03_relations.md create mode 100644 vendor/clap/examples/tutorial_builder/04_04_custom.md delete mode 100644 vendor/clap/examples/tutorial_builder/README.md create mode 100644 vendor/clap/examples/tutorial_derive/01_quick.md create mode 100644 vendor/clap/examples/tutorial_derive/02_app_settings.md create mode 100644 vendor/clap/examples/tutorial_derive/02_apps.md create mode 100644 vendor/clap/examples/tutorial_derive/02_crate.md create mode 100644 vendor/clap/examples/tutorial_derive/03_01_flag_bool.md create mode 100644 vendor/clap/examples/tutorial_derive/03_01_flag_count.md create mode 100644 vendor/clap/examples/tutorial_derive/03_02_option.md create mode 100644 vendor/clap/examples/tutorial_derive/03_03_positional.md create mode 100644 vendor/clap/examples/tutorial_derive/03_04_subcommands.md create mode 100644 vendor/clap/examples/tutorial_derive/03_05_default_values.md create mode 100644 vendor/clap/examples/tutorial_derive/04_01_enum.md create mode 100644 vendor/clap/examples/tutorial_derive/04_02_parse.md create mode 100644 vendor/clap/examples/tutorial_derive/04_02_validate.md create mode 100644 vendor/clap/examples/tutorial_derive/04_03_relations.md create mode 100644 vendor/clap/examples/tutorial_derive/04_04_custom.md delete mode 100644 vendor/clap/examples/tutorial_derive/README.md create mode 100644 vendor/clap/src/_cookbook/cargo_example.rs create mode 100644 vendor/clap/src/_cookbook/cargo_example_derive create mode 100644 vendor/clap/src/_cookbook/cargo_example_derive.rs create mode 100644 vendor/clap/src/_cookbook/escaped_positional.rs create mode 100644 vendor/clap/src/_cookbook/escaped_positional_derive.rs create mode 100644 vendor/clap/src/_cookbook/git.rs create mode 100644 vendor/clap/src/_cookbook/git_derive.rs create mode 100644 vendor/clap/src/_cookbook/mod.rs create mode 100644 vendor/clap/src/_cookbook/multicall_busybox.rs create mode 100644 vendor/clap/src/_cookbook/multicall_hostname.rs create mode 100644 vendor/clap/src/_cookbook/pacman.rs create mode 100644 vendor/clap/src/_cookbook/repl.rs create mode 100644 vendor/clap/src/_cookbook/typed_derive.rs create mode 100644 vendor/clap/src/_derive/_tutorial.rs create mode 100644 vendor/clap/src/_derive/mod.rs create mode 100644 vendor/clap/src/_faq.rs create mode 100644 vendor/clap/src/_features.rs create mode 100644 vendor/clap/src/_tutorial.rs delete mode 100644 vendor/crossbeam-queue/.cargo-checksum.json delete mode 100644 vendor/crossbeam-queue/CHANGELOG.md delete mode 100644 vendor/crossbeam-queue/Cargo.toml delete mode 100644 vendor/crossbeam-queue/LICENSE-APACHE delete mode 100644 vendor/crossbeam-queue/LICENSE-MIT delete mode 100644 vendor/crossbeam-queue/README.md delete mode 100644 vendor/crossbeam-queue/build.rs delete mode 100644 vendor/crossbeam-queue/no_atomic.rs delete mode 100644 vendor/crossbeam-queue/src/array_queue.rs delete mode 100644 vendor/crossbeam-queue/src/lib.rs delete mode 100644 vendor/crossbeam-queue/src/seg_queue.rs delete mode 100644 vendor/crossbeam-queue/tests/array_queue.rs delete mode 100644 vendor/crossbeam-queue/tests/seg_queue.rs delete mode 100644 vendor/crossbeam/.cargo-checksum.json delete mode 100644 vendor/crossbeam/CHANGELOG.md delete mode 100644 vendor/crossbeam/Cargo.toml delete mode 100644 vendor/crossbeam/LICENSE-APACHE delete mode 100644 vendor/crossbeam/LICENSE-MIT delete mode 100644 vendor/crossbeam/README.md delete mode 100644 vendor/crossbeam/no_atomic.rs delete mode 100644 vendor/crossbeam/src/lib.rs delete mode 100644 vendor/crossbeam/tests/subcrates.rs delete mode 100644 vendor/digest-0.8.1/.cargo-checksum.json delete mode 100644 vendor/digest-0.8.1/Cargo.toml delete mode 100644 vendor/digest-0.8.1/LICENSE-APACHE delete mode 100644 vendor/digest-0.8.1/LICENSE-MIT delete mode 100644 vendor/digest-0.8.1/src/dev.rs delete mode 100644 vendor/digest-0.8.1/src/digest.rs delete mode 100644 vendor/digest-0.8.1/src/dyn_digest.rs delete mode 100644 vendor/digest-0.8.1/src/errors.rs delete mode 100644 vendor/digest-0.8.1/src/lib.rs delete mode 100644 vendor/fake-simd/.cargo-checksum.json delete mode 100644 vendor/fake-simd/Cargo.toml delete mode 100644 vendor/fake-simd/LICENSE-APACHE delete mode 100644 vendor/fake-simd/LICENSE-MIT delete mode 100644 vendor/fake-simd/src/lib.rs delete mode 100644 vendor/fs-err/README.tpl delete mode 100644 vendor/fs-err/tests/version-numbers.rs delete mode 100644 vendor/generic-array-0.12.4/.cargo-checksum.json delete mode 100644 vendor/generic-array-0.12.4/CHANGELOG.md delete mode 100644 vendor/generic-array-0.12.4/Cargo.toml delete mode 100644 vendor/generic-array-0.12.4/LICENSE delete mode 100644 vendor/generic-array-0.12.4/README.md delete mode 100644 vendor/generic-array-0.12.4/rustfmt.toml delete mode 100644 vendor/generic-array-0.12.4/src/arr.rs delete mode 100644 vendor/generic-array-0.12.4/src/functional.rs delete mode 100644 vendor/generic-array-0.12.4/src/hex.rs delete mode 100644 vendor/generic-array-0.12.4/src/impl_serde.rs delete mode 100644 vendor/generic-array-0.12.4/src/impls.rs delete mode 100644 vendor/generic-array-0.12.4/src/iter.rs delete mode 100644 vendor/generic-array-0.12.4/src/lib.rs delete mode 100644 vendor/generic-array-0.12.4/src/sequence.rs delete mode 100644 vendor/generic-array-0.12.4/tests/arr.rs delete mode 100644 vendor/generic-array-0.12.4/tests/generics.rs delete mode 100644 vendor/generic-array-0.12.4/tests/hex.rs delete mode 100644 vendor/generic-array-0.12.4/tests/import_name.rs delete mode 100644 vendor/generic-array-0.12.4/tests/iter.rs delete mode 100644 vendor/generic-array-0.12.4/tests/mod.rs create mode 100644 vendor/handlebars/examples/helper_macro.rs create mode 100644 vendor/handlebars/tests/embed.rs create mode 100644 vendor/handlebars/tests/templates/hello.hbs create mode 100644 vendor/handlebars/tests/whitespace.rs create mode 100644 vendor/hermit-abi/src/errno.rs create mode 100644 vendor/lazycell/.cargo-checksum.json create mode 100644 vendor/lazycell/CHANGELOG.md create mode 100644 vendor/lazycell/Cargo.toml create mode 100644 vendor/lazycell/LICENSE-APACHE create mode 100644 vendor/lazycell/LICENSE-MIT create mode 100644 vendor/lazycell/README.md create mode 100644 vendor/lazycell/src/lib.rs create mode 100644 vendor/lazycell/src/serde_impl.rs create mode 100644 vendor/libc/src/unix/linux_like/android/b64/riscv64/align.rs create mode 100644 vendor/libc/src/unix/linux_like/android/b64/riscv64/mod.rs delete mode 100644 vendor/opaque-debug/.cargo-checksum.json delete mode 100644 vendor/opaque-debug/Cargo.toml delete mode 100644 vendor/opaque-debug/LICENSE-APACHE delete mode 100644 vendor/opaque-debug/LICENSE-MIT delete mode 100644 vendor/opaque-debug/src/lib.rs create mode 100644 vendor/pest_meta/src/optimizer/lister.rs delete mode 100644 vendor/pretty_assertions-0.7.2/.cargo-checksum.json delete mode 100644 vendor/pretty_assertions-0.7.2/CHANGELOG.md delete mode 100644 vendor/pretty_assertions-0.7.2/Cargo.lock delete mode 100644 vendor/pretty_assertions-0.7.2/Cargo.toml delete mode 100644 vendor/pretty_assertions-0.7.2/LICENSE-APACHE delete mode 100644 vendor/pretty_assertions-0.7.2/LICENSE-MIT delete mode 100644 vendor/pretty_assertions-0.7.2/README.md delete mode 100644 vendor/pretty_assertions-0.7.2/examples/pretty_assertion.png delete mode 100644 vendor/pretty_assertions-0.7.2/examples/pretty_assertion.rs delete mode 100644 vendor/pretty_assertions-0.7.2/examples/pretty_assertion_v0_6_1.png delete mode 100644 vendor/pretty_assertions-0.7.2/examples/standard_assertion.png delete mode 100644 vendor/pretty_assertions-0.7.2/examples/standard_assertion.rs delete mode 100755 vendor/pretty_assertions-0.7.2/scripts/check delete mode 100755 vendor/pretty_assertions-0.7.2/scripts/install delete mode 100755 vendor/pretty_assertions-0.7.2/scripts/publish delete mode 100644 vendor/pretty_assertions-0.7.2/src/lib.rs delete mode 100644 vendor/pretty_assertions-0.7.2/src/printer.rs create mode 100644 vendor/pretty_assertions/.cargo-checksum.json create mode 100644 vendor/pretty_assertions/CHANGELOG.md create mode 100644 vendor/pretty_assertions/Cargo.lock create mode 100644 vendor/pretty_assertions/Cargo.toml create mode 100644 vendor/pretty_assertions/LICENSE-APACHE create mode 100644 vendor/pretty_assertions/LICENSE-MIT create mode 100644 vendor/pretty_assertions/README.md create mode 100644 vendor/pretty_assertions/examples/pretty_assertion.png create mode 100644 vendor/pretty_assertions/examples/pretty_assertion.rs create mode 100644 vendor/pretty_assertions/examples/pretty_assertion_v0_6_1.png create mode 100644 vendor/pretty_assertions/examples/standard_assertion.png create mode 100644 vendor/pretty_assertions/examples/standard_assertion.rs create mode 100755 vendor/pretty_assertions/scripts/check create mode 100755 vendor/pretty_assertions/scripts/install create mode 100755 vendor/pretty_assertions/scripts/publish create mode 100644 vendor/pretty_assertions/src/lib.rs create mode 100644 vendor/pretty_assertions/src/printer.rs create mode 100644 vendor/proc-macro2/src/rcvec.rs delete mode 100644 vendor/quick-error-1.2.3/.cargo-checksum.json delete mode 100644 vendor/quick-error-1.2.3/Cargo.lock delete mode 100644 vendor/quick-error-1.2.3/Cargo.toml delete mode 100644 vendor/quick-error-1.2.3/LICENSE-APACHE delete mode 100644 vendor/quick-error-1.2.3/LICENSE-MIT delete mode 100644 vendor/quick-error-1.2.3/README.rst delete mode 100644 vendor/quick-error-1.2.3/bulk.yaml delete mode 100644 vendor/quick-error-1.2.3/examples/context.rs delete mode 100644 vendor/quick-error-1.2.3/src/lib.rs delete mode 100644 vendor/quick-error-1.2.3/vagga.yaml create mode 100644 vendor/redox_syscall/src/arch/x86.rs delete mode 100644 vendor/rustc_tools_util/.cargo-checksum.json delete mode 100644 vendor/rustc_tools_util/Cargo.toml delete mode 100644 vendor/rustc_tools_util/README.md delete mode 100644 vendor/rustc_tools_util/src/lib.rs delete mode 100644 vendor/sha-1-0.8.2/.cargo-checksum.json delete mode 100644 vendor/sha-1-0.8.2/Cargo.lock delete mode 100644 vendor/sha-1-0.8.2/Cargo.toml delete mode 100644 vendor/sha-1-0.8.2/LICENSE-APACHE delete mode 100644 vendor/sha-1-0.8.2/LICENSE-MIT delete mode 100644 vendor/sha-1-0.8.2/benches/lib.rs delete mode 100644 vendor/sha-1-0.8.2/examples/sha1sum.rs delete mode 100644 vendor/sha-1-0.8.2/src/aarch64.rs delete mode 100644 vendor/sha-1-0.8.2/src/consts.rs delete mode 100644 vendor/sha-1-0.8.2/src/lib.rs delete mode 100644 vendor/sha-1-0.8.2/src/utils.rs delete mode 100644 vendor/sha-1-0.8.2/tests/data/one_million_a.bin delete mode 100644 vendor/sha-1-0.8.2/tests/data/sha1.blb delete mode 100644 vendor/sha-1-0.8.2/tests/lib.rs create mode 100644 vendor/thin-vec/.cargo-checksum.json create mode 100644 vendor/thin-vec/Cargo.toml create mode 100644 vendor/thin-vec/README.md create mode 100644 vendor/thin-vec/src/lib.rs create mode 100644 vendor/thiserror/tests/ui/from-backtrace-backtrace.rs create mode 100644 vendor/thiserror/tests/ui/from-backtrace-backtrace.stderr create mode 100644 vendor/tracing/benches/baseline.rs create mode 100644 vendor/tracing/benches/dispatch_get_clone.rs create mode 100644 vendor/tracing/benches/dispatch_get_ref.rs create mode 100644 vendor/tracing/benches/empty_span.rs create mode 100644 vendor/tracing/benches/enter_span.rs create mode 100644 vendor/tracing/benches/event.rs delete mode 100644 vendor/tracing/benches/global_subscriber.rs delete mode 100644 vendor/tracing/benches/no_subscriber.rs create mode 100644 vendor/tracing/benches/shared.rs create mode 100644 vendor/tracing/benches/span_fields.rs create mode 100644 vendor/tracing/benches/span_no_fields.rs create mode 100644 vendor/tracing/benches/span_repeated.rs delete mode 100644 vendor/tracing/benches/subscriber.rs delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/.cargo-checksum.json delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/CODE_OF_CONDUCT.md delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/CONTRIBUTING.md delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/Cargo.toml delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/LICENSE-APACHE delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/LICENSE-MIT delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/ORG_CODE_OF_CONDUCT.md delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/README.md delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/SECURITY.md delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/src/error.rs delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/src/lib.rs delete mode 100644 vendor/wasi-0.10.2+wasi-snapshot-preview1/src/lib_generated.rs diff --git a/Cargo.lock b/Cargo.lock index 2569b3e19..fda523611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,15 +79,9 @@ dependencies = [ "maplit", "once_cell", "tendril", - "url 2.2.2", + "url", ] -[[package]] -name = "annotate-snippets" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" - [[package]] name = "annotate-snippets" version = "0.9.1" @@ -109,9 +103,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.60" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "array_tool" @@ -215,34 +209,13 @@ dependencies = [ "typenum", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -263,7 +236,6 @@ dependencies = [ "anyhow", "flate2", "hex 0.4.2", - "num_cpus", "rayon", "serde", "serde_json", @@ -284,12 +256,6 @@ dependencies = [ "toml", ] -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytecount" version = "0.6.2" @@ -299,12 +265,6 @@ dependencies = [ "packed_simd_2", ] -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - [[package]] name = "bytes" version = "1.0.1" @@ -328,7 +288,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.65.0" +version = "0.66.0" dependencies = [ "anyhow", "atty", @@ -339,7 +299,6 @@ dependencies = [ "cargo-util", "clap", "crates-io", - "crossbeam-utils", "curl", "curl-sys", "env_logger 0.9.0", @@ -363,12 +322,11 @@ dependencies = [ "libgit2-sys", "log", "memchr", - "num_cpus", "opener", "openssl", "os_info", "pathdiff", - "percent-encoding 2.1.0", + "percent-encoding", "pretty_env_logger", "rustc-workspace-hack", "rustfix", @@ -385,7 +343,7 @@ dependencies = [ "toml_edit", "unicode-width", "unicode-xid", - "url 2.2.2", + "url", "walkdir", "winapi", ] @@ -423,6 +381,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ + "cargo_metadata 0.15.0", "directories", "rustc-workspace-hack", "rustc_version", @@ -470,12 +429,13 @@ dependencies = [ "tar", "termcolor", "toml_edit", - "url 2.2.2", + "url", + "winapi", ] [[package]] name = "cargo-util" -version = "0.2.1" +version = "0.2.2" dependencies = [ "anyhow", "core-foundation", @@ -525,9 +485,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -617,9 +577,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.5" +version = "3.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7" +checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" dependencies = [ "atty", "bitflags", @@ -643,9 +603,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.5" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -665,14 +625,14 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.64" +version = "0.1.65" dependencies = [ "clippy_lints", "clippy_utils", "compiletest_rs", "derive-new", "filetime", - "futures 0.3.19", + "futures", "if_chain", "itertools", "parking_lot 0.12.1", @@ -680,7 +640,7 @@ dependencies = [ "regex", "rustc-semver", "rustc-workspace-hack", - "rustc_tools_util 0.2.0", + "rustc_tools_util", "semver", "serde", "syn", @@ -708,7 +668,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" dependencies = [ "cargo_metadata 0.14.0", "clippy_utils", @@ -725,15 +685,16 @@ dependencies = [ "toml", "unicode-normalization", "unicode-script", - "url 2.2.2", + "url", ] [[package]] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" dependencies = [ "arrayvec", "if_chain", + "itertools", "rustc-semver", ] @@ -777,9 +738,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.3" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -805,9 +766,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.73" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3" +checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca" dependencies = [ "cc", "rustc-std-workspace-core", @@ -822,6 +783,7 @@ dependencies = [ "getopts", "glob", "lazy_static", + "lazycell", "libc", "miow", "regex", @@ -927,10 +889,10 @@ version = "0.34.0" dependencies = [ "anyhow", "curl", - "percent-encoding 2.1.0", + "percent-encoding", "serde", "serde_json", - "url 2.2.2", + "url", ] [[package]] @@ -1016,7 +978,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] @@ -1041,16 +1003,6 @@ dependencies = [ "quote", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "curl" version = "0.4.43" @@ -1099,17 +1051,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "0.99.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298998b1cf6b5b2c8a7b023dfd45821825ce3ba8a8af55c921a0e734e4653f76" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "diff" version = "0.1.13" @@ -1122,22 +1063,13 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" dependencies = [ - "block-buffer 0.10.2", + "block-buffer", "crypto-common", ] @@ -1285,8 +1217,7 @@ dependencies = [ name = "error_index_generator" version = "0.0.0" dependencies = [ - "rustdoc", - "walkdir", + "mdbook", ] [[package]] @@ -1317,12 +1248,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1422,14 +1347,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] name = "fortanix-sgx-abi" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6" +checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -1437,9 +1362,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.5.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431" +checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" [[package]] name = "fs_extra" @@ -1447,12 +1372,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" -[[package]] -name = "fst" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d79238883cf0307100b90aba4a755d8051a3182305dfe7f649a1e9dc0517006f" - [[package]] name = "futf" version = "0.1.5" @@ -1463,12 +1382,6 @@ dependencies = [ "new_debug_unreachable", ] -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.19" @@ -1509,7 +1422,6 @@ dependencies = [ "futures-core", "futures-task", "futures-util", - "num_cpus", ] [[package]] @@ -1547,7 +1459,6 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ - "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -1570,15 +1481,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.4" @@ -1658,9 +1560,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" +checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1" dependencies = [ "bitflags", "libc", @@ -1668,19 +1570,19 @@ dependencies = [ "log", "openssl-probe", "openssl-sys", - "url 2.2.2", + "url", ] [[package]] name = "git2-curl" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13" +checksum = "ed817a00721e2f8037ba722e60358d4956dae9cca10315fc982f967907d3b0cd" dependencies = [ "curl", "git2", "log", - "url 2.2.2", + "url", ] [[package]] @@ -1713,16 +1615,16 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.1.0" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a0ffab8c36d0436114310c7e10b59b3307e650ddfabf6d006028e29a70c6e6" +checksum = "360d9740069b2f6cbb63ce2dbaa71a20d3185350cbb990d7bebeb9318415eb17" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.0", "serde", "serde_json", + "thiserror", ] [[package]] @@ -1754,12 +1656,13 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.0" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "compiler_builtins", "libc", + "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -1812,7 +1715,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3", + "quick-error", ] [[package]] @@ -1821,17 +1724,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.2.0" @@ -1869,13 +1761,13 @@ dependencies = [ [[package]] name = "im-rc" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" dependencies = [ "bitmaps", - "rand_core 0.5.1", - "rand_xoshiro 0.4.0", + "rand_core 0.6.2", + "rand_xoshiro", "sized-chunks", "typenum", "version_check", @@ -1986,12 +1878,6 @@ dependencies = [ "libc", ] -[[package]] -name = "json" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" - [[package]] name = "jsondocck" version = "0.1.0" @@ -2006,122 +1892,28 @@ dependencies = [ ] [[package]] -name = "jsonpath_lib" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61352ec23883402b7d30b3313c16cbabefb8907361c4eb669d990cbb87ceee5a" -dependencies = [ - "array_tool", - "env_logger 0.7.1", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "jsonrpc-client-transports" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" +name = "jsondoclint" +version = "0.1.0" dependencies = [ - "derive_more", - "futures 0.3.19", - "jsonrpc-core", - "jsonrpc-pubsub", - "jsonrpc-server-utils", - "log", - "parity-tokio-ipc", - "serde", + "anyhow", + "fs-err", + "rustdoc-json-types", "serde_json", - "tokio", - "url 1.7.2", ] [[package]] -name = "jsonrpc-core" -version = "18.0.0" +name = "jsonpath_lib" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +checksum = "61352ec23883402b7d30b3313c16cbabefb8907361c4eb669d990cbb87ceee5a" dependencies = [ - "futures 0.3.19", - "futures-executor", - "futures-util", + "array_tool", + "env_logger 0.7.1", "log", "serde", - "serde_derive", "serde_json", ] -[[package]] -name = "jsonrpc-core-client" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" -dependencies = [ - "futures 0.3.19", - "jsonrpc-client-transports", -] - -[[package]] -name = "jsonrpc-derive" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jsonrpc-ipc-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" -dependencies = [ - "futures 0.3.19", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "parity-tokio-ipc", - "parking_lot 0.11.2", - "tower-service", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" -dependencies = [ - "futures 0.3.19", - "jsonrpc-core", - "lazy_static", - "log", - "parking_lot 0.11.2", - "rand 0.7.3", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" -dependencies = [ - "bytes", - "futures 0.3.19", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "tokio", - "tokio-stream", - "tokio-util", - "unicase", -] - [[package]] name = "kstring" version = "2.0.0" @@ -2145,18 +1937,37 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40" dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "libffi" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" +dependencies = [ + "cc", +] + [[package]] name = "libgit2-sys" -version = "0.13.2+1.4.2" +version = "0.14.0+1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" +checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b" dependencies = [ "cc", "libc", @@ -2264,30 +2075,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "lsp-codec" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa939d0b62476a5a19fb7fcb423a5c6ce8c7e09b851d37531e2fe3e0e6d9d257" -dependencies = [ - "bytes", - "serde_json", - "tokio-util", -] - -[[package]] -name = "lsp-types" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3edefcd66dde1f7f1df706f46520a3c93adc5ca4bc5747da6621195e894efd" -dependencies = [ - "bitflags", - "serde", - "serde_json", - "serde_repr", - "url 2.2.2", -] - [[package]] name = "lzma-sys" version = "0.1.16" @@ -2346,7 +2133,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" dependencies = [ - "digest 0.10.2", + "digest", ] [[package]] @@ -2421,9 +2208,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac96d1e7a65f206443f95afff6de8f1690c77c97d6fc9c9bb2d2cd0662e9ff9f" +checksum = "8eb022374af2f446981254e6bf9efb6e2c9e1a53176d395fca02792fd4435729" [[package]] name = "minimal-lexical" @@ -2452,19 +2239,6 @@ dependencies = [ "adler 1.0.2", ] -[[package]] -name = "mio" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - [[package]] name = "miow" version = "0.3.7" @@ -2483,6 +2257,8 @@ dependencies = [ "getrandom 0.2.0", "lazy_static", "libc", + "libffi", + "libloading", "log", "measureme", "rand 0.8.5", @@ -2516,15 +2292,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", -] - [[package]] name = "num-integer" version = "0.1.43" @@ -2594,12 +2361,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opener" version = "0.5.0" @@ -2653,17 +2414,11 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordslice" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" - [[package]] name = "os_info" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" +checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399" dependencies = [ "log", "serde", @@ -2676,15 +2431,6 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.4.0" @@ -2724,20 +2470,6 @@ dependencies = [ "unwind", ] -[[package]] -name = "parity-tokio-ipc" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" -dependencies = [ - "futures 0.3.19", - "libc", - "log", - "rand 0.7.3", - "tokio", - "winapi", -] - [[package]] name = "parking_lot" version = "0.11.2" @@ -2792,12 +2524,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -2815,18 +2541,19 @@ dependencies = [ [[package]] name = "pest" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" dependencies = [ "pest", "pest_generator", @@ -2834,9 +2561,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" dependencies = [ "pest", "pest_meta", @@ -2847,13 +2574,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1 0.8.2", + "sha-1", ] [[package]] @@ -2945,18 +2672,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -2967,15 +2682,6 @@ dependencies = [ "log", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3064,12 +2770,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" - [[package]] name = "quine-mc_cluskey" version = "0.2.4" @@ -3085,37 +2785,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "racer" -version = "2.2.2" -dependencies = [ - "bitflags", - "derive_more", - "env_logger 0.7.1", - "humantime 2.0.1", - "lazy_static", - "lazycell", - "log", - "racer-cargo-metadata", - "rls-span", -] - -[[package]] -name = "racer-cargo-metadata" -version = "0.1.2" -dependencies = [ - "racer-interner", - "serde", - "serde_json", -] - -[[package]] -name = "racer-interner" -version = "0.1.0" -dependencies = [ - "serde", -] - [[package]] name = "rand" version = "0.7.3" @@ -3196,15 +2865,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_xoshiro" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -3301,68 +2961,18 @@ dependencies = [ ] [[package]] -name = "rls" -version = "1.41.0" +name = "replace-version-placeholder" +version = "0.1.0" dependencies = [ - "anyhow", - "cargo", - "cargo-util", - "cargo_metadata 0.14.0", - "clippy_lints", - "crossbeam-channel", - "difference", - "env_logger 0.9.0", - "futures 0.3.19", - "heck", - "home", - "itertools", - "jsonrpc-core", - "lazy_static", - "log", - "lsp-codec", - "lsp-types", - "num_cpus", - "ordslice", - "racer", - "rand 0.8.5", - "rayon", - "regex", - "rls-analysis", - "rls-data", - "rls-ipc", - "rls-rustc", - "rls-span", - "rls-vfs", - "rustc-workspace-hack", - "rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly", - "serde", - "serde_derive", - "serde_ignored", - "serde_json", - "tempfile", - "tokio", - "tokio-stream", - "tokio-util", - "toml", - "toml_edit", - "url 2.2.2", + "tidy", "walkdir", ] [[package]] -name = "rls-analysis" -version = "0.18.3" +name = "rls" +version = "2.0.0" dependencies = [ - "derive-new", - "env_logger 0.9.0", - "fst", - "itertools", - "json", - "lazy_static", - "log", - "rls-data", - "rls-span", + "rustc-workspace-hack", "serde", "serde_json", ] @@ -3377,33 +2987,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rls-ipc" -version = "0.1.0" -dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-ipc-server", - "rls-data", - "serde", -] - -[[package]] -name = "rls-rustc" -version = "0.6.0" -dependencies = [ - "clippy_lints", - "env_logger 0.9.0", - "futures 0.3.19", - "log", - "rand 0.8.5", - "rls-data", - "rls-ipc", - "serde", - "tokio", -] - [[package]] name = "rls-span" version = "0.5.3" @@ -3413,16 +2996,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rls-vfs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce4b57b25b4330ed5ec14028fc02141e083ddafda327e7eb598dc0569c8c83c9" -dependencies = [ - "log", - "rls-span", -] - [[package]] name = "rust-demangler" version = "0.0.1" @@ -3522,21 +3095,12 @@ name = "rustc-workspace-hack" version = "1.0.0" dependencies = [ "bstr", - "byteorder", "clap", - "crossbeam-utils", - "libc", "libz-sys", - "memchr", - "proc-macro2", - "quote", - "rand_core 0.5.1", "regex", - "serde", "serde_json", - "smallvec", "syn", - "url 2.2.2", + "url", "winapi", ] @@ -3567,6 +3131,7 @@ dependencies = [ "rustc_serialize", "rustc_span", "smallvec", + "thin-vec", "tracing", ] @@ -3581,12 +3146,14 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", "smallvec", + "thin-vec", "tracing", ] @@ -3601,6 +3168,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_macros", "rustc_parse", "rustc_session", "rustc_span", @@ -3680,6 +3248,7 @@ dependencies = [ "rustc_span", "rustc_target", "smallvec", + "thin-vec", "tracing", ] @@ -3692,6 +3261,7 @@ dependencies = [ "libc", "libloading", "measureme", + "object 0.29.0", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3727,7 +3297,6 @@ dependencies = [ "object 0.29.0", "pathdiff", "regex", - "rustc_apfloat", "rustc_arena", "rustc_ast", "rustc_attr", @@ -3804,6 +3373,7 @@ dependencies = [ "stable_deref_trait", "stacker", "tempfile", + "thin-vec", "tracing", "winapi", ] @@ -3825,6 +3395,7 @@ dependencies = [ "rustc_interface", "rustc_lint", "rustc_log", + "rustc_macros", "rustc_metadata", "rustc_middle", "rustc_parse", @@ -3862,7 +3433,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.8.0", + "annotate-snippets", "atty", "rustc_data_structures", "rustc_error_messages", @@ -3871,6 +3442,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "rustc_target", "serde", "serde_json", "termcolor", @@ -3988,6 +3560,7 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_serialize", + "rustc_session", "rustc_span", "rustc_target", "smallvec", @@ -4017,6 +3590,7 @@ dependencies = [ "rustc_hir", "rustc_incremental", "rustc_lint", + "rustc_macros", "rustc_metadata", "rustc_middle", "rustc_mir_build", @@ -4114,7 +3688,7 @@ dependencies = [ name = "rustc_macros" version = "0.1.0" dependencies = [ - "annotate-snippets 0.8.0", + "annotate-snippets", "fluent-bundle", "fluent-syntax", "proc-macro2", @@ -4162,7 +3736,7 @@ dependencies = [ "gsgdt", "polonius-engine", "rand 0.8.5", - "rand_xoshiro 0.6.0", + "rand_xoshiro", "rustc-rayon", "rustc-rayon-core", "rustc_apfloat", @@ -4183,6 +3757,7 @@ dependencies = [ "rustc_target", "rustc_type_ir", "smallvec", + "thin-vec", "tracing", ] @@ -4217,11 +3792,14 @@ dependencies = [ "regex", "rustc_ast", "rustc_data_structures", + "rustc_errors", "rustc_graphviz", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_middle", "rustc_serialize", + "rustc_session", "rustc_span", "rustc_target", "smallvec", @@ -4257,8 +3835,10 @@ name = "rustc_monomorphize" version = "0.0.0" dependencies = [ "rustc_data_structures", + "rustc_errors", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4325,6 +3905,7 @@ dependencies = [ "rustc_ast", "rustc_errors", "rustc_lint", + "rustc_macros", "rustc_metadata", "rustc_session", "rustc_span", @@ -4365,6 +3946,8 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", + "rustc_target", + "thin-vec", "tracing", ] @@ -4386,7 +3969,9 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", + "thin-vec", "tracing", ] @@ -4423,9 +4008,11 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", + "rustc_errors", "rustc_hir", "rustc_hir_pretty", "rustc_lexer", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4440,6 +4027,7 @@ dependencies = [ "indexmap", "rustc_macros", "smallvec", + "thin-vec", ] [[package]] @@ -4447,7 +4035,6 @@ name = "rustc_session" version = "0.0.0" dependencies = [ "getopts", - "num_cpus", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4489,7 +4076,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "scoped-tls", - "sha-1 0.10.0", + "sha-1", "sha2", "tracing", "unicode-width", @@ -4503,7 +4090,9 @@ dependencies = [ "punycode", "rustc-demangle", "rustc_data_structures", + "rustc_errors", "rustc_hir", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4529,12 +4118,6 @@ dependencies = [ name = "rustc_tools_util" version = "0.2.0" -[[package]] -name = "rustc_tools_util" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" - [[package]] name = "rustc_trait_selection" version = "0.0.0" @@ -4585,6 +4168,7 @@ version = "0.1.0" dependencies = [ "itertools", "rustc_data_structures", + "rustc_hir", "rustc_infer", "rustc_macros", "rustc_middle", @@ -4602,6 +4186,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4632,6 +4217,7 @@ dependencies = [ "rustc_attr", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_graphviz", "rustc_hir", "rustc_hir_pretty", @@ -4679,6 +4265,7 @@ dependencies = [ "serde_json", "smallvec", "tempfile", + "thin-vec", "tracing", "tracing-subscriber", "tracing-tree", @@ -4729,7 +4316,7 @@ dependencies = [ name = "rustfmt-nightly" version = "1.5.1" dependencies = [ - "annotate-snippets 0.9.1", + "annotate-snippets", "anyhow", "bytecount", "cargo_metadata 0.14.0", @@ -4839,18 +4426,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", @@ -4868,9 +4455,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "indexmap", "itoa", @@ -4878,29 +4465,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_repr" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug", -] - [[package]] name = "sha-1" version = "0.10.0" @@ -4909,7 +4473,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.2", + "digest", ] [[package]] @@ -4920,7 +4484,7 @@ checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.2", + "digest", ] [[package]] @@ -4944,15 +4508,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - [[package]] name = "similar" version = "2.1.0" @@ -4995,9 +4550,9 @@ checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" [[package]] name = "snapbox" -version = "0.2.9" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f212b806d6f56d19838e36a0aaa7e79a0bc9ca177e873fb87651ad92f983e2" +checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7" dependencies = [ "concolor", "content_inspector", @@ -5013,9 +4568,9 @@ dependencies = [ [[package]] name = "snapbox-macros" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930" +checksum = "8a253e6f894cfa440cba00600a249fa90869d8e0ec45ab274a456e043a0ce8f2" [[package]] name = "socket2" @@ -5064,7 +4619,7 @@ dependencies = [ "dlmalloc", "fortanix-sgx-abi", "hashbrown", - "hermit-abi 0.2.0", + "hermit-abi 0.2.6", "libc", "miniz_oxide 0.4.0", "object 0.26.2", @@ -5252,20 +4807,26 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "thin-vec" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104c2cb3180b6fb6d5b2278768e9b88b578d32ba751ea6e8d026688a40d7ed87" + [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" dependencies = [ "proc-macro2", "quote", @@ -5298,7 +4859,6 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo_metadata 0.14.0", - "crossbeam-utils", "lazy_static", "regex", "walkdir", @@ -5338,39 +4898,8 @@ checksum = "50dae83881bc9b0403dd5b44ea9deed3e939856cc8722d5be37f0d6e5c6d53dd" dependencies = [ "autocfg", "bytes", - "libc", "memchr", - "mio", - "num_cpus", - "once_cell", "pin-project-lite", - "signal-hook-registry", - "winapi", -] - -[[package]] -name = "tokio-stream" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", ] [[package]] @@ -5401,17 +4930,11 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c" -[[package]] -name = "tower-service" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" - [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -5421,9 +4944,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -5432,11 +4955,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] @@ -5525,14 +5049,16 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "ui_test" -version = "0.1.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" dependencies = [ "cargo_metadata 0.15.0", "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", @@ -5730,17 +5256,6 @@ dependencies = [ "libc", ] -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.2" @@ -5748,9 +5263,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.2.0", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", "serde", ] @@ -5766,6 +5281,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.10" diff --git a/Cargo.toml b/Cargo.toml index ffc886d47..e49fe5e2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,10 @@ members = [ "src/tools/unicode-table-generator", "src/tools/expand-yaml-anchors", "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/html-checker", "src/tools/bump-stage0", + "src/tools/replace-version-placeholder", "src/tools/lld-wrapper", ] @@ -96,21 +98,6 @@ gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 -# We want the RLS to use the version of Cargo that we've got vendored in this -# repository to ensure that the same exact version of Cargo is used by both the -# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository -# so we use a `[patch]` here to override the github repository with our local -# vendored copy. -[patch."https://github.com/rust-lang/cargo"] -cargo = { path = "src/tools/cargo" } -cargo-util = { path = "src/tools/cargo/crates/cargo-util" } - -[patch."https://github.com/rust-lang/rustfmt"] -# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt` -# that we're shipping as well (to ensure that the rustfmt in RLS and the -# `rustfmt` executable are the same exact version). -rustfmt-nightly = { path = "src/tools/rustfmt" } - [patch.crates-io] # See comments in `src/tools/rustc-workspace-hack/README.md` for what's going on # here diff --git a/README.md b/README.md index 7f601d5ee..27e7145c5 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Read ["Installation"] from [The Book]. ## Installing from Source The Rust build system uses a Python script called `x.py` to build the compiler, -which manages the bootstrapping process. It lives in the root of the project. +which manages the bootstrapping process. It lives at the root of the project. The `x.py` command can be run directly on most systems in the following format: @@ -32,7 +32,7 @@ The `x.py` command can be run directly on most systems in the following format: This is how the documentation and examples assume you are running `x.py`. -Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself: +Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case, you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself: ```sh # Python 3 @@ -83,7 +83,7 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide If you plan to use `x.py install` to create an installation, it is recommended that you set the `prefix` value in the `[install]` section to a directory. - Create install directory if you are not installing in default directory. + Create an install directory if you are not installing in the default directory. 4. Build and install: @@ -103,11 +103,10 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide ### Building on Windows There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by -Visual Studio, and the GNU ABI used by the GCC toolchain. Which version of Rust -you need depends largely on what C/C++ libraries you want to interoperate with: -for interop with software produced by Visual Studio use the MSVC build of Rust; -for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU -build. +Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust +you need depends largely on what C/C++ libraries you want to interoperate with. +Use the MSVC build of Rust to interop with software produced by Visual Studio and +the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain. #### MinGW @@ -115,10 +114,10 @@ build. [msys2]: https://www.msys2.org/ -1. Grab the latest [MSYS2 installer][msys2] and go through the installer. +1. Download the latest [MSYS2 installer][msys2] and go through the installer. -2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed - MSYS2 (i.e. `C:\msys64`), depending on whether you want 32-bit or 64-bit +2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation + directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead) @@ -153,7 +152,7 @@ build. #### MSVC MSVC builds of Rust additionally require an installation of Visual Studio 2017 -(or later) so `rustc` can use its linker. The simplest way is to get the +(or later) so `rustc` can use its linker. The simplest way is to get [Visual Studio], check the “C++ build tools†and “Windows 10 SDK†workload. [Visual Studio]: https://visualstudio.microsoft.com/downloads/ @@ -168,7 +167,7 @@ shell with: python x.py build ``` -Currently, building Rust only works with some known versions of Visual Studio. If +Right now, building Rust only works with some known versions of Visual Studio. If you have a more recent version installed and the build system doesn't understand, you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. @@ -225,7 +224,7 @@ the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will Since the Rust compiler is written in Rust, it must be built by a precompiled "snapshot" version of itself (made in an earlier stage of -development). As such, source builds require a connection to the Internet, to +development). As such, source builds require an Internet connection to fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: diff --git a/RELEASES.md b/RELEASES.md index 694bd0965..a3df56f1d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,106 @@ +Version 1.65.0 (2022-11-03) +========================== + +Language +-------- +- [Error on `as` casts of enums with `#[non_exhaustive]` variants](https://github.com/rust-lang/rust/pull/92744/) +- [Stabilize `let else`](https://github.com/rust-lang/rust/pull/93628/) +- [Stabilize generic associated types (GATs)](https://github.com/rust-lang/rust/pull/96709/) +- [Add lints `let_underscore_drop`, `let_underscore_lock`, and `let_underscore_must_use` from Clippy](https://github.com/rust-lang/rust/pull/97739/) +- [Stabilize `break`ing from arbitrary labeled blocks ("label-break-value")](https://github.com/rust-lang/rust/pull/99332/) +- [Uninitialized integers, floats, and raw pointers are now considered immediate UB](https://github.com/rust-lang/rust/pull/98919/). + Usage of `MaybeUninit` is the correct way to work with uninitialized memory. +- [Stabilize raw-dylib for Windows x86_64, aarch64, and thumbv7a](https://github.com/rust-lang/rust/pull/99916/) +- [Do not allow `Drop` impl on foreign ADTs](https://github.com/rust-lang/rust/pull/99576/) + +Compiler +-------- +- [Stabilize -Csplit-debuginfo on Linux](https://github.com/rust-lang/rust/pull/98051/) +- [Use niche-filling optimization even when multiple variants have data](https://github.com/rust-lang/rust/pull/94075/) +- [Associated type projections are now verified to be well-formed prior to resolving the underlying type](https://github.com/rust-lang/rust/pull/99217/#issuecomment-1209365630) +- [Stringify non-shorthand visibility correctly](https://github.com/rust-lang/rust/pull/100350/) +- [Normalize struct field types when unsizing](https://github.com/rust-lang/rust/pull/101831/) +- [Update to LLVM 15](https://github.com/rust-lang/rust/pull/99464/) +- [Fix aarch64 call abi to correctly zeroext when needed](https://github.com/rust-lang/rust/pull/97800/) +- [debuginfo: Generalize C++-like encoding for enums](https://github.com/rust-lang/rust/pull/98393/) +- [Add `special_module_name` lint](https://github.com/rust-lang/rust/pull/94467/) +- [Add support for generating unique profraw files by default when using `-C instrument-coverage`](https://github.com/rust-lang/rust/pull/100384/) +- [Allow dynamic linking for iOS/tvOS targets](https://github.com/rust-lang/rust/pull/100636/) + +New targets: + +- [Add armv4t-none-eabi as a tier 3 target](https://github.com/rust-lang/rust/pull/100244/) +- [Add powerpc64-unknown-openbsd and riscv64-unknown-openbsd as tier 3 targets](https://github.com/rust-lang/rust/pull/101025/) + - Refer to Rust's [platform support page][platform-support-doc] for more + information on Rust's tiered platform support. + +Libraries +--------- + +- [Don't generate `PartialEq::ne` in derive(PartialEq)](https://github.com/rust-lang/rust/pull/98655/) +- [Windows RNG: Use `BCRYPT_RNG_ALG_HANDLE` by default](https://github.com/rust-lang/rust/pull/101325/) +- [Forbid mixing `System` with direct system allocator calls](https://github.com/rust-lang/rust/pull/101394/) +- [Document no support for writing to non-blocking stdio/stderr](https://github.com/rust-lang/rust/pull/101416/) +- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295) + This also changes the safety conditions on `Layout::from_size_align_unchecked`. + +Stabilized APIs +--------------- + +- [`std::backtrace::Backtrace`](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html) +- [`Bound::as_ref`](https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.as_ref) +- [`std::io::read_to_string`](https://doc.rust-lang.org/stable/std/io/fn.read_to_string.html) +- [`<*const T>::cast_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_mut) +- [`<*mut T>::cast_const`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_const) + +These APIs are now stable in const contexts: + +- [`<*const T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from) +- [`<*mut T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from) + +Cargo +----- + +- [Apply GitHub fast path even for partial hashes](https://github.com/rust-lang/cargo/pull/10807/) +- [Do not add home bin path to PATH if it's already there](https://github.com/rust-lang/cargo/pull/11023/) +- [Take priority into account within the pending queue](https://github.com/rust-lang/cargo/pull/11032/). + This slightly optimizes job scheduling by Cargo, with typically small improvements on larger crate graph builds. + +Compatibility Notes +------------------- + +- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295). + This also changes the safety conditions on `Layout::from_size_align_unchecked`. +- [`PollFn` now only implements `Unpin` if the closure is `Unpin`](https://github.com/rust-lang/rust/pull/102737). + This is a possible breaking change if users were relying on the blanket unpin implementation. + See discussion on the PR for details of why this change was made. +- [Drop ExactSizeIterator impl from std::char::EscapeAscii](https://github.com/rust-lang/rust/pull/99880) + This is a backwards-incompatible change to the standard library's surface + area, but is unlikely to affect real world usage. +- [Do not consider a single repeated lifetime eligible for elision in the return type](https://github.com/rust-lang/rust/pull/103450) + This behavior was unintentionally changed in 1.64.0, and this release reverts that change by making this an error again. +- [Reenable disabled early syntax gates as future-incompatibility lints](https://github.com/rust-lang/rust/pull/99935/) +- [Update the minimum external LLVM to 13](https://github.com/rust-lang/rust/pull/100460/) +- [Don't duplicate file descriptors into stdio fds](https://github.com/rust-lang/rust/pull/101426/) +- [Sunset RLS](https://github.com/rust-lang/rust/pull/100863/) +- [Deny usage of `#![cfg_attr(..., crate_type = ...)]` to set the crate type](https://github.com/rust-lang/rust/pull/99784/) + This strengthens the forward compatibility lint deprecated_cfg_attr_crate_type_name to deny. +- [`llvm-has-rust-patches` allows setting the build system to treat the LLVM as having Rust-specific patches](https://github.com/rust-lang/rust/pull/101072) + This option may need to be set for distributions that are building Rust with a patched LLVM via `llvm-config`, not the built-in LLVM. + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Add `x.sh` and `x.ps1` shell scripts](https://github.com/rust-lang/rust/pull/99992/) +- [compiletest: use target cfg instead of hard-coded tables](https://github.com/rust-lang/rust/pull/100260/) +- [Use object instead of LLVM for reading bitcode from rlibs](https://github.com/rust-lang/rust/pull/98100/) +- [Enable MIR inlining for optimized compilations](https://github.com/rust-lang/rust/pull/91743) + This provides a 3-10% improvement in compiletimes for real world crates. See [perf results](https://perf.rust-lang.org/compare.html?start=aedf78e56b2279cc869962feac5153b6ba7001ed&end=0075bb4fad68e64b6d1be06bf2db366c30bc75e1&stat=instructions:u). + Version 1.64.0 (2022-09-22) =========================== diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index cfc3d5b15..dde368e7b 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -33,6 +33,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate alloc; diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a5f1cbc96..46dbbd83d 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -16,10 +16,12 @@ #![feature(maybe_uninit_slice)] #![feature(min_specialization)] #![feature(decl_macro)] +#![feature(pointer_byte_offsets)] #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] -#![feature(ptr_const_cast)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use smallvec::SmallVec; @@ -210,7 +212,7 @@ impl TypedArena { unsafe { if mem::size_of::() == 0 { - self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T); + 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); @@ -218,7 +220,7 @@ impl TypedArena { } else { let ptr = self.ptr.get(); // Advance the pointer. - self.ptr.set(self.ptr.get().offset(1)); + self.ptr.set(self.ptr.get().add(1)); // Write into uninitialized memory. ptr::write(ptr, object); &mut *ptr diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 9822e9864..c24180bac 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,12 +7,13 @@ edition = "2021" doctest = false [dependencies] -rustc_serialize = { path = "../rustc_serialize" } -tracing = "0.1" -rustc_span = { path = "../rustc_span" } +bitflags = "1.2.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -bitflags = "1.2.1" +thin-vec = "0.2.8" +tracing = "0.1" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 870a7c0be..d86db8f8b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -24,22 +24,19 @@ pub use UnsafeSource::*; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter}; -use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream}; - +use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::thin_vec::ThinVec; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; - -use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; use std::mem; +use thin_vec::ThinVec; /// A "Label" is an identifier of some point in sources, /// e.g. in the following code: @@ -94,7 +91,7 @@ pub struct Path { /// The segments in the path: the things separated by `::`. /// Global paths begin with `kw::PathRoot`. pub segments: Vec, - pub tokens: Option, + pub tokens: Option, } impl PartialEq for Path { @@ -326,46 +323,17 @@ pub type GenericBounds = Vec; /// Specifies the enforced ordering for generic parameters. In the future, /// if we wanted to relax this order, we could override `PartialEq` and /// `PartialOrd`, to allow the kinds to be unordered. -#[derive(Hash, Clone, Copy)] +#[derive(Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum ParamKindOrd { Lifetime, - Type, - Const, - // `Infer` is not actually constructed directly from the AST, but is implicitly constructed - // during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last. - Infer, -} - -impl Ord for ParamKindOrd { - fn cmp(&self, other: &Self) -> Ordering { - use ParamKindOrd::*; - let to_int = |v| match v { - Lifetime => 0, - Infer | Type | Const => 1, - }; - - to_int(*self).cmp(&to_int(*other)) - } -} -impl PartialOrd for ParamKindOrd { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + TypeOrConst, } -impl PartialEq for ParamKindOrd { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl Eq for ParamKindOrd {} impl fmt::Display for ParamKindOrd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ParamKindOrd::Lifetime => "lifetime".fmt(f), - ParamKindOrd::Type => "type".fmt(f), - ParamKindOrd::Const { .. } => "const".fmt(f), - ParamKindOrd::Infer => "infer".fmt(f), + ParamKindOrd::TypeOrConst => "type and const".fmt(f), } } } @@ -497,7 +465,6 @@ pub struct WhereRegionPredicate { /// E.g., `T = int`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WhereEqPredicate { - pub id: NodeId, pub span: Span, pub lhs_ty: P, pub rhs_ty: P, @@ -505,7 +472,7 @@ pub struct WhereEqPredicate { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Crate { - pub attrs: Vec, + pub attrs: AttrVec, pub items: Vec>, pub spans: ModSpans, /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold @@ -567,7 +534,7 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, - pub tokens: Option, + pub tokens: Option, /// The following *isn't* a parse error, but will cause multiple errors in following stages. /// ```compile_fail /// let x = { @@ -586,7 +553,7 @@ pub struct Pat { pub id: NodeId, pub kind: PatKind, pub span: Span, - pub tokens: Option, + pub tokens: Option, } impl Pat { @@ -597,7 +564,7 @@ impl Pat { // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. - PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, ident, None) => { TyKind::Path(None, Path::from_ident(*ident)) } PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), @@ -684,10 +651,43 @@ pub struct PatField { pub is_placeholder: bool, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] -pub enum BindingMode { - ByRef(Mutability), - ByValue(Mutability), +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub enum ByRef { + Yes, + No, +} + +impl From for ByRef { + fn from(b: bool) -> ByRef { + match b { + false => ByRef::No, + true => ByRef::Yes, + } + } +} + +/// Explicit binding annotations given in the HIR for a binding. Note +/// that this is not the final binding *mode* that we infer after type +/// inference. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub struct BindingAnnotation(pub ByRef, pub Mutability); + +impl BindingAnnotation { + pub const NONE: Self = Self(ByRef::No, Mutability::Not); + pub const REF: Self = Self(ByRef::Yes, Mutability::Not); + pub const MUT: Self = Self(ByRef::No, Mutability::Mut); + pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut); + + pub fn prefix_str(self) -> &'static str { + match self { + Self::NONE => "", + Self::REF => "ref ", + Self::MUT => "mut ", + Self::REF_MUT => "ref mut ", + } + } } #[derive(Clone, Encodable, Decodable, Debug)] @@ -716,7 +716,7 @@ pub enum PatKind { /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens /// during name resolution. - Ident(BindingMode, Ident, Option>), + Ident(BindingAnnotation, Ident, Option>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. @@ -771,7 +771,7 @@ pub enum PatKind { Paren(P), /// A macro pattern; pre-expansion. - MacCall(MacCall), + MacCall(P), } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] @@ -937,8 +937,8 @@ impl Stmt { /// a trailing semicolon. /// /// This only modifies the parsed AST struct, not the attached - /// `LazyTokenStream`. The parser is responsible for calling - /// `CreateTokenStream::add_trailing_semi` when there is actually + /// `LazyAttrTokenStream`. The parser is responsible for calling + /// `ToAttrTokenStream::add_trailing_semi` when there is actually /// a semicolon in the tokenstream. pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { @@ -981,10 +981,10 @@ pub enum StmtKind { #[derive(Clone, Encodable, Decodable, Debug)] pub struct MacCallStmt { - pub mac: MacCall, + pub mac: P, pub style: MacStmtStyle, pub attrs: AttrVec, - pub tokens: Option, + pub tokens: Option, } #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)] @@ -1009,7 +1009,7 @@ pub struct Local { pub kind: LocalKind, pub span: Span, pub attrs: AttrVec, - pub tokens: Option, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -1108,7 +1108,7 @@ pub struct Expr { pub kind: ExprKind, pub span: Span, pub attrs: AttrVec, - pub tokens: Option, + pub tokens: Option, } impl Expr { @@ -1269,7 +1269,7 @@ impl Expr { id: DUMMY_NODE_ID, kind: ExprKind::Err, span: DUMMY_SP, - attrs: ThinVec::new(), + attrs: AttrVec::new(), tokens: None, }, ) @@ -1439,7 +1439,7 @@ pub enum ExprKind { InlineAsm(P), /// A macro invocation; pre-expansion. - MacCall(MacCall), + MacCall(P), /// A struct literal expression. /// @@ -1691,7 +1691,7 @@ pub enum StrStyle { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Lit { /// The original literal token as written in source code. - pub token: token::Lit, + pub token_lit: token::Lit, /// The "semantic" representation of the literal lowered from the original tokens. /// Strings are unescaped, hexadecimal forms are eliminated, etc. /// FIXME: Remove this and only create the semantic representation during lowering to HIR. @@ -1719,7 +1719,7 @@ impl StrLit { StrStyle::Raw(n) => token::StrRaw(n), }; Lit { - token: token::Lit::new(token_kind, self.symbol, self.suffix), + token_lit: token::Lit::new(token_kind, self.symbol, self.suffix), span: self.span, kind: LitKind::Str(self.symbol_unescaped, self.style), } @@ -1753,7 +1753,8 @@ pub enum LitFloatType { /// E.g., `"foo"`, `42`, `12.34`, or `bool`. #[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] pub enum LitKind { - /// A string literal (`"foo"`). + /// A string literal (`"foo"`). The symbol is unescaped, and so may differ + /// from the original token's symbol. Str(Symbol, StrStyle), /// A byte string (`b"foo"`). ByteStr(Lrc<[u8]>), @@ -1763,12 +1764,13 @@ pub enum LitKind { Char(char), /// An integer literal (`1`). Int(u128, LitIntType), - /// A float literal (`1f64` or `1E10f64`). + /// A float literal (`1f64` or `1E10f64`). Stored as a symbol rather than + /// `f64` so that `LitKind` can impl `Eq` and `Hash`. Float(Symbol, LitFloatType), /// A boolean literal. Bool(bool), /// Placeholder for a literal that wasn't well-formed in some way. - Err(Symbol), + Err, } impl LitKind { @@ -1807,7 +1809,7 @@ impl LitKind { | LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) - | LitKind::Err(..) => false, + | LitKind::Err => false, } } } @@ -1966,7 +1968,7 @@ pub struct Ty { pub id: NodeId, pub kind: TyKind, pub span: Span, - pub tokens: Option, + pub tokens: Option, } impl Clone for Ty { @@ -2042,7 +2044,7 @@ pub enum TyKind { /// Inferred type of a `self` or `&self` argument in a method. ImplicitSelf, /// A macro in the type position. - MacCall(MacCall), + MacCall(P), /// Placeholder for a kind that has failed to be defined. Err, /// Placeholder for a `va_list`. @@ -2059,8 +2061,11 @@ impl TyKind { } pub fn is_simple_path(&self) -> Option { - if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 { - Some(segments[0].ident.name) + if let TyKind::Path(None, Path { segments, .. }) = &self + && let [segment] = &segments[..] + && segment.args.is_none() + { + Some(segment.ident.name) } else { None } @@ -2071,6 +2076,7 @@ impl TyKind { #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TraitObjectSyntax { Dyn, + DynStar, None, } @@ -2086,15 +2092,15 @@ pub enum InlineAsmRegOrRegClass { bitflags::bitflags! { #[derive(Encodable, Decodable, HashStable_Generic)] pub struct InlineAsmOptions: u16 { - const PURE = 1 << 0; - const NOMEM = 1 << 1; - const READONLY = 1 << 2; + const PURE = 1 << 0; + const NOMEM = 1 << 1; + const READONLY = 1 << 2; const PRESERVES_FLAGS = 1 << 3; - const NORETURN = 1 << 4; - const NOSTACK = 1 << 5; - const ATT_SYNTAX = 1 << 6; - const RAW = 1 << 7; - const MAY_UNWIND = 1 << 8; + const NORETURN = 1 << 4; + const NOSTACK = 1 << 5; + const ATT_SYNTAX = 1 << 6; + const RAW = 1 << 7; + const MAY_UNWIND = 1 << 8; } } @@ -2230,7 +2236,7 @@ pub type ExplicitSelf = Spanned; impl Param { /// Attempts to cast parameter to `ExplicitSelf`. pub fn to_self(&self) -> Option { - if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind { + if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), ident, _) = self.pat.kind { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), @@ -2260,11 +2266,24 @@ impl Param { pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None }); - let param = |mutbl, ty| Param { + let (mutbl, ty) = match eself.node { + SelfKind::Explicit(ty, mutbl) => (mutbl, ty), + SelfKind::Value(mutbl) => (mutbl, infer_ty), + SelfKind::Region(lt, mutbl) => ( + Mutability::Not, + P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }), + span, + tokens: None, + }), + ), + }; + Param { attrs, pat: P(Pat { id: DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), + kind: PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), eself_ident, None), span, tokens: None, }), @@ -2272,19 +2291,6 @@ impl Param { ty, id: DUMMY_NODE_ID, is_placeholder: false, - }; - match eself.node { - SelfKind::Explicit(ty, mutbl) => param(mutbl, ty), - SelfKind::Value(mutbl) => param(mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => param( - Mutability::Not, - P(Ty { - id: DUMMY_NODE_ID, - kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }), - span, - tokens: None, - }), - ), } } } @@ -2336,9 +2342,9 @@ impl Async { } /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. - pub fn opt_return_id(self) -> Option { + pub fn opt_return_id(self) -> Option<(NodeId, Span)> { match self { - Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id), + Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)), Async::No => None, } } @@ -2522,8 +2528,8 @@ impl Encodable for AttrId { } impl Decodable for AttrId { - fn decode(_: &mut D) -> AttrId { - crate::attr::mk_attr_id() + default fn decode(_: &mut D) -> AttrId { + panic!("cannot decode `AttrId` with `{}`", std::any::type_name::()); } } @@ -2531,7 +2537,7 @@ impl Decodable for AttrId { pub struct AttrItem { pub path: Path, pub args: MacArgs, - pub tokens: Option, + pub tokens: Option, } /// A list of attributes. @@ -2548,10 +2554,16 @@ pub struct Attribute { pub span: Span, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct NormalAttr { + pub item: AttrItem, + pub tokens: Option, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub enum AttrKind { /// A normal attribute. - Normal(AttrItem, Option), + Normal(P), /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` @@ -2596,13 +2608,13 @@ impl PolyTraitRef { pub struct Visibility { pub kind: VisibilityKind, pub span: Span, - pub tokens: Option, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { Public, - Restricted { path: P, id: NodeId }, + Restricted { path: P, id: NodeId, shorthand: bool }, Inherited, } @@ -2665,7 +2677,7 @@ impl VariantData { /// An item definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Item { - pub attrs: Vec, + pub attrs: AttrVec, pub id: NodeId, pub span: Span, pub vis: Visibility, @@ -2682,7 +2694,7 @@ pub struct Item { /// /// Note that the tokens here do not include the outer attributes, but will /// include inner attributes. - pub tokens: Option, + pub tokens: Option, } impl Item { @@ -2873,7 +2885,7 @@ pub enum ItemKind { /// A macro invocation. /// /// E.g., `foo!(..)`. - MacCall(MacCall), + MacCall(P), /// A macro definition. MacroDef(MacroDef), @@ -2947,7 +2959,7 @@ pub enum AssocItemKind { /// An associated type. TyAlias(Box), /// A macro expanding to associated items. - MacCall(MacCall), + MacCall(P), } impl AssocItemKind { @@ -2996,7 +3008,7 @@ pub enum ForeignItemKind { /// An foreign type. TyAlias(Box), /// A macro expanding to foreign items. - MacCall(MacCall), + MacCall(P), } impl From for ItemKind { @@ -3030,22 +3042,34 @@ pub type ForeignItem = Item; #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(AssocItemKind, 72); - rustc_data_structures::static_assert_size!(Attribute, 152); - rustc_data_structures::static_assert_size!(Block, 48); - rustc_data_structures::static_assert_size!(Expr, 104); - rustc_data_structures::static_assert_size!(Fn, 192); - rustc_data_structures::static_assert_size!(ForeignItemKind, 72); - rustc_data_structures::static_assert_size!(GenericBound, 88); - rustc_data_structures::static_assert_size!(Generics, 72); - rustc_data_structures::static_assert_size!(Impl, 200); - rustc_data_structures::static_assert_size!(Item, 200); - rustc_data_structures::static_assert_size!(ItemKind, 112); - rustc_data_structures::static_assert_size!(Lit, 48); - rustc_data_structures::static_assert_size!(Pat, 120); - rustc_data_structures::static_assert_size!(Path, 40); - rustc_data_structures::static_assert_size!(PathSegment, 24); - rustc_data_structures::static_assert_size!(Stmt, 32); - rustc_data_structures::static_assert_size!(Ty, 96); + static_assert_size!(AssocItem, 104); + static_assert_size!(AssocItemKind, 32); + static_assert_size!(Attribute, 32); + static_assert_size!(Block, 48); + static_assert_size!(Expr, 104); + static_assert_size!(ExprKind, 72); + #[cfg(not(bootstrap))] + static_assert_size!(Fn, 184); + static_assert_size!(ForeignItem, 96); + static_assert_size!(ForeignItemKind, 24); + static_assert_size!(GenericArg, 24); + static_assert_size!(GenericBound, 88); + static_assert_size!(Generics, 72); + static_assert_size!(Impl, 200); + static_assert_size!(Item, 184); + static_assert_size!(ItemKind, 112); + static_assert_size!(Lit, 48); + static_assert_size!(LitKind, 24); + static_assert_size!(Local, 72); + static_assert_size!(Param, 40); + static_assert_size!(Pat, 120); + static_assert_size!(PatKind, 96); + static_assert_size!(Path, 40); + static_assert_size!(PathSegment, 24); + static_assert_size!(Stmt, 32); + static_assert_size!(StmtKind, 16); + static_assert_size!(Ty, 96); + static_assert_size!(TyKind, 72); } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 5c30a75a1..1b31be07f 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -4,7 +4,7 @@ use crate::ptr::P; use crate::token::Nonterminal; -use crate::tokenstream::LazyTokenStream; +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}; @@ -124,18 +124,18 @@ impl HasSpan for AttrItem { /// A trait for AST nodes having (or not having) collected tokens. pub trait HasTokens { - fn tokens(&self) -> Option<&LazyTokenStream>; - fn tokens_mut(&mut self) -> Option<&mut Option>; + 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<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { self.tokens.as_ref() } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { Some(&mut self.tokens) } } @@ -147,10 +147,10 @@ macro_rules! impl_has_tokens_none { ($($T:ty),+ $(,)?) => { $( impl HasTokens for $T { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { None } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { None } } @@ -162,25 +162,25 @@ impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); impl> HasTokens for T { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { self.ast_deref().tokens() } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { self.ast_deref_mut().tokens_mut() } } impl HasTokens for Option { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { self.as_ref().and_then(|inner| inner.tokens()) } - fn tokens_mut(&mut self) -> Option<&mut Option> { + 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<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { StmtKind::Local(local) => local.tokens.as_ref(), StmtKind::Item(item) => item.tokens(), @@ -189,7 +189,7 @@ impl HasTokens for StmtKind { StmtKind::MacCall(mac) => mac.tokens.as_ref(), } } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { match self { StmtKind::Local(local) => Some(&mut local.tokens), StmtKind::Item(item) => item.tokens_mut(), @@ -201,26 +201,26 @@ impl HasTokens for StmtKind { } impl HasTokens for Stmt { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { self.kind.tokens() } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { self.kind.tokens_mut() } } impl HasTokens for Attribute { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { match &self.kind { - AttrKind::Normal(_, tokens) => tokens.as_ref(), + 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> { + fn tokens_mut(&mut self) -> Option<&mut Option> { Some(match &mut self.kind { - AttrKind::Normal(_, tokens) => tokens, + AttrKind::Normal(normal) => &mut normal.tokens, kind @ AttrKind::DocComment(..) => { panic!("Called tokens_mut on doc comment attr {:?}", kind) } @@ -229,7 +229,7 @@ impl HasTokens for Attribute { } impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyTokenStream> { + fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { Nonterminal::NtItem(item) => item.tokens(), Nonterminal::NtStmt(stmt) => stmt.tokens(), @@ -243,7 +243,7 @@ impl HasTokens for Nonterminal { Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, } } - fn tokens_mut(&mut self) -> Option<&mut Option> { + fn tokens_mut(&mut self) -> Option<&mut Option> { match self { Nonterminal::NtItem(item) => item.tokens_mut(), Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), @@ -270,7 +270,7 @@ pub trait HasAttrs { /// during token collection. const SUPPORTS_CUSTOM_INNER_ATTRS: bool; fn attrs(&self) -> &[Attribute]; - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)); + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)); } macro_rules! impl_has_attrs { @@ -279,12 +279,13 @@ macro_rules! impl_has_attrs { 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 Vec)) { - VecOrAttrVec::visit(&mut self.attrs, f) + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { + f(&mut self.attrs) } } )+ @@ -299,7 +300,7 @@ macro_rules! impl_has_attrs_none { fn attrs(&self) -> &[Attribute] { &[] } - fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec)) {} + fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {} } )+ }; @@ -330,7 +331,7 @@ impl> HasAttrs for T { fn attrs(&self) -> &[Attribute] { self.ast_deref().attrs() } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { self.ast_deref_mut().visit_attrs(f) } } @@ -340,7 +341,7 @@ impl HasAttrs for Option { fn attrs(&self) -> &[Attribute] { self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[]) } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { if let Some(inner) = self.as_mut() { inner.visit_attrs(f); } @@ -362,13 +363,13 @@ impl HasAttrs for StmtKind { } } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { match self { - StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f), + StmtKind::Local(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) => visit_attrvec(&mut mac.attrs, f), + StmtKind::MacCall(mac) => f(&mut mac.attrs), } } } @@ -378,38 +379,11 @@ impl HasAttrs for Stmt { fn attrs(&self) -> &[Attribute] { self.kind.attrs() } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { self.kind.visit_attrs(f); } } -/// Helper trait for the impls above. Abstracts over -/// the two types of attribute fields that AST nodes -/// may have (`Vec` or `AttrVec`). -trait VecOrAttrVec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)); -} - -impl VecOrAttrVec for Vec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)) { - f(self) - } -} - -impl VecOrAttrVec for AttrVec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)) { - visit_attrvec(self, f) - } -} - -fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec)) { - crate::mut_visit::visit_clobber(attrs, |attrs| { - let mut vec = attrs.into(); - f(&mut vec); - vec.into() - }); -} - /// A newtype around an AST node that implements the traits above if the node implements them. pub struct AstNodeWrapper { pub wrapped: Wrapped, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 86af7769d..990f4f8f1 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -7,18 +7,22 @@ use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, Neste use crate::ast::{Path, PathSegment}; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter, Token}; -use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use crate::tokenstream::{DelimSpan, Spacing, TokenTree}; -use crate::tokenstream::{LazyTokenStream, TokenStream}; +use crate::tokenstream::{LazyAttrTokenStream, TokenStream}; use crate::util::comments; -use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::sync::WorkerLocal; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::BytePos; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use std::cell::Cell; use std::iter; +#[cfg(debug_assertions)] +use std::ops::BitXor; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicU32, Ordering}; pub struct MarkedAttrs(GrowableBitSet); @@ -114,7 +118,7 @@ impl Attribute { #[inline] pub fn has_name(&self, name: Symbol) -> bool { match self.kind { - AttrKind::Normal(ref item, _) => item.path == name, + AttrKind::Normal(ref normal) => normal.item.path == name, AttrKind::DocComment(..) => false, } } @@ -122,9 +126,9 @@ impl Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { match self.kind { - AttrKind::Normal(ref item, _) => { - if item.path.segments.len() == 1 { - Some(item.path.segments[0].ident) + AttrKind::Normal(ref normal) => { + if normal.item.path.segments.len() == 1 { + Some(normal.item.path.segments[0].ident) } else { None } @@ -138,14 +142,16 @@ impl Attribute { pub fn value_str(&self) -> Option { match self.kind { - AttrKind::Normal(ref item, _) => item.meta_kind().and_then(|kind| kind.value_str()), + AttrKind::Normal(ref normal) => { + normal.item.meta_kind().and_then(|kind| kind.value_str()) + } AttrKind::DocComment(..) => None, } } pub fn meta_item_list(&self) -> Option> { match self.kind { - AttrKind::Normal(ref item, _) => match item.meta_kind() { + AttrKind::Normal(ref normal) => match normal.item.meta_kind() { Some(MetaItemKind::List(list)) => Some(list), _ => None, }, @@ -154,8 +160,8 @@ impl Attribute { } pub fn is_word(&self) -> bool { - if let AttrKind::Normal(item, _) = &self.kind { - matches!(item.args, MacArgs::Empty) + if let AttrKind::Normal(normal) = &self.kind { + matches!(normal.item.args, MacArgs::Empty) } else { false } @@ -182,13 +188,7 @@ impl MetaItem { } pub fn value_str(&self) -> Option { - match self.kind { - MetaItemKind::NameValue(ref v) => match v.kind { - LitKind::Str(ref s, _) => Some(*s), - _ => None, - }, - _ => None, - } + self.kind.value_str() } pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { @@ -237,6 +237,9 @@ impl AttrItem { } impl Attribute { + /// 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, @@ -244,10 +247,16 @@ impl Attribute { } } + /// 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(ref item, _) if item.path == sym::doc => item + AttrKind::Normal(ref normal) if normal.item.path == sym::doc => normal + .item .meta_kind() .and_then(|kind| kind.value_str()) .map(|data| (data, CommentKind::Line)), @@ -255,11 +264,15 @@ impl Attribute { } } + /// 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(ref item, _) if item.path == sym::doc => { - item.meta_kind().and_then(|kind| kind.value_str()) + AttrKind::Normal(ref normal) if normal.item.path == sym::doc => { + normal.item.meta_kind().and_then(|kind| kind.value_str()) } _ => None, } @@ -271,14 +284,14 @@ impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { match self.kind { - AttrKind::Normal(ref item, _) => item, + AttrKind::Normal(ref normal) => &normal.item, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { - AttrKind::Normal(item, _) => item, + AttrKind::Normal(normal) => normal.into_inner().item, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } @@ -286,31 +299,30 @@ impl Attribute { /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option { match self.kind { - AttrKind::Normal(ref item, _) => item.meta(self.span), + AttrKind::Normal(ref normal) => normal.item.meta(self.span), AttrKind::DocComment(..) => None, } } pub fn meta_kind(&self) -> Option { match self.kind { - AttrKind::Normal(ref item, _) => item.meta_kind(), + AttrKind::Normal(ref normal) => normal.item.meta_kind(), AttrKind::DocComment(..) => None, } } - pub fn tokens(&self) -> AttrAnnotatedTokenStream { + pub fn tokens(&self) -> TokenStream { match self.kind { - AttrKind::Normal(_, ref tokens) => tokens + AttrKind::Normal(ref normal) => normal + .tokens .as_ref() .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self)) - .create_token_stream(), - AttrKind::DocComment(comment_kind, data) => AttrAnnotatedTokenStream::from(( - AttrAnnotatedTokenTree::Token(Token::new( - token::DocComment(comment_kind, self.style, data), - self.span, - )), + .to_attr_token_stream() + .to_tokenstream(), + AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token( + Token::new(token::DocComment(comment_kind, self.style, data), self.span), Spacing::Alone, - )), + )]), } } } @@ -340,47 +352,86 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { NestedMetaItem::MetaItem(mk_word_item(ident)) } -pub(crate) fn mk_attr_id() -> AttrId { - use std::sync::atomic::AtomicU32; - use std::sync::atomic::Ordering; +pub struct AttrIdGenerator(WorkerLocal>); - static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0); +#[cfg(debug_assertions)] +static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX); - let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst); - assert!(id != u32::MAX); - AttrId::from_u32(id) +impl AttrIdGenerator { + pub fn new() -> Self { + // We use `(index as u32).reverse_bits()` to initialize the + // starting value of AttrId in each worker thread. + // The `index` is the index of the worker thread. + // This ensures that the AttrId generated in each thread is unique. + AttrIdGenerator(WorkerLocal::new(|index| { + let index: u32 = index.try_into().unwrap(); + + #[cfg(debug_assertions)] + { + let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits(); + MAX_ATTR_ID.fetch_min(max_id, Ordering::Release); + } + + Cell::new(index.reverse_bits()) + })) + } + + pub fn mk_attr_id(&self) -> AttrId { + let id = self.0.get(); + + // Ensure the assigned attr_id does not overlap the bits + // representing the number of threads. + #[cfg(debug_assertions)] + assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire)); + + self.0.set(id + 1); + AttrId::from_u32(id) + } } -pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { - mk_attr_from_item(AttrItem { path, args, tokens: None }, None, style, span) +pub fn mk_attr( + g: &AttrIdGenerator, + style: AttrStyle, + path: Path, + args: MacArgs, + 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, + tokens: Option, style: AttrStyle, span: Span, ) -> Attribute { - Attribute { kind: AttrKind::Normal(item, tokens), id: mk_attr_id(), style, span } + Attribute { + kind: AttrKind::Normal(P(ast::NormalAttr { item, tokens })), + id: g.mk_attr_id(), + style, + span, + } } /// Returns an inner attribute with the given value and span. -pub fn mk_attr_inner(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) +pub fn mk_attr_inner(g: &AttrIdGenerator, item: MetaItem) -> Attribute { + mk_attr(g, AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) } /// Returns an outer attribute with the given value and span. -pub fn mk_attr_outer(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) +pub fn mk_attr_outer(g: &AttrIdGenerator, item: MetaItem) -> Attribute { + mk_attr(g, AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } 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: mk_attr_id(), style, span } + Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } } pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { @@ -484,7 +535,7 @@ impl MetaItemKind { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::Lit(lit.clone()), span: lit.span, - attrs: ThinVec::new(), + attrs: ast::AttrVec::new(), tokens: None, }); MacArgs::Eq(span, MacArgsEq::Ast(expr)) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 4b94ec0d6..bd7a85b07 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -13,17 +13,23 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(if_let_guard)] -#![feature(label_break_value)] +#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(slice_internals)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + pub mod util { pub mod classify; pub mod comments; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 01bd498b3..9fd0b63c4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,7 +14,6 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -338,12 +337,7 @@ where } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attrs(attrs: &mut Vec, vis: &mut T) { - visit_vec(attrs, |attr| vis.visit_attribute(attr)); -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_thin_attrs(attrs: &mut AttrVec, vis: &mut T) { +pub fn visit_attrs(attrs: &mut AttrVec, vis: &mut T) { for attr in attrs.iter_mut() { vis.visit_attribute(attr); } @@ -398,7 +392,7 @@ pub fn noop_flat_map_pat_field( vis.visit_ident(ident); vis.visit_pat(pat); vis.visit_span(span); - visit_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); smallvec![fp] } @@ -424,7 +418,7 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { 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_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); vis.visit_id(id); vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); @@ -507,7 +501,7 @@ pub fn noop_flat_map_variant( let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; visitor.visit_ident(ident); visitor.visit_vis(vis); - visit_thin_attrs(attrs, visitor); + 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)); @@ -589,14 +583,16 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } } vis.visit_span(span); - visit_thin_attrs(attrs, vis); + 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(AttrItem { path, args, tokens }, attr_tokens) => { + AttrKind::Normal(normal) => { + let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = + &mut **normal; vis.visit_path(path); visit_mac_args(args, vis); visit_lazy_tts(tokens, vis); @@ -638,7 +634,7 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { 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_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); @@ -646,21 +642,21 @@ pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> Smal } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attr_annotated_tt(tt: &mut AttrAnnotatedTokenTree, vis: &mut T) { +pub fn visit_attr_tt(tt: &mut AttrTokenTree, vis: &mut T) { match tt { - AttrAnnotatedTokenTree::Token(token) => { + AttrTokenTree::Token(token, _) => { visit_token(token, vis); } - AttrAnnotatedTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => { + AttrTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => { vis.visit_span(open); vis.visit_span(close); - visit_attr_annotated_tts(tts, vis); + visit_attr_tts(tts, vis); } - AttrAnnotatedTokenTree::Attributes(data) => { + AttrTokenTree::Attributes(data) => { for attr in &mut *data.attrs { match &mut attr.kind { - AttrKind::Normal(_, attr_tokens) => { - visit_lazy_tts(attr_tokens, vis); + AttrKind::Normal(normal) => { + visit_lazy_tts(&mut normal.tokens, vis); } AttrKind::DocComment(..) => { vis.visit_span(&mut attr.span); @@ -694,27 +690,27 @@ pub fn visit_tts(TokenStream(tts): &mut TokenStream, vis: &mut T) } } -pub fn visit_attr_annotated_tts( - AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream, - vis: &mut T, -) { +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, _is_joint)| visit_attr_annotated_tt(tree, vis)); + visit_vec(tts, |tree| visit_attr_tt(tree, vis)); } } -pub fn visit_lazy_tts_opt_mut(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) { +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.create_token_stream(); - visit_attr_annotated_tts(&mut tts, vis); - *lazy_tts = LazyTokenStream::new(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) { +pub fn visit_lazy_tts(lazy_tts: &mut Option, vis: &mut T) { visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis); } @@ -880,7 +876,7 @@ pub fn noop_flat_map_generic_param( if let Some(ref mut colon_span) = colon_span { vis.visit_span(colon_span); } - visit_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); match kind { GenericParamKind::Lifetime => {} @@ -933,8 +929,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); } WherePredicate::EqPredicate(ep) => { - let WhereEqPredicate { id, span, lhs_ty, rhs_ty } = ep; - vis.visit_id(id); + let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep; vis.visit_span(span); vis.visit_ty(lhs_ty); vis.visit_ty(rhs_ty); @@ -977,7 +972,7 @@ pub fn noop_flat_map_field_def( visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); - visit_thin_attrs(attrs, visitor); + visit_attrs(attrs, visitor); smallvec![fd] } @@ -990,7 +985,7 @@ pub fn noop_flat_map_expr_field( vis.visit_expr(expr); vis.visit_id(id); vis.visit_span(span); - visit_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); smallvec![f] } @@ -1430,7 +1425,7 @@ pub fn noop_visit_expr( } vis.visit_id(id); vis.visit_span(span); - visit_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); visit_lazy_tts(tokens, vis); } @@ -1476,7 +1471,7 @@ pub fn noop_flat_map_stmt_kind( StmtKind::MacCall(mut mac) => { let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut(); vis.visit_mac_call(mac_); - visit_thin_attrs(attrs, vis); + visit_attrs(attrs, vis); visit_lazy_tts(tokens, vis); smallvec![StmtKind::MacCall(mac)] } @@ -1486,7 +1481,7 @@ pub fn noop_flat_map_stmt_kind( pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { path, id } => { + VisibilityKind::Restricted { path, id, shorthand: _ } => { vis.visit_path(path); vis.visit_id(id); } @@ -1511,12 +1506,6 @@ impl DummyAstNode for P { } } -impl DummyAstNode for ThinVec { - fn dummy() -> Self { - Default::default() - } -} - impl DummyAstNode for Item { fn dummy() -> Self { Item { diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index 7f928cb57..7b5acc3f4 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -13,7 +13,7 @@ rustc_index::newtype_index! { } } -rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId); +rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId); /// The [`NodeId`] used to represent the root of the crate. pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 85d9687c6..97dfb7837 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -398,6 +398,30 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of an 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, 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 { @@ -436,6 +460,31 @@ impl Token { || self == &OpenDelim(Delimiter::Parenthesis) } + /// 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(..)) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 9e4a22e1f..875cd620d 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -121,12 +121,12 @@ where } } -pub trait CreateTokenStream: sync::Send + sync::Sync { - fn create_token_stream(&self) -> AttrAnnotatedTokenStream; +pub trait ToAttrTokenStream: sync::Send + sync::Sync { + fn to_attr_token_stream(&self) -> AttrTokenStream; } -impl CreateTokenStream for AttrAnnotatedTokenStream { - fn create_token_stream(&self) -> AttrAnnotatedTokenStream { +impl ToAttrTokenStream for AttrTokenStream { + fn to_attr_token_stream(&self) -> AttrTokenStream { self.clone() } } @@ -135,68 +135,68 @@ impl CreateTokenStream for AttrAnnotatedTokenStream { /// of an actual `TokenStream` until it is needed. /// `Box` is here only to reduce the structure size. #[derive(Clone)] -pub struct LazyTokenStream(Lrc>); +pub struct LazyAttrTokenStream(Lrc>); -impl LazyTokenStream { - pub fn new(inner: impl CreateTokenStream + 'static) -> LazyTokenStream { - LazyTokenStream(Lrc::new(Box::new(inner))) +impl LazyAttrTokenStream { + pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream { + LazyAttrTokenStream(Lrc::new(Box::new(inner))) } - pub fn create_token_stream(&self) -> AttrAnnotatedTokenStream { - self.0.create_token_stream() + pub fn to_attr_token_stream(&self) -> AttrTokenStream { + self.0.to_attr_token_stream() } } -impl fmt::Debug for LazyTokenStream { +impl fmt::Debug for LazyAttrTokenStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "LazyTokenStream({:?})", self.create_token_stream()) + write!(f, "LazyAttrTokenStream({:?})", self.to_attr_token_stream()) } } -impl Encodable for LazyTokenStream { +impl Encodable for LazyAttrTokenStream { fn encode(&self, s: &mut S) { // Used by AST json printing. - Encodable::encode(&self.create_token_stream(), s); + Encodable::encode(&self.to_attr_token_stream(), s); } } -impl Decodable for LazyTokenStream { +impl Decodable for LazyAttrTokenStream { fn decode(_d: &mut D) -> Self { - panic!("Attempted to decode LazyTokenStream"); + panic!("Attempted to decode LazyAttrTokenStream"); } } -impl HashStable for LazyTokenStream { +impl HashStable for LazyAttrTokenStream { fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("Attempted to compute stable hash for LazyTokenStream"); + panic!("Attempted to compute stable hash for LazyAttrTokenStream"); } } -/// A `AttrAnnotatedTokenStream` is similar to a `TokenStream`, but with extra +/// 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 AttrAnnotatedTokenStream(pub Lrc>); +pub struct AttrTokenStream(pub Lrc>); -/// Like `TokenTree`, but for `AttrAnnotatedTokenStream` +/// Like `TokenTree`, but for `AttrTokenStream`. #[derive(Clone, Debug, Encodable, Decodable)] -pub enum AttrAnnotatedTokenTree { - Token(Token), - Delimited(DelimSpan, Delimiter, AttrAnnotatedTokenStream), +pub enum AttrTokenTree { + Token(Token, Spacing), + Delimited(DelimSpan, 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 AttrAnnotatedTokenStream { - pub fn new(tokens: Vec<(AttrAnnotatedTokenTree, Spacing)>) -> AttrAnnotatedTokenStream { - AttrAnnotatedTokenStream(Lrc::new(tokens)) +impl AttrTokenStream { + pub fn new(tokens: Vec) -> AttrTokenStream { + AttrTokenStream(Lrc::new(tokens)) } - /// Converts this `AttrAnnotatedTokenStream` to a plain `TokenStream - /// During conversion, `AttrAnnotatedTokenTree::Attributes` get 'flattened' + /// 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. @@ -204,31 +204,27 @@ impl AttrAnnotatedTokenStream { let trees: Vec<_> = self .0 .iter() - .flat_map(|tree| match &tree.0 { - AttrAnnotatedTokenTree::Token(inner) => { - smallvec![TokenTree::Token(inner.clone(), tree.1)].into_iter() + .flat_map(|tree| match &tree { + AttrTokenTree::Token(inner, spacing) => { + smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter() } - AttrAnnotatedTokenTree::Delimited(span, delim, stream) => { + AttrTokenTree::Delimited(span, delim, stream) => { smallvec![TokenTree::Delimited(*span, *delim, stream.to_tokenstream()),] .into_iter() } - AttrAnnotatedTokenTree::Attributes(data) => { + AttrTokenTree::Attributes(data) => { let mut outer_attrs = Vec::new(); let mut inner_attrs = Vec::new(); for attr in &data.attrs { match attr.style { - crate::AttrStyle::Outer => { - outer_attrs.push(attr); - } - crate::AttrStyle::Inner => { - inner_attrs.push(attr); - } + crate::AttrStyle::Outer => outer_attrs.push(attr), + crate::AttrStyle::Inner => inner_attrs.push(attr), } } let mut target_tokens: Vec<_> = data .tokens - .create_token_stream() + .to_attr_token_stream() .to_tokenstream() .0 .iter() @@ -239,9 +235,9 @@ impl AttrAnnotatedTokenStream { // 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, 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: + // 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 @@ -255,7 +251,7 @@ impl AttrAnnotatedTokenStream { let mut builder = TokenStreamBuilder::new(); for inner_attr in inner_attrs { - builder.push(inner_attr.tokens().to_tokenstream()); + builder.push(inner_attr.tokens()); } builder.push(delim_tokens.clone()); *tree = TokenTree::Delimited(*span, *delim, builder.build()); @@ -273,7 +269,7 @@ impl AttrAnnotatedTokenStream { let mut flat: SmallVec<[_; 1]> = SmallVec::new(); for attr in outer_attrs { // FIXME: Make this more efficient - flat.extend(attr.tokens().to_tokenstream().0.clone().iter().cloned()); + flat.extend(attr.tokens().0.clone().iter().cloned()); } flat.extend(target_tokens); flat.into_iter() @@ -300,7 +296,7 @@ pub struct AttributesData { pub attrs: AttrVec, /// The underlying tokens for the attribute target that `attrs` /// are applied to - pub tokens: LazyTokenStream, + pub tokens: LazyAttrTokenStream, } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. @@ -363,12 +359,6 @@ impl TokenStream { } } -impl From<(AttrAnnotatedTokenTree, Spacing)> for AttrAnnotatedTokenStream { - fn from((tree, spacing): (AttrAnnotatedTokenTree, Spacing)) -> AttrAnnotatedTokenStream { - AttrAnnotatedTokenStream::new(vec![(tree, spacing)]) - } -} - impl iter::FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { TokenStream::new(iter.into_iter().collect::>()) @@ -420,21 +410,6 @@ impl TokenStream { TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect())) } - fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option { - let tokens = node.tokens()?; - let attrs = node.attrs(); - let attr_annotated = if attrs.is_empty() { - tokens.create_token_stream() - } else { - let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() }; - AttrAnnotatedTokenStream::new(vec![( - AttrAnnotatedTokenTree::Attributes(attr_data), - Spacing::Alone, - )]) - }; - Some(attr_annotated.to_tokenstream()) - } - // Create a token stream containing a single token with alone spacing. pub fn token_alone(kind: TokenKind, span: Span) -> TokenStream { TokenStream::new(vec![TokenTree::token_alone(kind, span)]) @@ -451,8 +426,18 @@ impl TokenStream { } pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { - TokenStream::opt_from_ast(node) - .unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node)) + 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 { @@ -555,7 +540,7 @@ impl TokenStreamBuilder { // Get the first stream, which will become the result stream. // If it's `None`, create an empty stream. - let mut iter = streams.drain(..); + let mut iter = streams.into_iter(); let mut res_stream_lrc = iter.next().unwrap().0; // Append the subsequent elements to the result stream, after diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 9c18f55c0..536b38560 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -9,7 +9,6 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::ascii; -use tracing::debug; pub enum LitError { NotLiteral, @@ -23,7 +22,7 @@ pub enum LitError { impl LitKind { /// Converts literal token into a semantic literal. - pub fn from_lit_token(lit: token::Lit) -> Result { + pub fn from_token_lit(lit: token::Lit) -> Result { let token::Lit { kind, symbol, suffix } = lit; if suffix.is_some() && !kind.may_have_suffix() { return Err(LitError::InvalidSuffix); @@ -146,14 +145,14 @@ impl LitKind { LitKind::ByteStr(bytes.into()) } - token::Err => LitKind::Err(symbol), + token::Err => LitKind::Err, }) } /// Attempts to recover a token from semantic literal. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn to_lit_token(&self) -> token::Lit { + pub fn to_token_lit(&self) -> token::Lit { let (kind, symbol, suffix) = match *self { LitKind::Str(symbol, ast::StrStyle::Cooked) => { // Don't re-intern unless the escaped string is different. @@ -164,12 +163,7 @@ impl LitKind { } LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None), LitKind::ByteStr(ref bytes) => { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); + let string = bytes.escape_ascii().to_string(); (token::ByteStr, Symbol::intern(&string), None) } LitKind::Byte(byte) => { @@ -199,7 +193,9 @@ impl LitKind { let symbol = if value { kw::True } else { kw::False }; (token::Bool, symbol, None) } - LitKind::Err(symbol) => (token::Err, symbol, None), + // This only shows up in places like `-Zunpretty=hir` output, so we + // don't bother to produce something useful. + LitKind::Err => (token::Err, Symbol::intern(""), None), }; token::Lit::new(kind, symbol, suffix) @@ -208,8 +204,8 @@ impl LitKind { impl Lit { /// Converts literal token into an AST literal. - pub fn from_lit_token(token: token::Lit, span: Span) -> Result { - Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span }) + pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { + Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) } /// Converts arbitrary token into an AST literal. @@ -232,21 +228,21 @@ impl Lit { _ => return Err(LitError::NotLiteral), }; - Lit::from_lit_token(lit, token.span) + Lit::from_token_lit(lit, token.span) } /// Attempts to recover an AST literal from semantic literal. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { - Lit { token: kind.to_lit_token(), kind, span } + Lit { token_lit: kind.to_token_lit(), kind, span } } /// Losslessly convert an AST literal into a token. pub fn to_token(&self) -> Token { - let kind = match self.token.kind { - token::Bool => token::Ident(self.token.symbol, false), - _ => token::Literal(self.token), + let kind = match self.token_lit.kind { + token::Bool => token::Ident(self.token_lit.symbol, false), + _ => token::Literal(self.token_lit), }; Token::new(kind, self.span) } diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 74b7fe9e2..6c5c7f66f 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -297,11 +297,11 @@ impl ExprPrecedence { match self { ExprPrecedence::Closure => PREC_CLOSURE, - ExprPrecedence::Break | - ExprPrecedence::Continue | - ExprPrecedence::Ret | - ExprPrecedence::Yield | - ExprPrecedence::Yeet => PREC_JUMP, + ExprPrecedence::Break + | ExprPrecedence::Continue + | ExprPrecedence::Ret + | ExprPrecedence::Yield + | ExprPrecedence::Yeet => 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 @@ -318,43 +318,43 @@ impl ExprPrecedence { ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8, // Unary, prefix - ExprPrecedence::Box | - ExprPrecedence::AddrOf | + ExprPrecedence::Box + | 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, + | ExprPrecedence::Let + | ExprPrecedence::Unary => PREC_PREFIX, // Unary, postfix - ExprPrecedence::Await | - ExprPrecedence::Call | - ExprPrecedence::MethodCall | - ExprPrecedence::Field | - ExprPrecedence::Index | - ExprPrecedence::Try | - ExprPrecedence::InlineAsm | - ExprPrecedence::Mac => PREC_POSTFIX, + ExprPrecedence::Await + | ExprPrecedence::Call + | ExprPrecedence::MethodCall + | ExprPrecedence::Field + | ExprPrecedence::Index + | ExprPrecedence::Try + | ExprPrecedence::InlineAsm + | ExprPrecedence::Mac => 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::Async | - ExprPrecedence::Struct | - ExprPrecedence::Err => PREC_PAREN, + 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::Async + | ExprPrecedence::Struct + | ExprPrecedence::Err => PREC_PAREN, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d9594b323..1d0de5a4b 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -156,8 +156,8 @@ pub trait Visitor<'ast>: Sized { fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { walk_where_predicate(self, p) } - fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) { - walk_fn(self, fk, s) + fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) { + walk_fn(self, fk) } fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) { walk_assoc_item(self, i, ctxt) @@ -168,8 +168,8 @@ pub trait Visitor<'ast>: Sized { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) { walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { - walk_poly_trait_ref(self, t, m) + fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { + walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) @@ -177,14 +177,8 @@ pub trait Visitor<'ast>: Sized { fn visit_field_def(&mut self, s: &'ast FieldDef) { walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &'ast EnumDef, - generics: &'ast Generics, - item_id: NodeId, - _: Span, - ) { - walk_enum_def(self, enum_definition, generics, item_id) + fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) { + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &'ast Variant) { walk_variant(self, v) @@ -207,11 +201,11 @@ pub trait Visitor<'ast>: Sized { fn visit_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId, _nested: bool) { walk_use_tree(self, use_tree, id) } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { - walk_path_segment(self, path_span, path_segment) + fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { + walk_path_segment(self, path_segment) } - fn visit_generic_args(&mut self, path_span: Span, generic_args: &'ast GenericArgs) { - walk_generic_args(self, path_span, generic_args) + fn visit_generic_args(&mut self, generic_args: &'ast GenericArgs) { + walk_generic_args(self, generic_args) } fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) { walk_generic_arg(self, generic_arg) @@ -287,11 +281,8 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime visitor.visit_ident(lifetime.ident); } -pub fn walk_poly_trait_ref<'a, V>( - visitor: &mut V, - trait_ref: &'a PolyTraitRef, - _: &TraitBoundModifier, -) where +pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) +where V: Visitor<'a>, { walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params); @@ -334,7 +325,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Enum(ref enum_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_enum_def(enum_definition, generics, item.id, item.span) + visitor.visit_enum_def(enum_definition) } ItemKind::Impl(box Impl { defaultness: _, @@ -377,12 +368,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_attribute, &item.attrs); } -pub fn walk_enum_def<'a, V: Visitor<'a>>( - visitor: &mut V, - enum_definition: &'a EnumDef, - _: &'a Generics, - _: NodeId, -) { +pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) { walk_list!(visitor, visit_variant, &enum_definition.variants); } @@ -449,7 +435,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) { for segment in &path.segments { - visitor.visit_path_segment(path.span, segment); + visitor.visit_path_segment(segment); } } @@ -471,18 +457,14 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>(visitor: &mut V, use_tree: &'a UseTree, } } -pub fn walk_path_segment<'a, V: Visitor<'a>>( - visitor: &mut V, - path_span: Span, - segment: &'a PathSegment, -) { +pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V, segment: &'a PathSegment) { visitor.visit_ident(segment.ident); if let Some(ref args) = segment.args { - visitor.visit_generic_args(path_span, args); + visitor.visit_generic_args(args); } } -pub fn walk_generic_args<'a, V>(visitor: &mut V, _path_span: Span, generic_args: &'a GenericArgs) +pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) where V: Visitor<'a>, { @@ -516,7 +498,7 @@ where pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) { visitor.visit_ident(constraint.ident); if let Some(ref gen_args) = constraint.gen_args { - visitor.visit_generic_args(gen_args.span(), gen_args); + visitor.visit_generic_args(gen_args); } match constraint.kind { AssocConstraintKind::Equality { ref term } => match term { @@ -598,7 +580,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) { match *bound { - GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier), + GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(ref lifetime) => { visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound) } @@ -673,7 +655,7 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: & visitor.visit_fn_ret_ty(&function_declaration.output); } -pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) { +pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) { match kind { FnKind::Fn(_, _, sig, _, generics, body) => { visitor.visit_generics(generics); @@ -814,7 +796,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_expr, arguments); } ExprKind::MethodCall(ref segment, ref arguments, _span) => { - visitor.visit_path_segment(expression.span, segment); + visitor.visit_path_segment(segment); walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { @@ -935,14 +917,14 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let VisibilityKind::Restricted { ref path, id } = vis.kind { + if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind { visitor.visit_path(path, id); } } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match attr.kind { - AttrKind::Normal(ref item, ref _tokens) => walk_mac_args(visitor, &item.args), + AttrKind::Normal(ref normal) => walk_mac_args(visitor, &normal.item.args), AttrKind::DocComment(..) => {} } } diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 39ba62ef2..ce1c8d499 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -8,16 +8,18 @@ doctest = false [dependencies] rustc_arena = { path = "../rustc_arena" } -tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_hir = { path = "../rustc_hir" } -rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } +rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } -rustc_span = { path = "../rustc_span" } -rustc_errors = { path = "../rustc_errors" } rustc_session = { path = "../rustc_session" } -rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +thin-vec = "0.2.8" +tracing = "0.1" diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 4166b4fc2..24672efc6 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,11 +1,17 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt}; +use super::errors::{ + AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, + InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, + InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, + InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, + RegisterConflict, +}; use super::LoweringContext; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::definitions::DefPathData; @@ -26,13 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let asm_arch = if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch }; if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc { - struct_span_err!( - self.tcx.sess, - sp, - E0472, - "inline assembly is unsupported on this target" - ) - .emit(); + self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp }); } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. @@ -59,10 +59,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) && !self.tcx.sess.opts.actually_rustdoc { - self.tcx - .sess - .struct_span_err(sp, "the `att_syntax` option is only supported on x86") - .emit(); + self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp }); } if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { feature_err( @@ -82,51 +79,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If the abi was already in the list, emit an error match clobber_abis.get(&abi) { Some((prev_name, prev_sp)) => { - let mut err = self.tcx.sess.struct_span_err( - *abi_span, - &format!("`{}` ABI specified multiple times", prev_name), - ); - err.span_label(*prev_sp, "previously specified here"); - // Multiple different abi names may actually be the same ABI // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI let source_map = self.tcx.sess.source_map(); - if source_map.span_to_snippet(*prev_sp) - != source_map.span_to_snippet(*abi_span) - { - err.note("these ABIs are equivalent on the current target"); - } + let equivalent = (source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span)) + .then_some(()); - err.emit(); + self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes { + abi_span: *abi_span, + prev_name: *prev_name, + prev_span: *prev_sp, + equivalent, + }); } None => { - clobber_abis.insert(abi, (abi_name, *abi_span)); + clobber_abis.insert(abi, (*abi_name, *abi_span)); } } } Err(&[]) => { - self.tcx - .sess - .struct_span_err( - *abi_span, - "`clobber_abi` is not supported on this target", - ) - .emit(); + self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span }); } Err(supported_abis) => { - let mut err = self - .tcx - .sess - .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); } - err.note(&format!( - "the following ABIs are supported on this target: {}", - abis - )); - err.emit(); + self.tcx.sess.emit_err(InvalidAbiClobberAbi { + abi_span: *abi_span, + supported_abis: abis, + }); } } } @@ -141,24 +124,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .iter() .map(|(op, op_sp)| { let lower_reg = |reg| match reg { - InlineAsmRegOrRegClass::Reg(s) => { + InlineAsmRegOrRegClass::Reg(reg) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { - asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); + asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| { + sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error }); asm::InlineAsmReg::Err }) } else { asm::InlineAsmReg::Err }) } - InlineAsmRegOrRegClass::RegClass(s) => { + InlineAsmRegOrRegClass::RegClass(reg_class) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { - asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register class `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); - asm::InlineAsmRegClass::Err - }) + asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( + |error| { + sess.emit_err(InvalidRegisterClass { + op_span: *op_sp, + reg_class, + error, + }); + asm::InlineAsmRegClass::Err + }, + ) } else { asm::InlineAsmRegClass::Err }) @@ -168,26 +155,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let op = match *op { InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In { reg: lower_reg(reg), - expr: self.lower_expr_mut(expr), + expr: self.lower_expr(expr), }, InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out { reg: lower_reg(reg), late, - expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + expr: expr.as_ref().map(|expr| self.lower_expr(expr)), }, InlineAsmOperand::InOut { reg, late, ref expr } => { hir::InlineAsmOperand::InOut { reg: lower_reg(reg), late, - expr: self.lower_expr_mut(expr), + expr: self.lower_expr(expr), } } InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { hir::InlineAsmOperand::SplitInOut { reg: lower_reg(reg), late, - in_expr: self.lower_expr_mut(in_expr), - out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + in_expr: self.lower_expr(in_expr), + out_expr: out_expr.as_ref().map(|expr| self.lower_expr(expr)), } } InlineAsmOperand::Const { ref anon_const } => { @@ -233,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); hir::InlineAsmOperand::SymStatic { path, def_id } } else { @@ -282,50 +269,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let valid_modifiers = class.valid_modifiers(asm_arch.unwrap()); if !valid_modifiers.contains(&modifier) { - let mut err = sess.struct_span_err( - placeholder_span, - "invalid asm template modifier for this register class", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - if !valid_modifiers.is_empty() { + let sub = if !valid_modifiers.is_empty() { let mut mods = format!("`{}`", valid_modifiers[0]); for m in &valid_modifiers[1..] { let _ = write!(mods, ", `{}`", m); } - err.note(&format!( - "the `{}` register class supports \ - the following template modifiers: {}", - class.name(), - mods - )); + InvalidAsmTemplateModifierRegClassSub::SupportModifier { + class_name: class.name(), + modifiers: mods, + } } else { - err.note(&format!( - "the `{}` register class does not support template modifiers", - class.name() - )); - } - err.emit(); + InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier { + class_name: class.name(), + } + }; + sess.emit_err(InvalidAsmTemplateModifierRegClass { + placeholder_span, + op_span: op_sp, + sub, + }); } } hir::InlineAsmOperand::Const { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierConst { placeholder_span, - "asm template modifiers are not allowed for `const` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierSym { placeholder_span, - "asm template modifiers are not allowed for `sym` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } } } @@ -346,12 +322,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // require that the operand name an explicit register, not a // register class. if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { - let msg = format!( - "register class `{}` can only be used as a clobber, \ - not as an input or output", - reg_class.name() - ); - sess.struct_span_err(op_sp, &msg).emit(); + sess.emit_err(RegisterClassOnlyClobber { + op_span: op_sp, + reg_class_name: reg_class.name(), + }); continue; } @@ -391,16 +365,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { unreachable!(); }; - let msg = format!( - "register `{}` conflicts with register `{}`", - reg.name(), - reg2.name() - ); - let mut err = sess.struct_span_err(op_sp, &msg); - err.span_label(op_sp, &format!("register `{}`", reg.name())); - err.span_label(op_sp2, &format!("register `{}`", reg2.name())); - - match (op, op2) { + let in_out = match (op, op2) { ( hir::InlineAsmOperand::In { .. }, hir::InlineAsmOperand::Out { late, .. }, @@ -411,14 +376,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) => { assert!(!*late); let out_op_sp = if input { op_sp2 } else { op_sp }; - let msg = "use `lateout` instead of \ - `out` to avoid conflict"; - err.span_help(out_op_sp, msg); - } - _ => {} - } + Some(out_op_sp) + }, + _ => None, + }; - err.emit(); + sess.emit_err(RegisterConflict { + op_span1: op_sp, + op_span2: op_sp2, + reg1_name: reg.name(), + reg2_name: reg2.name(), + in_out + }); } Entry::Vacant(v) => { if r == reg { diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 7cbfe143b..12a0cc0d2 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,8 +1,6 @@ use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; use rustc_hir as hir; -use rustc_session::parse::feature_err; -use rustc_span::sym; use smallvec::SmallVec; @@ -87,20 +85,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ty = l .ty .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); + .map(|t| self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); let els = if let LocalKind::InitElse(_, els) = &l.kind { - if !self.tcx.features().let_else { - feature_err( - &self.tcx.sess.parse_sess, - sym::let_else, - l.span, - "`let...else` statements are unstable", - ) - .emit(); - } Some(self.lower_block(els, false)) } else { None diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs new file mode 100644 index 000000000..c87d0ca96 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -0,0 +1,347 @@ +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")] +pub struct GenericTypeWithParentheses { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(Clone, Copy)] +pub struct UseAngleBrackets { + pub open_param: Span, + pub close_param: Span, +} + +impl AddSubdiagnostic for UseAngleBrackets { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(SessionDiagnostic)] +#[help] +#[diag(ast_lowering::invalid_abi, code = "E0703")] +pub struct InvalidAbi { + #[primary_span] + #[label] + pub span: Span, + pub abi: Symbol, + pub valid_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::assoc_ty_parentheses)] +pub struct AssocTyParentheses { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: AssocTyParenthesesSub, +} + +#[derive(Clone, Copy)] +pub enum AssocTyParenthesesSub { + Empty { parentheses_span: Span }, + NotEmpty { open_param: Span, close_param: Span }, +} + +impl AddSubdiagnostic for AssocTyParenthesesSub { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::Empty { parentheses_span } => diag.multipart_suggestion( + fluent::ast_lowering::remove_parentheses, + vec![(parentheses_span, String::new())], + Applicability::MaybeIncorrect, + ), + Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(open_param, String::from("<")), (close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ), + }; + } +} + +#[derive(SessionDiagnostic)] +#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")] +pub struct MisplacedImplTrait<'a> { + #[primary_span] + pub span: Span, + pub position: DiagnosticArgFromDisplay<'a>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::rustc_box_attribute_error)] +pub struct RustcBoxAttributeError { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::underscore_expr_lhs_assign)] +pub struct UnderscoreExprLhsAssign { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::base_expression_double_dot)] +pub struct BaseExpressionDoubleDot { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")] +pub struct AwaitOnlyInAsyncFnAndBlocks { + #[primary_span] + #[label] + pub dot_await_span: Span, + #[label(ast_lowering::this_not_async)] + pub item_span: Option, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")] +pub struct GeneratorTooManyParameters { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")] +pub struct ClosureCannotBeStatic { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")] +pub struct AsyncNonMoveClosureNotSupported { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::functional_record_update_destructuring_assignment)] +pub struct FunctionalRecordUpdateDestructuringAssignemnt { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::async_generators_not_supported, code = "E0727")] +pub struct AsyncGeneratorsNotSupported { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")] +pub struct InlineAsmUnsupportedTarget { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::att_syntax_only_x86)] +pub struct AttSyntaxOnlyX86 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::abi_specified_multiple_times)] +pub struct AbiSpecifiedMultipleTimes { + #[primary_span] + pub abi_span: Span, + pub prev_name: Symbol, + #[label] + pub prev_span: Span, + #[note] + pub equivalent: Option<()>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::clobber_abi_not_supported)] +pub struct ClobberAbiNotSupported { + #[primary_span] + pub abi_span: Span, +} + +#[derive(SessionDiagnostic)] +#[note] +#[diag(ast_lowering::invalid_abi_clobber_abi)] +pub struct InvalidAbiClobberAbi { + #[primary_span] + pub abi_span: Span, + pub supported_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_register)] +pub struct InvalidRegister<'a> { + #[primary_span] + pub op_span: Span, + pub reg: Symbol, + pub error: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_register_class)] +pub struct InvalidRegisterClass<'a> { + #[primary_span] + pub op_span: Span, + pub reg_class: Symbol, + pub error: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)] +pub struct InvalidAsmTemplateModifierRegClass { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, + #[subdiagnostic] + pub sub: InvalidAsmTemplateModifierRegClassSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidAsmTemplateModifierRegClassSub { + #[note(ast_lowering::support_modifiers)] + SupportModifier { class_name: Symbol, modifiers: String }, + #[note(ast_lowering::does_not_support_modifiers)] + DoesNotSupportModifier { class_name: Symbol }, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_asm_template_modifier_const)] +pub struct InvalidAsmTemplateModifierConst { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_asm_template_modifier_sym)] +pub struct InvalidAsmTemplateModifierSym { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::register_class_only_clobber)] +pub struct RegisterClassOnlyClobber { + #[primary_span] + pub op_span: Span, + pub reg_class_name: Symbol, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::register_conflict)] +pub struct RegisterConflict<'a> { + #[primary_span] + #[label(ast_lowering::register1)] + pub op_span1: Span, + #[label(ast_lowering::register2)] + pub op_span2: Span, + pub reg1_name: &'a str, + pub reg2_name: &'a str, + #[help] + pub in_out: Option, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[diag(ast_lowering::sub_tuple_binding)] +pub struct SubTupleBinding<'a> { + #[primary_span] + #[label] + #[suggestion_verbose( + ast_lowering::sub_tuple_binding_suggestion, + code = "..", + applicability = "maybe-incorrect" + )] + pub span: Span, + pub ident: Ident, + pub ident_name: Symbol, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::extra_double_dot)] +pub struct ExtraDoubleDot<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(ast_lowering::previously_used_here)] + pub prev_span: Span, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[note] +#[diag(ast_lowering::misplaced_double_dot)] +pub struct MisplacedDoubleDot { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::misplaced_relax_trait_bound)] +pub struct MisplacedRelaxTraitBound { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)] +pub struct NotSupportedForLifetimeBinderAsyncClosure { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::arbitrary_expression_in_pattern)] +pub struct ArbitraryExpressionInPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::inclusive_range_with_no_end)] +pub struct InclusiveRangeWithNoEnd { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::trait_fn_async, code = "E0706")] +#[note] +#[note(ast_lowering::note2)] +pub struct TraitFnAsync { + #[primary_span] + pub fn_span: Span, + #[label] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index fb6715ff1..7b8070d3c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,19 +1,23 @@ +use super::errors::{ + AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, + BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, + GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, + RustcBoxAttributeError, UnderscoreExprLhsAssign, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use crate::{FnDeclKind, ImplTraitPosition}; - use rustc_ast::attr; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Ident}; use rustc_span::DUMMY_SP; +use thin_vec::thin_vec; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -46,13 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(e.id); return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; } else { - self.tcx.sess - .struct_span_err( - e.span, - "#[rustc_box] requires precisely one argument \ - and no other attributes are allowed", - ) - .emit(); + self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span }); hir::ExprKind::Err } } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { @@ -68,10 +66,12 @@ impl<'hir> LoweringContext<'_, 'hir> { seg, ParamMode::Optional, ParenthesizedGenericArgs::Err, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); - let args = self.lower_exprs(args); - hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span)) + let receiver = self.lower_expr(&args[0]); + let args = + self.arena.alloc_from_iter(args[1..].iter().map(|x| self.lower_expr_mut(x))); + hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span)) } ExprKind::Binary(binop, ref lhs, ref rhs) => { let binop = self.lower_binop(binop); @@ -90,13 +90,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Cast(ref expr, ref ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(ref expr, ref ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ref ohs) => { @@ -146,13 +146,19 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), ExprKind::Await(ref expr) => { - let span = if expr.span.hi() < e.span.hi() { - expr.span.shrink_to_hi().with_hi(e.span.hi()) + let dot_await_span = if expr.span.hi() < e.span.hi() { + let span_with_whitespace = self + .tcx + .sess + .source_map() + .span_extend_while(expr.span, char::is_whitespace) + .unwrap_or(expr.span); + span_with_whitespace.shrink_to_hi().with_hi(e.span.hi()) } else { // this is a recovered `await expr` e.span }; - self.lower_expr_await(span, expr) + self.lower_expr_await(dot_await_span, expr) } ExprKind::Closure( ref binder, @@ -210,13 +216,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } ExprKind::Underscore => { - self.tcx - .sess.struct_span_err( - e.span, - "in expressions, `_` can only be used on the left-hand side of an assignment", - ) - .span_label(e.span, "`_` not allowed here") - .emit(); + self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); hir::ExprKind::Err } ExprKind::Path(ref qself, ref path) => { @@ -225,7 +225,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); hir::ExprKind::Path(qpath) } @@ -248,11 +248,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Rest(sp) => { - self.tcx - .sess - .struct_span_err(*sp, "base expression required after `..`") - .span_label(*sp, "add a base expression here") - .emit(); + self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp }); Some(&*self.arena.alloc(self.expr_err(*sp))) } StructRest::None => None, @@ -263,7 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), )), self.arena .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))), @@ -446,12 +442,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond)); let new_cond = self.manage_let_cond(lowered_cond); let then = self.lower_block_expr(body); - let expr_break = self.expr_break(span, ThinVec::new()); + let expr_break = self.expr_break(span, AttrVec::new()); let stmt_break = self.stmt_expr(span, expr_break); let else_blk = self.block_all(span, arena_vec![self; stmt_break], None); - let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new())); + let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new())); let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr)); - let if_expr = self.expr(span, if_kind, ThinVec::new()); + let if_expr = self.expr(span, if_kind, AttrVec::new()); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); let opt_label = self.lower_label(opt_label); @@ -510,7 +506,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let constructor = self.arena.alloc(self.expr_lang_item_path( method_span, lang_item, - ThinVec::new(), + AttrVec::new(), None, )); self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) @@ -562,7 +558,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let output = match ret_ty { Some(ty) => hir::FnRetTy::Return( - self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)), + self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)), ), None => hir::FnRetTy::DefaultReturn(self.lower_span(span)), }; @@ -587,7 +583,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (pat, task_context_hid) = self.pat_ident_binding_mode( span, Ident::with_dummy_span(sym::_task_context), - hir::BindingAnnotation::Mutable, + hir::BindingAnnotation::MUT, ); let param = hir::Param { hir_id: self.next_id(), @@ -633,7 +629,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let gen_future = self.expr_lang_item_path( unstable_span, hir::LangItem::FromGenerator, - ThinVec::new(), + AttrVec::new(), None, ); @@ -661,17 +657,10 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { - let mut err = struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { dot_await_span, - E0728, - "`await` is only allowed inside `async` functions and blocks" - ); - err.span_label(dot_await_span, "only allowed inside `async` functions and blocks"); - if let Some(item_sp) = self.current_item { - err.span_label(item_sp, "this is not `async`"); - } - err.emit(); + item_span: self.current_item, + }); } } let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); @@ -688,7 +677,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // this name to identify what is being awaited by a suspended async functions. let awaitee_ident = Ident::with_dummy_span(sym::__awaitee); let (awaitee_pat, awaitee_pat_hid) = - self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable); + self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT); let task_context_ident = Ident::with_dummy_span(sym::_task_context); @@ -745,7 +734,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); - this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new())) + this.arena.alloc(this.expr(gen_future_span, expr_break, AttrVec::new())) }); self.arm(ready_pat, break_x) }; @@ -778,7 +767,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let yield_expr = self.expr( span, hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }), - ThinVec::new(), + AttrVec::new(), ); let yield_expr = self.arena.alloc(yield_expr); @@ -866,7 +855,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None); + let fn_decl = self.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { binder: binder_clause, @@ -891,13 +880,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match generator_kind { Some(hir::GeneratorKind::Gen) => { if decl.inputs.len() > 1 { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0628, - "too many parameters for a generator (expected 0 or 1 parameters)" - ) - .emit(); + self.tcx.sess.emit_err(GeneratorTooManyParameters { fn_decl_span }); } Some(movability) } @@ -906,13 +889,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } None => { if movability == Movability::Static { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ) - .emit(); + self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span }); } None } @@ -945,10 +922,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, ) -> hir::ExprKind<'hir> { if let &ClosureBinder::For { span, .. } = binder { - self.tcx.sess.span_err( - span, - "`for<...>` binders on `async` closures are not currently supported", - ); + self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); } let (binder_clause, generic_params) = self.lower_closure_binder(binder); @@ -959,17 +933,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = self.with_new_scopes(|this| { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { - struct_span_err!( - this.tcx.sess, - fn_decl_span, - E0708, - "`async` non-`move` closures with parameters are not currently supported", - ) - .help( - "consider using `let` statements to manually capture \ - variables by reference before entering an `async move` closure", - ) - .emit(); + this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); } // Transform `async |x: u8| -> X { ... }` into @@ -985,17 +949,17 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AsyncGeneratorKind::Closure, |this| this.with_new_scopes(|this| this.lower_expr_mut(body)), ); - this.expr(fn_decl_span, async_body, ThinVec::new()) + this.expr(fn_decl_span, async_body, AttrVec::new()) }); body_id }); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); - // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); + let fn_decl = + self.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { binder: binder_clause, @@ -1165,11 +1129,14 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a tuple struct. - let tuple_struct_pat = - hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0)); + let tuple_struct_pat = hir::PatKind::TupleStruct( + qpath, + pats, + hir::DotDotPos::new(rest.map(|r| r.0)), + ); return self.pat_without_dbm(lhs.span, tuple_struct_pat); } } @@ -1181,7 +1148,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a unit struct. let unit_struct_pat = hir::PatKind::Path(qpath); @@ -1205,24 +1172,13 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let fields_omitted = match &se.rest { StructRest::Base(e) => { - self.tcx - .sess - .struct_span_err( - e.span, - "functional record updates are not allowed in destructuring \ - assignments", - ) - .span_suggestion( - e.span, - "consider removing the trailing pattern", - "", - rustc_errors::Applicability::MachineApplicable, - ) - .emit(); + self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt { + span: e.span, + }); true } StructRest::Rest(_) => true, @@ -1235,13 +1191,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Tup(elements) => { let (pats, rest) = self.destructure_sequence(elements, "tuple", eq_sign_span, assignments); - let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0)); + let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0))); return self.pat_without_dbm(lhs.span, tuple_pat); } ExprKind::Paren(e) => { // We special-case `(..)` for consistency with patterns. if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind { - let tuple_pat = hir::PatKind::Tuple(&[], Some(0)); + let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0))); return self.pat_without_dbm(lhs.span, tuple_pat); } else { return self.destructure_assign_mut(e, eq_sign_span, assignments); @@ -1255,7 +1211,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ident = self.expr_ident(lhs.span, ident, binding); let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span)); - let expr = self.expr(lhs.span, assign, ThinVec::new()); + let expr = self.expr(lhs.span, assign, AttrVec::new()); assignments.push(self.stmt_expr(lhs.span, expr)); pat } @@ -1297,7 +1253,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None); let fn_expr = - self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), AttrVec::new())); hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } @@ -1317,7 +1273,13 @@ impl<'hir> LoweringContext<'_, 'hir> { (Some(..), Some(..), HalfOpen) => hir::LangItem::Range, (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, (Some(..), Some(..), Closed) => unreachable!(), - (_, None, Closed) => self.diagnostic().span_fatal(span, "inclusive range with no end"), + (start, None, Closed) => { + self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span }); + match start { + Some(..) => hir::LangItem::RangeFrom, + None => hir::LangItem::RangeFull, + } + } }; let fields = self.arena.alloc_from_iter( @@ -1404,8 +1366,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs); hir::ExprField { - hir_id: self.next_id(), + hir_id, ident: self.lower_ident(f.ident), expr: self.lower_expr(&f.expr), span: self.lower_span(f.span), @@ -1417,13 +1381,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Gen) => {} Some(hir::GeneratorKind::Async(_)) => { - struct_span_err!( - self.tcx.sess, - span, - E0727, - "`async` generators are not yet supported" - ) - .emit(); + self.tcx.sess.emit_err(AsyncGeneratorsNotSupported { span }); } None => self.generator_kind = Some(hir::GeneratorKind::Gen), } @@ -1468,7 +1426,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `None => break` let none_arm = { let break_expr = - self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new())); + self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, AttrVec::new())); let pat = self.pat_none(for_span); self.arm(pat, break_expr) }; @@ -1477,14 +1435,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let some_arm = { let some_pat = self.pat_some(pat_span, pat); let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); - let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new())); + let body_expr = self.arena.alloc(self.expr_block(body_block, AttrVec::new())); self.arm(some_pat, body_expr) }; // `mut iter` let iter = Ident::with_dummy_span(sym::iter); let (iter_pat, iter_pat_nid) = - self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable); + self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT); // `match Iterator::next(&mut iter) { ... }` let match_expr = { @@ -1534,15 +1492,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::MatchSource::ForLoopDesugar, )); - let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect(); - // This is effectively `{ let _result = ...; _result }`. // The construct was introduced in #21984 and is necessary to make sure that // temporaries in the `head` expression are dropped and do not leak to the // surrounding scope of the `match` since the `match` is not a terminating scope. // // Also, add the attributes to the outer returned expr node. - self.expr_drop_temps_mut(for_span, match_expr, attrs.into()) + self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone()) } /// Desugar `ExprKind::Try` from: `?` into: @@ -1592,9 +1548,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let uc_nested = attr::mk_nested_word_item(uc_ident); attr::mk_list_item(allow_ident, vec![uc_nested]) }; - attr::mk_attr_outer(allow) + attr::mk_attr_outer(&self.tcx.sess.parse_sess.attr_id_generator, allow) }; - let attrs = vec![attr]; + let attrs: AttrVec = thin_vec![attr]; // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,` let continue_arm = { @@ -1604,7 +1560,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, val_ident, val_pat_nid, - ThinVec::from(attrs.clone()), + attrs.clone(), )); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) @@ -1623,7 +1579,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(residual_expr), unstable_span, ); - let thin_attrs = ThinVec::from(attrs); let ret_expr = if let Some(catch_node) = self.catch_scope { let target_id = Ok(self.lower_node_id(catch_node)); self.arena.alloc(self.expr( @@ -1632,13 +1587,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::Destination { label: None, target_id }, Some(from_residual_expr), ), - thin_attrs, + attrs, )) } else { self.arena.alloc(self.expr( try_span, hir::ExprKind::Ret(Some(from_residual_expr)), - thin_attrs, + attrs, )) }; @@ -1726,7 +1681,7 @@ impl<'hir> LoweringContext<'_, 'hir> { arms: &'hir [hir::Arm<'hir>], source: hir::MatchSource, ) -> hir::Expr<'hir> { - self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new()) + self.expr(span, hir::ExprKind::Match(arg, arms, source), AttrVec::new()) } fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> { @@ -1743,12 +1698,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr( span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e), - ThinVec::new(), + AttrVec::new(), ) } fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> { - self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), ThinVec::new())) + self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), AttrVec::new())) } fn expr_call_mut( @@ -1757,7 +1712,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e: &'hir hir::Expr<'hir>, args: &'hir [hir::Expr<'hir>], ) -> hir::Expr<'hir> { - self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new()) + self.expr(span, hir::ExprKind::Call(e, args), AttrVec::new()) } fn expr_call( @@ -1777,7 +1732,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: Option, ) -> hir::Expr<'hir> { let path = - self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id)); + self.arena.alloc(self.expr_lang_item_path(span, lang_item, AttrVec::new(), hir_id)); self.expr_call_mut(span, path, args) } @@ -1820,7 +1775,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident: Ident, binding: hir::HirId, ) -> hir::Expr<'hir> { - self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new()) + self.expr_ident_with_attrs(sp, ident, binding, AttrVec::new()) } fn expr_ident_with_attrs( @@ -1830,12 +1785,14 @@ impl<'hir> LoweringContext<'_, 'hir> { binding: hir::HirId, attrs: AttrVec, ) -> hir::Expr<'hir> { + let hir_id = self.next_id(); + let res = Res::Local(binding); let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), - res: Res::Local(binding), - segments: arena_vec![self; hir::PathSegment::from_ident(ident)], + res, + segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)], }), )); @@ -1858,13 +1815,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }), None, ), - ThinVec::new(), + AttrVec::new(), ) } fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> { let blk = self.block_all(span, &[], None); - let expr = self.expr_block(blk, ThinVec::new()); + let expr = self.expr_block(blk, AttrVec::new()); self.arena.alloc(expr) } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index d5af74d47..85846b567 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -11,8 +11,6 @@ use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; -use tracing::debug; - /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { /// Source map @@ -31,7 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> { definitions: &'a definitions::Definitions, } -#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))] +#[instrument(level = "debug", skip(sess, definitions, bodies))] pub(super) fn index_hir<'hir>( sess: &Session, definitions: &definitions::Definitions, @@ -67,10 +65,11 @@ pub(super) fn index_hir<'hir>( } impl<'a, 'hir> NodeCollector<'a, 'hir> { - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { debug_assert_eq!(self.owner, hir_id.owner); debug_assert_ne!(hir_id.local_id.as_u32(), 0); + debug_assert_ne!(hir_id.local_id, self.parent_node); // Make sure that the DepNode of some node coincides with the HirId // owner of that node. @@ -142,7 +141,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, i: &'hir Item<'hir>) { debug_assert_eq!(i.def_id, self.owner); self.with_parent(i.hir_id(), |this| { @@ -156,7 +155,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { debug_assert_eq!(fi.def_id, self.owner); self.with_parent(fi.hir_id(), |this| { @@ -175,7 +174,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { debug_assert_eq!(ti.def_id, self.owner); self.with_parent(ti.hir_id(), |this| { @@ -183,7 +182,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { debug_assert_eq!(ii.def_id, self.owner); self.with_parent(ii.hir_id(), |this| { @@ -199,6 +198,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { + self.insert(field.span, field.hir_id, Node::PatField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_pat_field(this, field); + }); + } + fn visit_arm(&mut self, arm: &'hir Arm<'hir>) { let node = Node::Arm(arm); @@ -225,6 +231,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) { + self.insert(field.span, field.hir_id, Node::ExprField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_expr_field(this, field); + }); + } + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); @@ -233,11 +246,9 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) { - if let Some(hir_id) = path_segment.hir_id { - self.insert(path_span, hir_id, Node::PathSegment(path_segment)); - } - intravisit::walk_path_segment(self, path_span, path_segment); + fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) { + self.insert(path_segment.ident.span, path_segment.hir_id, Node::PathSegment(path_segment)); + intravisit::walk_path_segment(self, path_segment); } fn visit_ty(&mut self, ty: &'hir Ty<'hir>) { @@ -269,12 +280,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fk: intravisit::FnKind<'hir>, fd: &'hir FnDecl<'hir>, b: BodyId, - s: Span, + _: Span, id: HirId, ) { assert_eq!(self.owner, id.owner); assert_eq!(self.parent_node, id.local_id); - intravisit::walk_fn(self, fk, fd, b, s, id); + intravisit::walk_fn(self, fk, fd, b, id); } fn visit_block(&mut self, block: &'hir Block<'hir>) { @@ -295,14 +306,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime)); } - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { + fn visit_variant(&mut self, v: &'hir Variant<'hir>) { self.insert(v.span, v.id, Node::Variant(v)); self.with_parent(v.id, |this| { // Register the constructor of this variant. if let Some(ctor_hir_id) = v.data.ctor_hir_id() { this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data)); } - intravisit::walk_variant(this, v, g, item_id); + intravisit::walk_variant(this, v); }); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ee4c0036f..550833275 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,5 +1,6 @@ +use super::errors::{InvalidAbi, MisplacedRelaxTraitBound}; use super::ResolverAstLoweringExt; -use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; +use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; use rustc_ast::ptr::P; @@ -7,7 +8,6 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -25,6 +25,7 @@ use std::iter; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, pub(super) resolver: &'a mut ResolverAstLowering, + pub(super) ast_arena: &'a Arena<'static>, pub(super) ast_index: &'a IndexVec>, pub(super) owners: &'a mut IndexVec>>, } @@ -60,6 +61,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { tcx: self.tcx, resolver: self.resolver, arena: self.tcx.hir_arena, + ast_arena: self.ast_arena, // HirId handling. bodies: Vec::new(), @@ -85,6 +87,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), + generics_def_id_map: Default::default(), }; lctx.with_hir_id_owner(owner, |lctx| f(lctx)); @@ -120,7 +123,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); - hir::OwnerNode::Crate(lctx.arena.alloc(module)) + hir::OwnerNode::Crate(module) }) } @@ -158,14 +161,18 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } impl<'hir> LoweringContext<'_, 'hir> { - pub(super) fn lower_mod(&mut self, items: &[P], spans: &ModSpans) -> hir::Mod<'hir> { - hir::Mod { + pub(super) fn lower_mod( + &mut self, + items: &[P], + spans: &ModSpans, + ) -> &'hir hir::Mod<'hir> { + self.arena.alloc(hir::Mod { spans: hir::ModSpans { inner_span: self.lower_span(spans.inner_span), inject_use_span: self.lower_span(spans.inject_use_span), }, item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))), - } + }) } pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { @@ -259,10 +266,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let body_id = this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); - let itctx = ImplTraitContext::Universal; - let (generics, decl) = this.lower_generics(generics, id, itctx, |this| { + let mut itctx = ImplTraitContext::Universal; + let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id) + this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id) }); let sig = hir::FnSig { decl, @@ -306,8 +313,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy), ); hir::ItemKind::TyAlias(ty, generics) } @@ -319,7 +326,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)), ); hir::ItemKind::TyAlias(ty, generics) @@ -328,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, variants) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.arena.alloc_from_iter( enum_definition.variants.iter().map(|x| this.lower_variant(x)), @@ -341,7 +348,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, struct_def) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), ); hir::ItemKind::Struct(struct_def, generics) @@ -350,7 +357,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, vdata) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), ); hir::ItemKind::Union(vdata, generics) @@ -378,18 +385,18 @@ impl<'hir> LoweringContext<'_, 'hir> { // method, it will not be considered an in-band // lifetime to be added, but rather a reference to a // parent lifetime. - let itctx = ImplTraitContext::Universal; + let mut itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, id, itctx, |this| { + self.lower_generics(ast_generics, id, &mut itctx, |this| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, - ImplTraitContext::Disallowed(ImplTraitPosition::Trait), + &ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) }); let lowered_ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (trait_ref, lowered_ty) }); @@ -428,11 +435,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (unsafety, items, bounds)) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let bounds = this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ); let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), @@ -447,11 +454,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, bounds) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) }, ); @@ -474,7 +481,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (ty, self.lower_const_body(span, body)) } @@ -647,12 +654,18 @@ impl<'hir> LoweringContext<'_, 'hir> { kind: match i.kind { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { let fdec = &sig.decl; - let itctx = ImplTraitContext::Universal; + let mut itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, i.id, itctx, |this| { + self.lower_generics(generics, i.id, &mut itctx, |this| { ( // Disallow `impl Trait` in foreign items. - this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None), + this.lower_fn_decl( + fdec, + None, + sig.span, + FnDeclKind::ExternFn, + None, + ), this.lower_fn_params_to_names(fdec), ) }); @@ -661,7 +674,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ForeignItemKind::Static(ref t, m, _) => { let ty = - self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ForeignItemKind::Static(ty, m) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -729,11 +742,11 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124) - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); self.arena.alloc(t) } else { - self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }; let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs); @@ -756,14 +769,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind, has_default) = match i.kind { AssocItemKind::Const(_, ref ty, ref default) => { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => { + let asyncness = sig.header.asyncness; let names = self.lower_fn_params_to_names(&sig.decl); - let (generics, sig) = - self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None); + let (generics, sig) = self.lower_method_sig( + generics, + sig, + i.id, + FnDeclKind::Trait, + asyncness.opt_return_id(), + ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => { @@ -791,15 +810,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( &generics, i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { - this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + this.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }); hir::TraitItemKind::Type( this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, ) @@ -852,7 +871,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); ( hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), @@ -879,14 +898,14 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( &generics, i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err)); hir::ImplItemKind::TyAlias(ty) } Some(ty) => { - let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy); + let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy); hir::ImplItemKind::TyAlias(ty) } }, @@ -947,7 +966,11 @@ impl<'hir> LoweringContext<'_, 'hir> { params: &'hir [hir::Param<'hir>], value: hir::Expr<'hir>, ) -> hir::BodyId { - let body = hir::Body { generator_kind: self.generator_kind, params, value }; + let body = hir::Body { + generator_kind: self.generator_kind, + params, + value: self.arena.alloc(value), + }; let id = body.id(); debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); @@ -1074,12 +1097,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // Check if this is a binding pattern, if so, we can optimize and avoid adding a // `let = __argN;` statement. In this case, we do not rename the parameter. let (ident, is_simple_parameter) = match parameter.pat.kind { - hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - _, - ident, - _, - ) => (ident, true), + hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { + (ident, true) + } // For `ref mut` or wildcard arguments, we can't reuse the binding, but // we can keep the same name for the parameter. // This lets rustdoc render it correctly in documentation. @@ -1144,7 +1164,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (move_pat, move_id) = this.pat_ident_binding_mode( desugared_span, ident, - hir::BindingAnnotation::Mutable, + hir::BindingAnnotation::MUT, ); let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); let move_stmt = this.stmt_let_pat( @@ -1225,12 +1245,12 @@ impl<'hir> LoweringContext<'_, 'hir> { sig: &FnSig, id: NodeId, kind: FnDeclKind, - is_async: Option, + is_async: Option<(NodeId, Span)>, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); - let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, Some(id), kind, is_async) + let mut itctx = ImplTraitContext::Universal; + let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| { + this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1260,10 +1280,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn error_on_invalid_abi(&self, abi: StrLit) { - struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol) - .span_label(abi.span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); + self.tcx.sess.emit_err(InvalidAbi { + span: abi.span, + abi: abi.symbol, + valid_abis: abi::all_names().join(", "), + }); } fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { @@ -1294,7 +1315,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, parent_node_id: NodeId, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { debug_assert!(self.impl_trait_defs.is_empty()); @@ -1338,11 +1359,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let is_param = *is_param.get_or_insert_with(compute_is_param); if !is_param { - self.diagnostic().span_err( - bound.span(), - "`?Trait` bounds are only permitted at the \ - point where a type parameter is declared", - ); + self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() }); } } } @@ -1403,7 +1420,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: &GenericParamKind, bounds: &[GenericBound], - itctx: ImplTraitContext, + itctx: &ImplTraitContext, origin: PredicateOrigin, ) -> Option> { // Do not create a clause if we do not have anything inside it. @@ -1434,10 +1451,14 @@ impl<'hir> LoweringContext<'_, 'hir> { GenericParamKind::Const { .. } => None, GenericParamKind::Type { .. } => { let def_id = self.local_def_id(id).to_def_id(); + let hir_id = self.next_id(); + let res = Res::Def(DefKind::TyParam, def_id); let ty_path = self.arena.alloc(hir::Path { span: param_span, - res: Res::Def(DefKind::TyParam, def_id), - segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]), + res, + segments: self + .arena + .alloc_from_iter([hir::PathSegment::new(ident, hir_id, res)]), }); let ty_id = self.next_id(); let bounded_ty = @@ -1475,11 +1496,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params: self.lower_generic_params(bound_generic_params), bounded_ty: self - .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { self.lower_param_bound( bound, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) })), span: self.lower_span(span), @@ -1494,17 +1515,16 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime: self.lower_lifetime(lifetime), bounds: self.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), in_where_clause: true, }), - WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => { + WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - hir_id: self.lower_node_id(id), lhs_ty: self - .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), rhs_ty: self - .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), span: self.lower_span(span), }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 224dc3c23..9012aa704 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,14 +32,20 @@ #![feature(box_patterns)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; +use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync}; + +use rustc_arena::declare_arena; +use rustc_ast::ptr::P; use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; @@ -49,7 +55,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability, Handler}; +use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -75,6 +81,7 @@ macro_rules! arena_vec { mod asm; mod block; +mod errors; mod expr; mod index; mod item; @@ -89,6 +96,13 @@ struct LoweringContext<'a, 'hir> { /// Used to allocate HIR nodes. arena: &'hir hir::Arena<'hir>, + /// Used to allocate temporary AST nodes for use during lowering. + /// This allows us to create "fake" AST -- these nodes can sometimes + /// be allocated on the stack, but other times we need them to live longer + /// than the current stack frame, so they can be collected into vectors + /// and things like that. + ast_arena: &'a Arena<'static>, + /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, /// Attributes inside the owner being lowered. @@ -126,8 +140,23 @@ struct LoweringContext<'a, 'hir> { allow_try_trait: Option>, allow_gen_future: Option>, allow_into_future: Option>, + + /// Mapping from generics `def_id`s to TAIT generics `def_id`s. + /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic + /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this + /// field from the original parameter 'a to the new parameter 'a1. + generics_def_id_map: Vec>, } +declare_arena!([ + [] tys: rustc_ast::Ty, + [] aba: rustc_ast::AngleBracketedArgs, + [] ptr: rustc_ast::PolyTraitRef, + // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to + // use `'tcx`. If we don't have this we get a compile error. + [] _marker: std::marker::PhantomData<&'tcx ()>, +]); + trait ResolverAstLoweringExt { fn legacy_const_generic_args(&self, expr: &Expr) -> Option>; fn get_partial_res(&self, id: NodeId) -> Option; @@ -136,12 +165,6 @@ trait ResolverAstLoweringExt { fn get_lifetime_res(&self, id: NodeId) -> Option; fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind; - /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map` - /// field. - fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId); - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId; } impl ResolverAstLoweringExt for ResolverAstLowering { @@ -209,41 +232,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering { fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind { self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang) } - - /// Push a remapping into the top-most map. - /// Panics if no map has been pushed. - /// Remapping is used when creating lowering `-> impl Trait` return - /// types to create the resulting opaque type. - #[tracing::instrument(level = "debug", skip(self))] - fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) { - self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to); - } - - fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings so we need to try first the latest mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, We want the result to be: - // impl_sized#'b, so iterating forward is the wrong thing to do. - for map in self.generics_def_id_map.iter().rev() { - if let Some(r) = map.get(&local_def_id) { - debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`"); - local_def_id = *r; - } else { - debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map"); - } - } - - local_def_id - } } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, @@ -264,6 +252,7 @@ enum ImplTraitContext { ReturnPositionOpaqueTy { /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, origin: hir::OpaqueTyOrigin, + in_trait: bool, }, /// Impl trait in type aliases. TypeAliasesOpaqueTy, @@ -323,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] enum FnDeclKind { Fn, Inherent, @@ -335,9 +324,17 @@ enum FnDeclKind { } impl FnDeclKind { - fn impl_trait_return_allowed(&self) -> bool { + fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool { match self { FnDeclKind::Fn | FnDeclKind::Inherent => true, + FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true, + _ => false, + } + } + + fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { + match self { + FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true, _ => false, } } @@ -430,10 +427,13 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> { tcx.definitions_untracked().def_index_count(), ); + let ast_arena = Arena::default(); + for def_id in ast_index.indices() { item::ItemLowerer { tcx, resolver: &mut resolver, + ast_arena: &ast_arena, ast_index: &ast_index, owners: &mut owners, } @@ -499,6 +499,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { start } + /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name + /// resolver (if any). + fn orig_opt_local_def_id(&self, node: NodeId) -> Option { + self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id) + } + + fn orig_local_def_id(&self, node: NodeId) -> LocalDefId { + self.orig_opt_local_def_id(node) + .unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) + } + /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any), after applying any remapping from `get_remapped_def_id`. /// @@ -513,16 +524,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`. /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`. fn opt_local_def_id(&self, node: NodeId) -> Option { - self.resolver - .node_id_to_def_id - .get(&node) - .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id)) + self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id)) } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } + /// Get the previously recorded `to` local def id given the `from` local def id, obtained using + /// `generics_def_id_map` field. + fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId { + // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we + // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`. + // + // Consider: + // + // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` + // + // We would end with a generics_def_id_map like: + // + // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` + // + // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b. + // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b. + self.generics_def_id_map + .iter() + .rev() + .find_map(|map| map.get(&local_def_id).map(|local_def_id| *local_def_id)) + .unwrap_or(local_def_id) + } + /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -591,9 +622,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { remap: FxHashMap, f: impl FnOnce(&mut Self) -> R, ) -> R { - self.resolver.generics_def_id_map.push(remap); + self.generics_def_id_map.push(remap); let res = f(self); - self.resolver.generics_def_id_map.pop(); + self.generics_def_id_map.pop(); res } @@ -644,14 +675,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> (Fingerprint, Fingerprint) { self.tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { + hcx.with_hir_bodies(node.def_id(), bodies, |hcx| { node.hash_stable(hcx, &mut stable_hasher) }); let hash_including_bodies = stable_hasher.finish(); let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { - node.hash_stable(hcx, &mut stable_hasher) - }); + hcx.without_hir_bodies(|hcx| node.hash_stable(hcx, &mut stable_hasher)); let hash_without_bodies = stable_hasher.finish(); (hash_including_bodies, hash_without_bodies) }) @@ -663,6 +692,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// actually used in the HIR, as that would trigger an assertion in the /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped /// properly. Calling the method twice with the same `NodeId` is fine though. + #[instrument(level = "debug", skip(self), ret)] fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); @@ -696,6 +726,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Generate a new `HirId` without a backing `NodeId`. + #[instrument(level = "debug", skip(self), ret)] fn next_id(&mut self) -> hir::HirId { let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; @@ -767,7 +798,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Converts a lifetime into a new generic parameter. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lifetime_res_to_generic_param( &mut self, ident: Ident, @@ -811,7 +842,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime /// parameters will be successful. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] #[inline] fn lower_lifetime_binder( &mut self, @@ -874,14 +905,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // the `HirId`s. We don't actually need HIR version of attributes anyway. // Tokens are also not needed after macro expansion and parsing. let kind = match attr.kind { - AttrKind::Normal(ref item, _) => AttrKind::Normal( - AttrItem { - path: item.path.clone(), - args: self.lower_mac_args(&item.args), + AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { + item: AttrItem { + path: normal.item.path.clone(), + args: self.lower_mac_args(&normal.item.args), tokens: None, }, - None, - ), + tokens: None, + })), AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), }; @@ -929,8 +960,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lit.clone() } else { Lit { - token: token::Lit::new(token::LitKind::Err, kw::Empty, None), - kind: LitKind::Err(kw::Empty), + token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), + kind: LitKind::Err, span: DUMMY_SP, } }; @@ -956,7 +987,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_assoc_ty_constraint( &mut self, constraint: &AssocConstraint, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); // lower generic arguments of identifier in constraint @@ -967,18 +998,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(ref data) => { self.emit_bad_parenthesized_trait_in_assoc_ty(data); - self.lower_angle_bracketed_parameter_data( - &data.as_angle_bracketed_args(), - ParamMode::Explicit, - itctx, - ) - .0 + let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args()); + self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0 } }; gen_args_ctor.into_generic_args(self) } else { self.arena.alloc(hir::GenericArgs::none()) }; + let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy; let kind = match constraint.kind { AssocConstraintKind::Equality { ref term } => { @@ -1016,9 +1044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // then to an opaque type). // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. - ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - (true, ImplTraitContext::TypeAliasesOpaqueTy) - } + ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait), // We are in the parameter position, but not within a dyn type: // @@ -1040,15 +1066,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.with_dyn_type_scope(false, |this| { let node_id = this.next_node_id(); - let ty = this.lower_ty( - &Ty { - id: node_id, - kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), - span: this.lower_span(constraint.span), - tokens: None, - }, - itctx, - ); + let ty = this.ast_arena.tys.alloc(Ty { + id: node_id, + kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), + span: this.lower_span(constraint.span), + tokens: None, + }); + let ty = this.lower_ty(ty, itctx); hir::TypeBindingKind::Equality { term: ty.into() } }) @@ -1072,19 +1096,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) { - let mut err = self.tcx.sess.struct_span_err( - data.span, - "parenthesized generic arguments cannot be used in associated type constraints", - ); // Suggest removing empty parentheses: "Trait()" -> "Trait" - if data.inputs.is_empty() { + let sub = if data.inputs.is_empty() { let parentheses_span = data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - "remove these parentheses", - vec![(parentheses_span, String::new())], - Applicability::MaybeIncorrect, - ); + AssocTyParenthesesSub::Empty { parentheses_span } } // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` else { @@ -1098,20 +1114,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // End of last argument to end of parameters let close_param = data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![(open_param, String::from("<")), (close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + AssocTyParenthesesSub::NotEmpty { open_param, close_param } + }; + self.tcx.sess.emit_err(AssocTyParentheses { span: data.span, sub }); } #[instrument(level = "debug", skip(self))] fn lower_generic_arg( &mut self, arg: &ast::GenericArg, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), @@ -1163,7 +1175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } _ => {} } - GenericArg::Type(self.lower_ty_direct(&ty, itctx)) + GenericArg::Type(self.lower_ty(&ty, itctx)) } ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg { value: self.lower_anon_const(&ct), @@ -1173,7 +1185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: &ImplTraitContext) -> &'hir hir::Ty<'hir> { self.arena.alloc(self.lower_ty_direct(t, itctx)) } @@ -1183,11 +1195,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option, path: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::Ty<'hir> { // Check whether we should interpret this as a bare trait object. // This check mirrors the one in late resolution. We only introduce this special case in - // the rare occurence we need to lower `Fresh` anonymous lifetimes. + // the rare occurrence we need to lower `Fresh` anonymous lifetimes. // The other cases when a qpath should be opportunistically made a trait object are handled // by `ty_path`. if qself.is_none() @@ -1196,19 +1208,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { + let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef { + bound_generic_params: vec![], + trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, + span: t.span + }); let bound = this.lower_poly_trait_ref( - &PolyTraitRef { - bound_generic_params: vec![], - trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, - span: t.span - }, + poly_trait_ref, itctx, ); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) }); - let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None); + let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None); return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; } @@ -1225,7 +1238,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> { let kind = match t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => hir::TyKind::Err, @@ -1241,7 +1254,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.next_node_id() }; - let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo()); + let span = self.tcx.sess.source_map().start_point(t.span); Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } }); let lifetime = self.lower_lifetime(®ion); @@ -1253,7 +1266,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { generic_params, unsafety: self.lower_unsafety(f.unsafety), abi: self.lower_extern(f.ext), - decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), + decl: self.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None), param_names: self.lower_fn_params_to_names(&f.decl), })) } @@ -1268,14 +1281,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); } TyKind::ImplicitSelf => { + let hir_id = self.next_id(); let res = self.expect_full_res(t.id); let res = self.lower_res(res); hir::TyKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { res, - segments: arena_vec![self; hir::PathSegment::from_ident( - Ident::with_dummy_span(kw::SelfUpper) + segments: arena_vec![self; hir::PathSegment::new( + Ident::with_dummy_span(kw::SelfUpper), + hir_id, + res )], span: self.lower_span(t.span), }), @@ -1318,19 +1334,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { origin } => { - self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx) - } - ImplTraitContext::TypeAliasesOpaqueTy => { - let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; - self.lower_opaque_impl_trait( + ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self + .lower_opaque_impl_trait( span, - hir::OpaqueTyOrigin::TyAlias, + *origin, def_node_id, bounds, - nested_itctx, - ) - } + *in_trait, + itctx, + ), + ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait( + span, + hir::OpaqueTyOrigin::TyAlias, + def_node_id, + bounds, + false, + &ImplTraitContext::TypeAliasesOpaqueTy, + ), ImplTraitContext::Universal => { let span = t.span; let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); @@ -1342,15 +1362,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } path } + ImplTraitContext::Disallowed( + position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn), + ) => { + self.tcx + .sess + .create_feature_err( + MisplacedImplTrait { + span: t.span, + position: DiagnosticArgFromDisplay(&position), + }, + sym::return_position_impl_trait_in_trait, + ) + .emit(); + hir::TyKind::Err + } ImplTraitContext::Disallowed(position) => { - let mut err = struct_span_err!( - self.tcx.sess, - t.span, - E0562, - "`impl Trait` only allowed in function and inherent method return types, not in {}", - position - ); - err.emit(); + self.tcx.sess.emit_err(MisplacedImplTrait { + span: t.span, + position: DiagnosticArgFromDisplay(&position), + }); hir::TyKind::Err } } @@ -1397,14 +1428,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters /// for the lifetimes that get captured (`'x`, in our example above) and reference those. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_impl_trait( &mut self, span: Span, origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, - itctx: ImplTraitContext, + in_trait: bool, + itctx: &ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1492,6 +1524,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: hir_bounds, origin, + in_trait, }; debug!(?opaque_ty_item); @@ -1518,7 +1551,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!(?lifetimes); // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes) + hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait) } /// Registers a new opaque type with the proper `NodeId`s and @@ -1577,7 +1610,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, binder: _ } => { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() { + if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() { let node_id = self.next_node_id(); let new_def_id = self.create_def( @@ -1626,19 +1659,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the // given DefId, otherwise impl Trait is disallowed. Must be `Some` if // `make_ret_async` is also `Some`. - // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position. - // This guards against trait declarations and implementations where `impl Trait` is - // disallowed. // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future` in the // return type. This is used for `async fn` declarations. The `NodeId` is the ID of the - // return type `impl Trait` item. - #[tracing::instrument(level = "debug", skip(self))] + // return type `impl Trait` item, and the `Span` points to the `async` keyword. + #[instrument(level = "debug", skip(self))] fn lower_fn_decl( &mut self, decl: &FnDecl, fn_node_id: Option, + fn_span: Span, kind: FnDeclKind, - make_ret_async: Option, + make_ret_async: Option<(NodeId, Span)>, ) -> &'hir hir::FnDecl<'hir> { let c_variadic = decl.c_variadic(); @@ -1651,11 +1682,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { if fn_node_id.is_some() { - self.lower_ty_direct(¶m.ty, ImplTraitContext::Universal) + self.lower_ty_direct(¶m.ty, &ImplTraitContext::Universal) } else { self.lower_ty_direct( ¶m.ty, - ImplTraitContext::Disallowed(match kind { + &ImplTraitContext::Disallowed(match kind { FnDeclKind::Fn | FnDeclKind::Inherent => { unreachable!("fn should allow in-band lifetimes") } @@ -1669,20 +1700,63 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } })); - let output = if let Some(ret_id) = make_ret_async { - self.lower_async_fn_ret_ty( - &decl.output, - fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), - ret_id, - ) + let output = if let Some((ret_id, span)) = make_ret_async { + match kind { + FnDeclKind::Trait => { + if !kind.impl_trait_in_trait_allowed(self.tcx) { + self.tcx + .sess + .create_feature_err( + TraitFnAsync { fn_span, span }, + sym::return_position_impl_trait_in_trait, + ) + .emit(); + } + self.lower_async_fn_ret_ty( + &decl.output, + fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), + ret_id, + true, + ) + } + _ => { + if !kind.impl_trait_return_allowed(self.tcx) { + if kind == FnDeclKind::Impl { + self.tcx + .sess + .create_feature_err( + TraitFnAsync { fn_span, span }, + sym::return_position_impl_trait_in_trait, + ) + .emit(); + } else { + self.tcx.sess.emit_err(TraitFnAsync { fn_span, span }); + } + } + self.lower_async_fn_ret_ty( + &decl.output, + fn_node_id.expect("`make_ret_async` but no `fn_def_id`"), + ret_id, + false, + ) + } + } } else { match decl.output { FnRetTy::Ty(ref ty) => { - let context = match fn_node_id { - Some(fn_node_id) if kind.impl_trait_return_allowed() => { + let mut context = match fn_node_id { + Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => { + let fn_def_id = self.local_def_id(fn_node_id); + ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + in_trait: false, + } + } + Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + in_trait: true, } } _ => ImplTraitContext::Disallowed(match kind { @@ -1696,7 +1770,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnDeclKind::Impl => ImplTraitPosition::ImplReturn, }), }; - hir::FnRetTy::Return(self.lower_ty(ty, context)) + hir::FnRetTy::Return(self.lower_ty(ty, &mut context)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)), } @@ -1707,10 +1781,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output, c_variadic, implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| { - use BindingMode::{ByRef, ByValue}; let is_mutable_pat = matches!( arg.pat.kind, - PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..) + PatKind::Ident(hir::BindingAnnotation(_, Mutability::Mut), ..) ); match arg.ty.kind { @@ -1741,12 +1814,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `output`: unlowered output type (`T` in `-> T`) // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_async_fn_ret_ty( &mut self, output: &FnRetTy, fn_node_id: NodeId, opaque_ty_node_id: NodeId, + in_trait: bool, ) -> hir::FnRetTy<'hir> { let span = output.span(); @@ -1805,7 +1879,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id); debug!(?extra_lifetime_params); for (ident, outer_node_id, outer_res) in extra_lifetime_params { - let outer_def_id = self.local_def_id(outer_node_id); + let outer_def_id = self.orig_local_def_id(outer_node_id); let inner_node_id = self.next_node_id(); // Add a definition for the in scope lifetime def. @@ -1873,8 +1947,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and // hence the elision takes place at the fn site. - let future_bound = - this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span); + let future_bound = this.lower_async_fn_output_type_to_future_bound( + output, + span, + ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + in_trait, + }, + ); let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map( |&(new_node_id, lifetime, _)| { @@ -1912,6 +1992,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: arena_vec![this; future_bound], origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, }; trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id); @@ -1948,8 +2029,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let res = res.unwrap_or( self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), ); - let l = self.new_named_lifetime_with_res(id, span, ident, res); - hir::GenericArg::Lifetime(l) + hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res)) }, )); @@ -1957,8 +2037,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Foo = impl Trait` is, internally, created as a child of the // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. - let opaque_ty_ref = - hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args); + let opaque_ty_ref = hir::TyKind::OpaqueDef( + hir::ItemId { def_id: opaque_ty_def_id }, + generic_args, + in_trait, + ); let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref); hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } @@ -1967,8 +2050,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_async_fn_output_type_to_future_bound( &mut self, output: &FnRetTy, - fn_def_id: LocalDefId, span: Span, + mut nested_impl_trait_context: ImplTraitContext, ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. let output_ty = match output { @@ -1976,10 +2059,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - let context = ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - }; - self.lower_ty(ty, context) + self.lower_ty(ty, &mut nested_impl_trait_context) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -2005,7 +2085,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p, modifier) => hir::GenericBound::Trait( @@ -2018,24 +2098,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { + fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { let span = self.lower_span(l.ident.span); let ident = self.lower_ident(l.ident); self.new_named_lifetime(l.id, l.id, span, ident) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn new_named_lifetime_with_res( &mut self, id: NodeId, span: Span, ident: Ident, res: LifetimeRes, - ) -> hir::Lifetime { + ) -> &'hir hir::Lifetime { let name = match res { LifetimeRes::Param { param, .. } => { let p_name = ParamName::Plain(ident); - let param = self.resolver.get_remapped_def_id(param); + let param = self.get_remapped_def_id(param); hir::LifetimeName::Param(param, p_name) } @@ -2052,17 +2132,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?name); - hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } + self.arena.alloc(hir::Lifetime { + hir_id: self.lower_node_id(id), + span: self.lower_span(span), + name, + }) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn new_named_lifetime( &mut self, id: NodeId, new_id: NodeId, span: Span, ident: Ident, - ) -> hir::Lifetime { + ) -> &'hir hir::Lifetime { let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); self.new_named_lifetime_with_res(new_id, span, ident, res) } @@ -2117,7 +2201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericParamKind::Type { ref default, .. } => { let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { - self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }), synthetic: false, }; @@ -2125,7 +2209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { - let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2135,7 +2219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> { + fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> { let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) { hir::QPath::Resolved(None, path) => path, qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath), @@ -2143,11 +2227,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); @@ -2155,14 +2239,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } } - fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { + fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } + #[instrument(level = "debug", skip(self), ret)] fn lower_param_bounds( &mut self, bounds: &[GenericBound], - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::GenericBounds<'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } @@ -2170,11 +2255,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds_mut<'s>( &'s mut self, bounds: &'s [GenericBound], - itctx: ImplTraitContext, + itctx: &'s ImplTraitContext, ) -> impl Iterator> + Captures<'s> + Captures<'a> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } + #[instrument(level = "debug", skip(self), ret)] fn lower_generic_and_bounds( &mut self, node_id: NodeId, @@ -2200,16 +2286,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { node_id, &GenericParamKind::Type { default: None }, bounds, - ImplTraitContext::Universal, + &ImplTraitContext::Universal, hir::PredicateOrigin::ImplTrait, ); + let hir_id = self.next_id(); + let res = Res::Def(DefKind::TyParam, def_id.to_def_id()); let ty = hir::TyKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), - res: Res::Def(DefKind::TyParam, def_id.to_def_id()), - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))], + res, + segments: + arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], }), )); @@ -2235,7 +2324,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { c.value.span, "using `_` for array lengths is unstable", ) - .emit(); + .stash(c.value.span, StashKey::UnderscoreForArrayLengths); hir::ArrayLen::Body(self.lower_anon_const(c)) } } @@ -2372,11 +2461,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) { - self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated) + self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::NONE) } fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) { - self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated) + self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::NONE) } fn pat_ident_binding_mode( @@ -2465,14 +2554,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// bound, like the bound in `Box`. This method is not invoked /// when the bound is written, even if it is written with `'_` like in /// `Box`. In those cases, `lower_lifetime` is invoked. - fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime { + fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime { let r = hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), name: hir::LifetimeName::ImplicitObjectLifetimeDefault, }; debug!("elided_dyn_bound: r={:?}", r); - r + self.arena.alloc(r) } } diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 81006e00f..914fc5f58 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -1,9 +1,6 @@ use super::ResolverAstLoweringExt; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{ - FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty, - TyKind, -}; +use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_hir::def::LifetimeRes; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; @@ -66,15 +63,15 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { self.record_lifetime_use(*lifetime); } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { - self.record_elided_anchor(path_segment.id, path_span); - visit::walk_path_segment(self, path_span, path_segment); + fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { + self.record_elided_anchor(path_segment.id, path_segment.ident.span); + visit::walk_path_segment(self, path_segment); } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { self.current_binders.push(t.trait_ref.ref_id); - visit::walk_poly_trait_ref(self, t, m); + visit::walk_poly_trait_ref(self, t); self.current_binders.pop(); } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index bd2e76e55..1ea76fdbf 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,3 +1,6 @@ +use super::errors::{ + ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode}; use crate::ImplTraitPosition; @@ -5,7 +8,6 @@ use crate::ImplTraitPosition; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::symbol::Ident; @@ -22,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let node = loop { match pattern.kind { PatKind::Wild => break hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, ident, ref sub) => { + PatKind::Ident(binding_mode, ident, ref sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); } @@ -35,7 +37,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); break hir::PatKind::TupleStruct(qpath, pats, ddpos); @@ -51,7 +53,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); break hir::PatKind::Path(qpath); } @@ -61,15 +63,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField { - hir_id: self.next_id(), - ident: self.lower_ident(f.ident), - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: self.lower_span(f.span), + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs); + + hir::PatField { + hir_id, + ident: self.lower_ident(f.ident), + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: self.lower_span(f.span), + } })); break hir::PatKind::Struct(qpath, fs, etc); } @@ -109,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, pats: &[P], ctx: &str, - ) -> (&'hir [hir::Pat<'hir>], Option) { + ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) { let mut elems = Vec::with_capacity(pats.len()); let mut rest = None; @@ -129,20 +136,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is not allowed as a sub-tuple pattern PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => { let sp = pat.span; - self.diagnostic() - .struct_span_err( - sp, - &format!("`{} @` is not allowed in a {}", ident.name, ctx), - ) - .span_label(sp, "this is only allowed in slice patterns") - .help("remove this and bind each tuple field independently") - .span_suggestion_verbose( - sp, - &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident), - "..", - Applicability::MaybeIncorrect, - ) - .emit(); + self.tcx.sess.emit_err(SubTupleBinding { + span: sp, + ident_name: ident.name, + ident, + ctx, + }); } _ => {} } @@ -161,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos)) + (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos))) } /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into @@ -177,9 +176,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut prev_rest_span = None; // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. - let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| { + let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| { let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = this.lower_pat_ident(pat, bm, ident, lower_sub); + let node = this.lower_pat_ident(pat, ann, ident, lower_sub); this.pat_with_node_id_of(pat, node) }; @@ -195,9 +194,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } // Found a sub-slice pattern `$binding_mode $ident @ ..`. // Record, lower it to `$binding_mode $ident @ _`, and stop here. - PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => { prev_rest_span = Some(sub.span); - slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub))); + slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub))); break; } // It was not a subslice pattern so lower it normally. @@ -210,9 +209,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // There was a previous subslice pattern; make sure we don't allow more. let rest_span = match pat.kind { PatKind::Rest => Some(pat.span), - PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => { // #69103: Lower into `binding @ _` as above to avoid ICEs. - after.push(lower_rest_sub(self, pat, bm, ident, sub)); + after.push(lower_rest_sub(self, pat, ann, ident, sub)); Some(sub.span) } _ => None, @@ -236,7 +235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_ident( &mut self, p: &Pat, - binding_mode: &BindingMode, + annotation: BindingAnnotation, ident: Ident, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { @@ -249,29 +248,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; hir::PatKind::Binding( - self.lower_binding_mode(binding_mode), + annotation, self.lower_node_id(canonical_id), self.lower_ident(ident), lower_sub(self), ) } - Some(res) => hir::PatKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - span: self.lower_span(ident.span), - res: self.lower_res(res), - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))], - }), - )), - } - } - - fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation { - match *b { - BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated, - BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref, - BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable, - BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut, + Some(res) => { + let hir_id = self.next_id(); + let res = self.lower_res(res); + hir::PatKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + span: self.lower_span(ident.span), + res, + segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], + }), + )) + } } } @@ -291,19 +285,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { - self.diagnostic() - .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) - .span_label(sp, &format!("can only be used once per {} pattern", ctx)) - .span_label(prev_sp, "previously used here") - .emit(); + self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx }); } /// Used to ban the `..` pattern in places it shouldn't be semantically. fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { - self.diagnostic() - .struct_span_err(sp, "`..` patterns are not allowed here") - .note("only allowed in tuple, tuple struct, and slice patterns") - .emit(); + self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp }); // We're not in a list context so `..` can be reasonably treated // as `_` because it should always be valid and roughly matches the @@ -340,8 +327,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { - self.diagnostic() - .span_err(expr.span, "arbitrary expressions aren't allowed in patterns"); + self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span }); return self.arena.alloc(self.expr_err(expr.span)); } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 393be3b45..6bb1bb9ea 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,11 +1,11 @@ use crate::ImplTraitPosition; +use super::errors::{GenericTypeWithParentheses, UseAngleBrackets}; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::{self as ast, *}; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::GenericArg; @@ -13,7 +13,6 @@ use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use smallvec::smallvec; -use tracing::debug; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] @@ -23,7 +22,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option, p: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); @@ -157,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, ParenthesizedGenericArgs::Err, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::Path), ) })), span: self.lower_span(p.span), @@ -181,11 +180,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment: &PathSegment, param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { - let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { GenericArgs::AngleBracketed(ref data) => { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) @@ -193,10 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { - let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg); - err.span_label(data.span, "only `Fn` traits may use parentheses"); // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` - if !data.inputs.is_empty() { + let sub = if !data.inputs.is_empty() { // Start of the span to the 1st character of 1st argument let open_param = data.inputs_span.shrink_to_lo().to(data .inputs @@ -212,16 +208,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .span .shrink_to_hi() .to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![ - (open_param, String::from("<")), - (close_param, String::from(">")), - ], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + + Some(UseAngleBrackets { open_param, close_param }) + } else { + None + }; + self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub }); ( self.lower_angle_bracketed_parameter_data( &data.as_angle_bracketed_args(), @@ -258,16 +250,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let res = self.expect_full_res(segment.id); - let id = self.lower_node_id(segment.id); + let hir_id = self.lower_node_id(segment.id); debug!( "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", - segment.ident, segment.id, id, + segment.ident, segment.id, hir_id, ); hir::PathSegment { ident: self.lower_ident(segment.ident), - hir_id: Some(id), - res: Some(self.lower_res(res)), + hir_id, + res: self.lower_res(res), infer_args, args: if generic_args.is_empty() && generic_args.span.is_empty() { None @@ -324,7 +316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &AngleBracketedArgs, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &ImplTraitContext, ) -> (GenericArgsCtor<'hir>, bool) { let has_non_lt_args = data.args.iter().any(|arg| match arg { AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) @@ -358,15 +350,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { FnRetTy::Ty(ty) => { - self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) + self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) } FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; - let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))]; + let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; let binding = self.output_ty_binding(output_ty.span, output_ty); ( GenericArgsCtor { diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 22742b2ad..37eff9207 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 2d9d0073f..b1d10e07a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,9 +13,7 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -29,6 +27,8 @@ use rustc_target::spec::abi; use std::mem; use std::ops::{Deref, DerefMut}; +use crate::errors::*; + const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -121,30 +121,9 @@ impl<'a> AstValidator<'a> { fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { let sess = &self.session; if sess.opts.unstable_features.is_nightly_build() { - let err = "`let` expressions are not supported here"; - let mut diag = sess.struct_span_err(expr.span, err); - diag.note("only supported directly in conditions of `if` and `while` expressions"); - match forbidden_let_reason { - ForbiddenLetReason::GenericForbidden => {} - ForbiddenLetReason::NotSupportedOr(span) => { - diag.span_note( - span, - "`||` operators are not supported in let chain expressions", - ); - } - ForbiddenLetReason::NotSupportedParentheses(span) => { - diag.span_note( - span, - "`let`s wrapped in parentheses are not supported in a context with let \ - chains", - ); - } - } - diag.emit(); + sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); } else { - sess.struct_span_err(expr.span, "expected expression, found statement (`let`)") - .note("variable declaration using `let` is a statement") - .emit(); + sess.emit_err(ForbiddenLetStable { span: expr.span }); } } @@ -175,7 +154,7 @@ impl<'a> AstValidator<'a> { DEPRECATED_WHERE_CLAUSE_LOCATION, id, where_clauses.0.1, - "where clause not allowed here", + fluent::ast_passes::deprecated_where_clause_location, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( where_clauses.1.1.shrink_to_hi(), suggestion, @@ -205,10 +184,7 @@ impl<'a> AstValidator<'a> { AssocConstraintKind::Equality { .. } => {} AssocConstraintKind::Bound { .. } => { if self.is_assoc_ty_bound_banned { - self.err_handler().span_err( - constraint.span, - "associated type bounds are not allowed within structs, enums, or unions", - ); + self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span }); } } } @@ -247,11 +223,9 @@ impl<'a> AstValidator<'a> { 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(path.span, segment); + self.visit_path_segment(segment); } else { - self.with_banned_impl_trait(|this| { - this.visit_path_segment(path.span, segment) - }); + self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); } } } @@ -280,38 +254,33 @@ impl<'a> AstValidator<'a> { 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.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); + self.session.emit_err(KeywordLifetime { span: ident.span }); } } fn check_label(&self, ident: Ident) { if ident.without_first_quote().is_reserved() { - self.err_handler() - .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); + self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name }); } } - fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { + fn invalid_visibility(&self, vis: &Visibility, note: Option) { if let VisibilityKind::Inherited = vis.kind { return; } - let mut err = - struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.kind.is_pub() { - err.span_label(vis.span, "`pub` not permitted here because it's implied"); - } - if let Some(note) = note { - err.note(note); - } - err.emit(); + self.session.emit_err(InvalidVisibility { + span: vis.span, + implied: if vis.kind.is_pub() { Some(vis.span) } else { None }, + 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(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {} - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => { + 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), @@ -319,31 +288,9 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) { - if let Async::Yes { span, .. } = asyncness { - struct_span_err!( - self.session, - fn_span, - E0706, - "functions in traits cannot be declared `async`" - ) - .span_label(span, "`async` because of this") - .note("`async` trait functions are not currently supported") - .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait") - .emit(); - } - } - fn check_trait_fn_not_const(&self, constness: Const) { if let Const::Yes(span) = constness { - struct_span_err!( - self.session, - span, - E0379, - "functions in traits cannot be declared const" - ) - .span_label(span, "functions in traits cannot be const") - .emit(); + self.session.emit_err(TraitFnConst { span }); } } @@ -356,8 +303,7 @@ impl<'a> AstValidator<'a> { GenericParamKind::Lifetime { .. } => { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.err_handler() - .span_err(spans, "lifetime bounds cannot be used in this context"); + self.session.emit_err(ForbiddenLifetimeBound { spans }); } None } @@ -365,10 +311,7 @@ impl<'a> AstValidator<'a> { }) .collect(); if !non_lt_param_spans.is_empty() { - self.err_handler().span_err( - non_lt_param_spans, - "only lifetime parameters can be used in this context", - ); + self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans }); } } @@ -385,10 +328,7 @@ impl<'a> AstValidator<'a> { let max_num_args: usize = u16::MAX.into(); if fn_decl.inputs.len() > max_num_args { let Param { span, .. } = fn_decl.inputs[0]; - self.err_handler().span_fatal( - span, - &format!("function can not have more than {} arguments", max_num_args), - ); + self.session.emit_fatal(FnParamTooMany { span, max_num_args }); } } @@ -396,19 +336,13 @@ impl<'a> AstValidator<'a> { match &*fn_decl.inputs { [Param { ty, span, .. }] => { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "C-variadic function must be declared with at least one named argument", - ); + self.session.emit_err(FnParamCVarArgsOnly { span: *span }); } } [ps @ .., _] => { for Param { ty, span, .. } in ps { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "`...` must be the last argument of a C-variadic function", - ); + self.session.emit_err(FnParamCVarArgsNotLast { span: *span }); } } } @@ -435,19 +369,9 @@ impl<'a> AstValidator<'a> { }) .for_each(|attr| { if attr.is_doc_comment() { - self.err_handler() - .struct_span_err( - attr.span, - "documentation comments cannot be applied to function parameters", - ) - .span_label(attr.span, "doc comments are not allowed here") - .emit(); + self.session.emit_err(FnParamDocComment { span: attr.span }); } else { - self.err_handler().span_err( - attr.span, - "allow, cfg, cfg_attr, deny, expect, \ - forbid, and warn are the only allowed built-in attributes in function parameters", - ); + self.session.emit_err(FnParamForbiddenAttr { span: attr.span }); } }); } @@ -455,14 +379,7 @@ impl<'a> AstValidator<'a> { 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.err_handler() - .struct_span_err( - param.span, - "`self` parameter is only allowed in associated functions", - ) - .span_label(param.span, "not semantically valid as function parameter") - .note("associated functions are those in `impl` or `trait` definitions") - .emit(); + self.session.emit_err(FnParamForbiddenSelf { span: param.span }); } } } @@ -470,47 +387,20 @@ impl<'a> AstValidator<'a> { 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.err_handler() - .struct_span_err(span, "`default` is only allowed on items in trait impls") - .span_label(def_span, "`default` because of this") - .emit(); + self.session.emit_err(ForbiddenDefault { span, def_span }); } } - fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { - self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ()); - } - - fn error_item_without_body_with_help( - &self, - sp: Span, - ctx: &str, - msg: &str, - sugg: &str, - help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>), - ) { + /// 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); - let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { + + if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { end } else { sp.shrink_to_hi() - }; - let mut err = self.err_handler().struct_span_err(sp, msg); - err.span_suggestion( - replace_span, - &format!("provide a definition for the {}", ctx), - sugg, - Applicability::HasPlaceholders, - ); - help(&mut err); - err.emit(); - } - - fn check_impl_item_provided(&self, sp: Span, body: &Option, ctx: &str, sugg: &str) { - if body.is_none() { - let msg = format!("associated {} in `impl` without body", ctx); - self.error_item_without_body(sp, ctx, &msg, sugg); } } @@ -947,10 +837,10 @@ fn validate_generic_param_order( 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 { default: _ } => (ParamKindOrd::Type, ident.to_string()), + GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()), GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { let ty = pprust::ty_to_string(ty); - (ParamKindOrd::Const, format!("const {}: {}", ident, ty)) + (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty)) } }; param_idents.push((kind, ord_kind, bounds, idx, ident)); @@ -1180,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility( &item.vis, - Some("place qualifiers on individual impl items instead"), + Some(InvalidVisibilityNote::IndividualImplItems), ); if let Unsafe::Yes(span) = unsafety { error(span, "unsafe").code(error_code!(E0197)).emit(); @@ -1203,37 +1093,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_defaultness(item.span, defaultness); if body.is_none() { - let msg = "free function without a body"; - let ext = sig.header.ext; - - let f = |e: &mut DiagnosticBuilder<'_, _>| { - if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext - { - let start_suggestion = if let Extern::Explicit(abi, _) = ext { - format!("extern \"{}\" {{", abi.symbol_unescaped) - } else { - "extern {".to_owned() - }; - - let end_suggestion = " }".to_owned(); - let end_span = item.span.shrink_to_hi(); - - e - .multipart_suggestion( - "if you meant to declare an externally defined function, use an `extern` block", - vec![(*start_span, start_suggestion), (end_span, end_suggestion)], - Applicability::MaybeIncorrect, - ); - } - }; - - self.error_item_without_body_with_help( - item.span, - "function", - msg, - " { }", - f, - ); + self.session.emit_err(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(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: None, + }), + Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: Some(abi.symbol_unescaped), + }), + }, + }); } self.visit_vis(&item.vis); @@ -1248,7 +1124,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, - Some("place qualifiers on individual foreign items instead"), + Some(InvalidVisibilityNote::IndividualForeignItems), ); if let Unsafe::Yes(span) = unsafety { self.err_handler().span_err(span, "extern block cannot be declared unsafe"); @@ -1339,12 +1215,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, def); - let msg = "free constant item without body"; - self.error_item_without_body(item.span, "constant", msg, " = ;"); + self.session.emit_err(ConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::Static(.., None) => { - let msg = "free static item without body"; - self.error_item_without_body(item.span, "static", msg, " = ;"); + self.session.emit_err(StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::TyAlias(box TyAlias { defaultness, @@ -1355,8 +1235,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) => { self.check_defaultness(item.span, defaultness); if ty.is_none() { - let msg = "free type alias without body"; - self.error_item_without_body(item.span, "type", msg, " = ;"); + self.session.emit_err(TyAliasWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } self.check_type_no_bounds(bounds, "this context"); if where_clauses.1.0 { @@ -1409,7 +1291,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Mirrors `visit::walk_generic_args`, but tracks relevant state. - fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { + fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { self.check_generic_args_before_constraints(data); @@ -1548,25 +1430,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) { self.check_late_bound_lifetime_defs(&t.bound_generic_params); - visit::walk_poly_trait_ref(self, t, m); + visit::walk_poly_trait_ref(self, t); } fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } - fn visit_enum_def( - &mut self, - enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId, - _: Span, - ) { - self.with_banned_assoc_ty_bound(|this| { - visit::walk_enum_def(this, enum_definition, generics, item_id) - }) + fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) { + self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition)) } fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { @@ -1653,7 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. })) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); - self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span)); + self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { @@ -1668,10 +1542,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if ctxt == AssocCtxt::Impl { match &item.kind { AssocItemKind::Const(_, _, body) => { - self.check_impl_item_provided(item.span, body, "constant", " = ;"); + if body.is_none() { + self.session.emit_err(AssocConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::Fn(box Fn { body, .. }) => { - self.check_impl_item_provided(item.span, body, "function", " { }"); + if body.is_none() { + self.session.emit_err(AssocFnWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::TyAlias(box TyAlias { generics, @@ -1681,7 +1565,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ty, .. }) => { - self.check_impl_item_provided(item.span, ty, "type", " = ;"); + if ty.is_none() { + self.session.emit_err(AssocTypeWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } self.check_type_no_bounds(bounds, "`impl`s"); if ty.is_some() { self.check_gat_where( @@ -1699,7 +1588,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility(&item.vis, None); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness); - self.check_trait_fn_not_async(item.span, sig.header.asyncness); } } @@ -1896,14 +1784,14 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> /// Used to forbid `let` expressions in certain syntactic locations. #[derive(Clone, Copy)] -enum ForbiddenLetReason { +pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator NotSupportedOr(Span), /// A let chain with invalid parentheses /// - /// For exemple, `let 1 = 1 && (expr && expr)` is allowed + /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not NotSupportedParentheses(Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs new file mode 100644 index 000000000..4f3b09c58 --- /dev/null +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -0,0 +1,245 @@ +//! Errors emitted by ast_passes. + +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{Span, Symbol}; + +use crate::ast_validation::ForbiddenLetReason; + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_let)] +#[note] +pub struct ForbiddenLet { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub(crate) reason: ForbiddenLetReason, +} + +impl AddSubdiagnostic for ForbiddenLetReason { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::GenericForbidden => {} + Self::NotSupportedOr(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_or); + } + Self::NotSupportedParentheses(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_parentheses); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_let_stable)] +#[note] +pub struct ForbiddenLetStable { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_assoc_constraint)] +pub struct ForbiddenAssocConstraint { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_visibility, code = "E0449")] +pub struct InvalidVisibility { + #[primary_span] + pub span: Span, + #[label(ast_passes::implied)] + pub implied: Option, + #[subdiagnostic] + pub note: Option, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidVisibilityNote { + #[note(ast_passes::individual_impl_items)] + IndividualImplItems, + #[note(ast_passes::individual_foreign_items)] + IndividualForeignItems, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::trait_fn_const, code = "E0379")] +pub struct TraitFnConst { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_lifetime_bound)] +pub struct ForbiddenLifetimeBound { + #[primary_span] + pub spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_non_lifetime_param)] +pub struct ForbiddenNonLifetimeParam { + #[primary_span] + pub spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_too_many)] +pub struct FnParamTooMany { + #[primary_span] + pub span: Span, + pub max_num_args: usize, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_only)] +pub struct FnParamCVarArgsOnly { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_not_last)] +pub struct FnParamCVarArgsNotLast { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_doc_comment)] +pub struct FnParamDocComment { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_attr)] +pub struct FnParamForbiddenAttr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_self)] +#[note] +pub struct FnParamForbiddenSelf { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_default)] +pub struct ForbiddenDefault { + #[primary_span] + pub span: Span, + #[label] + pub def_span: Span, +} + +#[derive(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[diag(ast_passes::const_without_body)] +pub struct ConstWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::static_without_body)] +pub struct StaticWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[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, +} + +pub struct ExternBlockSuggestion { + pub start_span: Span, + pub end_span: Span, + pub abi: Option, +} + +impl AddSubdiagnostic for ExternBlockSuggestion { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + let start_suggestion = if let Some(abi) = self.abi { + format!("extern \"{}\" {{", abi) + } else { + "extern {".to_owned() + }; + let end_suggestion = " }".to_owned(); + + diag.multipart_suggestion( + fluent::ast_passes::extern_block_suggestion, + vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], + Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 789eca1f0..aeff73c5b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -2,17 +2,15 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd, VariantData}; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_feature::Features; use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_feature::{Features, GateIssue}; -use rustc_session::parse::{feature_err, feature_err_issue}; +use rustc_session::parse::{feature_err, feature_warn}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; - macro_rules! gate_feature_fn { ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ let (visitor, has_feature, span, name, explain, help) = @@ -20,9 +18,7 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .help(help) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit(); } }}; ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ @@ -31,8 +27,19 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).emit(); + } + }}; + (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ + let (visitor, has_feature, span, name, explain) = + (&*$visitor, $has_feature, $span, $name, $explain); + let has_feature: bool = has_feature(visitor.features); + debug!( + "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)", + name, span, has_feature + ); + if !has_feature && !span.allows_unstable($name) { + feature_warn(&visitor.sess.parse_sess, name, span, explain); } }}; } @@ -44,6 +51,9 @@ macro_rules! gate_feature_post { ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) }; + (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) + }; } pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { @@ -330,25 +340,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_gat(&self, generics: &ast::Generics, span: Span) { - if !generics.params.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "generic associated types are unstable" - ); - } - if !generics.where_clause.predicates.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "where clauses on associated types are unstable" - ); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -417,6 +408,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || 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) { struct_span_err!( self.sess, @@ -562,6 +554,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => { + gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable"); + } _ => {} } visit::walk_ty(self, ty) @@ -587,11 +582,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { { // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type // ascription error, but the likely intention was to write a `let` statement. (#78907). - feature_err_issue( + feature_err( &self.sess.parse_sess, sym::type_ascription, lhs.span, - GateIssue::Language, "type ascription is experimental", ).span_suggestion_verbose( lhs.span.shrink_to_lo(), @@ -614,28 +608,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. if self.sess.parse_sess.span_diagnostic.err_count() == 0 { + // To avoid noise about type ascription in common syntax errors, + // only emit if it is the *only* error. gate_feature_post!( &self, type_ascription, e.span, "type ascription is experimental" ); + } else { + // And if it isn't, cancel the early-pass warning. + self.sess + .parse_sess + .span_diagnostic + .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); } } ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } - ast::ExprKind::Block(_, Some(label)) => { - gate_feature_post!( - &self, - label_break_value, - label.ident.span, - "labels on blocks are unstable" - ); - } _ => {} } visit::walk_expr(self, e) @@ -690,7 +683,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } - visit::walk_fn(self, fn_kind, span) + visit::walk_fn(self, fn_kind) } fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { @@ -708,7 +701,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match i.kind { ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => { + ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -720,7 +713,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(generics, i.span); false } _ => false, @@ -789,14 +781,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // All uses of `gate_all!` 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 { ($gate:ident, $msg:literal) => { - // FIXME(eddyb) do something more useful than always - // disabling these uses of early feature-gatings. - if false { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature_post!(&visitor, $gate, *span, $msg); - } + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { + gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg); } }; } @@ -807,13 +797,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); gate_all!(try_blocks, "`try` blocks are unstable"); - gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); - // To avoid noise about type ascription in common syntax errors, - // only emit if it is the *only* error. (Also check it last.) - if sess.parse_sess.span_diagnostic.err_count() == 0 { - gate_all!(type_ascription, "type ascription is experimental"); - } + gate_all!(type_ascription, "type ascription is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 9d52c3288..8aa9d57f0 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -9,10 +9,14 @@ #![feature(if_let_guard)] #![feature(iter_is_partitioned)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] +#[macro_use] +extern crate tracing; + pub mod ast_validation; +mod errors; pub mod feature_gate; pub mod node_count; pub mod show_span; diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 9c7369c83..fa42f8778 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -63,9 +63,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: visit::FnKind<'_>, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, s) + walk_fn(self, fk) } fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { self.count += 1; @@ -79,9 +79,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { self.count += 1; - walk_poly_trait_ref(self, t, m) + walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; @@ -91,15 +91,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &EnumDef, - generics: &Generics, - item_id: NodeId, - _: Span, - ) { + fn visit_enum_def(&mut self, enum_definition: &EnumDef) { self.count += 1; - walk_enum_def(self, enum_definition, generics, item_id) + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &Variant) { self.count += 1; @@ -121,9 +115,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_use_tree(self, use_tree, id) } - fn visit_generic_args(&mut self, path_span: Span, generic_args: &GenericArgs) { + fn visit_generic_args(&mut self, generic_args: &GenericArgs) { self.count += 1; - walk_generic_args(self, path_span, generic_args) + walk_generic_args(self, generic_args) } fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) { self.count += 1; diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 79178830b..bf094af5f 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(with_negative_coherence)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 5eb7bf634..b87c6f78d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; -use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; -use rustc_ast::{attr, Term}; +use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax}; +use rustc_ast::{attr, BindingAnnotation, ByRef, Term}; use rustc_ast::{GenericArg, MacArgs, MacArgsEq}; use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; @@ -22,6 +22,7 @@ use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; use rustc_span::{BytePos, FileName, Span}; +use rustc_ast::attr::AttrIdGenerator; use std::borrow::Cow; pub use self::delimited::IterDelimited; @@ -107,6 +108,7 @@ pub fn print_crate<'a>( 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 }; @@ -120,7 +122,7 @@ pub fn print_crate<'a>( // `#![feature(prelude_import)]` let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import)); let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]); - let fake_attr = attr::mk_attr_inner(list); + let fake_attr = attr::mk_attr_inner(g, list); s.print_attribute(&fake_attr); // Currently, in Rust 2018 we don't have `extern crate std;` at the crate @@ -128,7 +130,7 @@ pub fn print_crate<'a>( if edition == Edition::Edition2015 { // `#![no_std]` let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std)); - let fake_attr = attr::mk_attr_inner(no_std_meta); + let fake_attr = attr::mk_attr_inner(g, no_std_meta); s.print_attribute(&fake_attr); } } @@ -372,7 +374,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_literal(&mut self, lit: &ast::Lit) { self.maybe_print_comment(lit.span.lo()); - self.word(lit.token.to_string()) + self.word(lit.token_lit.to_string()) } fn print_string(&mut self, st: &str, style: ast::StrStyle) { @@ -442,12 +444,12 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } self.maybe_print_comment(attr.span.lo()); match attr.kind { - ast::AttrKind::Normal(ref item, _) => { + ast::AttrKind::Normal(ref normal) => { match attr.style { ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.print_attr_item(&item, attr.span); + self.print_attr_item(&normal.item, attr.span); self.word("]"); } ast::AttrKind::DocComment(comment_kind, data) => { @@ -1399,16 +1401,12 @@ impl<'a> State<'a> { is that it doesn't matter */ match pat.kind { PatKind::Wild => self.word("_"), - PatKind::Ident(binding_mode, ident, ref sub) => { - match binding_mode { - ast::BindingMode::ByRef(mutbl) => { - self.word_nbsp("ref"); - self.print_mutability(mutbl, false); - } - ast::BindingMode::ByValue(ast::Mutability::Not) => {} - ast::BindingMode::ByValue(ast::Mutability::Mut) => { - self.word_nbsp("mut"); - } + PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, ref sub) => { + if by_ref == ByRef::Yes { + self.word_nbsp("ref"); + } + if mutbl == Mutability::Mut { + self.word_nbsp("mut"); } self.print_ident(ident); if let Some(ref p) = *sub { @@ -1487,12 +1485,10 @@ impl<'a> State<'a> { } PatKind::Ref(ref inner, mutbl) => { self.word("&"); - if mutbl == ast::Mutability::Mut { + if mutbl == Mutability::Mut { self.word("mut "); } - if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) = - inner.kind - { + if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind { self.popen(); self.print_pat(inner); self.pclose(); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index f1caf22f3..54bac29a6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -218,6 +218,8 @@ impl<'a> State<'a> { ast::ItemKind::GlobalAsm(ref 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 { @@ -412,9 +414,9 @@ impl<'a> State<'a> { pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) { match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), - ast::VisibilityKind::Restricted { ref path, .. } => { + ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => { let path = Self::to_string(|s| s.print_path(path, false, 0)); - if path == "crate" || path == "self" || path == "super" { + if shorthand && (path == "crate" || path == "self" || path == "super") { self.word_nbsp(format!("pub({})", path)) } else { self.word_nbsp(format!("pub(in {})", path)) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 10a9cfb62..753f62dd5 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -3,7 +3,6 @@ use rustc_ast as ast; use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::lint::builtin::UNEXPECTED_CFGS; @@ -14,6 +13,20 @@ use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; use std::num::NonZeroU32; +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 rust_version_symbol() -> Symbol { + let version = option_env!("CFG_VERSION").unwrap_or(""); + let version = version.split(' ').next().unwrap(); + Symbol::intern(&version) +} + pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() } @@ -25,46 +38,43 @@ enum AttrError { NonIdentFeature, MissingFeature, MultipleStabilityLevels, - UnsupportedLiteral(&'static str, /* is_bytestr */ bool), + UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool), +} + +pub(crate) enum UnsupportedLiteralReason { + Generic, + CfgString, + DeprecatedString, + DeprecatedKvPair, } fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { - let diag = &sess.span_diagnostic; match error { AttrError::MultipleItem(item) => { - struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit(); + sess.emit_err(session_diagnostics::MultipleItem { span, item }); } AttrError::UnknownMetaItem(item, expected) => { - let expected = expected.iter().map(|name| format!("`{}`", name)).collect::>(); - struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item) - .span_label(span, format!("expected one of {}", expected.join(", "))) - .emit(); + sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected }); } AttrError::MissingSince => { - struct_span_err!(diag, span, E0542, "missing 'since'").emit(); + sess.emit_err(session_diagnostics::MissingSince { span }); } AttrError::NonIdentFeature => { - struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit(); + sess.emit_err(session_diagnostics::NonIdentFeature { span }); } AttrError::MissingFeature => { - struct_span_err!(diag, span, E0546, "missing 'feature'").emit(); + sess.emit_err(session_diagnostics::MissingFeature { span }); } AttrError::MultipleStabilityLevels => { - struct_span_err!(diag, span, E0544, "multiple stability levels").emit(); + sess.emit_err(session_diagnostics::MultipleStabilityLevels { span }); } - AttrError::UnsupportedLiteral(msg, is_bytestr) => { - let mut err = struct_span_err!(diag, span, E0565, "{}", msg); - if is_bytestr { - if let Ok(lint_str) = sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "consider removing the prefix", - &lint_str[1..], - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + AttrError::UnsupportedLiteral(reason, is_bytestr) => { + sess.emit_err(session_diagnostics::UnsupportedLiteral { + span, + reason, + is_bytestr, + start_point_span: sess.source_map().start_point(span), + }); } } } @@ -131,6 +141,14 @@ impl ConstStability { } } +/// 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)] @@ -214,7 +232,8 @@ pub fn find_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) +{ find_stability_generic(sess, attrs.iter(), item_sp) } @@ -222,7 +241,7 @@ fn find_stability_generic<'a, I>( sess: &Session, attrs_iter: I, item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) where I: Iterator, { @@ -230,11 +249,10 @@ where let mut stab: Option<(Stability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None; + let mut body_stab: Option<(DefaultBodyStability, Span)> = None; let mut promotable = false; let mut allowed_through_unstable_modules = false; - let diagnostic = &sess.parse_sess.span_diagnostic; - 'outer: for attr in attrs_iter { if ![ sym::rustc_const_unstable, @@ -243,6 +261,7 @@ where sym::stable, sym::rustc_promotable, sym::rustc_allowed_through_unstable_modules, + sym::rustc_default_body_unstable, ] .iter() .any(|&s| attr.has_name(s)) @@ -273,14 +292,14 @@ where *item = Some(v); true } else { - struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit(); + sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); false } }; let meta_name = meta.name_or_empty(); match meta_name { - sym::rustc_const_unstable | sym::unstable => { + sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => { if meta_name == sym::unstable && stab.is_some() { handle_errors( &sess.parse_sess, @@ -295,6 +314,13 @@ where AttrError::MultipleStabilityLevels, ); break; + } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() { + handle_errors( + &sess.parse_sess, + attr.span, + AttrError::MultipleStabilityLevels, + ); + break; } let mut feature = None; @@ -308,7 +334,7 @@ where handle_errors( &sess.parse_sess, meta.span(), - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), ); continue 'outer; }; @@ -332,39 +358,28 @@ where // is a name/value pair string literal. issue_num = match issue.unwrap().as_str() { "none" => None, - issue => { - let emit_diag = |msg: &str| { - struct_span_err!( - diagnostic, - mi.span, - E0545, - "`issue` must be a non-zero numeric string \ - or \"none\"", - ) - .span_label(mi.name_value_literal_span().unwrap(), msg) - .emit(); - }; - match issue.parse() { - Ok(0) => { - emit_diag( - "`issue` must not be \"0\", \ - use \"none\" instead", - ); - continue 'outer; - } - Ok(num) => NonZeroU32::new(num), - Err(err) => { - emit_diag(&err.to_string()); - continue 'outer; - } + issue => match issue.parse::() { + Ok(num) => Some(num), + Err(err) => { + sess.emit_err( + session_diagnostics::InvalidIssueString { + span: mi.span, + cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( + mi.name_value_literal_span().unwrap(), + err.kind(), + ), + }, + ); + continue 'outer; } - } + }, }; } sym::soft => { if !mi.is_word() { - let msg = "`soft` should not have any arguments"; - sess.parse_sess.span_diagnostic.span_err(mi.span, msg); + sess.emit_err(session_diagnostics::SoftNoArgs { + span: mi.span, + }); } is_soft = true; } @@ -405,11 +420,16 @@ where }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); - } else { + } else if sym::rustc_const_unstable == meta_name { const_stab = Some(( ConstStability { level, feature, promotable: false }, attr.span, )); + } else if sym::rustc_default_body_unstable == meta_name { + body_stab = + Some((DefaultBodyStability { level, feature }, attr.span)); + } else { + unreachable!("Unknown stability attribute {meta_name}"); } } (None, _, _) => { @@ -417,8 +437,7 @@ where continue; } _ => { - struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'") - .emit(); + sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }); continue; } } @@ -471,13 +490,20 @@ where handle_errors( &sess.parse_sess, lit.span, - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral( + UnsupportedLiteralReason::Generic, + false, + ), ); continue 'outer; } } } + if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { + since = Some(rust_version_symbol()); + } + match (feature, since) { (Some(feature), Some(since)) => { let level = Stable { since, allowed_through_unstable_modules: false }; @@ -510,14 +536,7 @@ where if let Some((ref mut stab, _)) = const_stab { stab.promotable = promotable; } else { - struct_span_err!( - diagnostic, - item_sp, - E0717, - "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \ - or a `rustc_const_stable` attribute" - ) - .emit(); + sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }); } } @@ -532,17 +551,11 @@ where { *allowed_through_unstable_modules = true; } else { - struct_span_err!( - diagnostic, - item_sp, - E0789, - "`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute" - ) - .emit(); + sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); } } - (stab, const_stab) + (stab, const_stab, body_stab) } pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { @@ -652,25 +665,18 @@ pub fn eval_condition( NestedMetaItem::Literal(Lit { span, .. }) | NestedMetaItem::MetaItem(MetaItem { span, .. }), ] => { - sess.span_diagnostic - .struct_span_err(*span, "expected a version literal") - .emit(); + sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); return false; } [..] => { - sess.span_diagnostic - .struct_span_err(cfg.span, "expected single version literal") - .emit(); + sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { + span: cfg.span, + }); return false; } }; let Some(min_version) = parse_version(min_version.as_str(), false) else { - sess.span_diagnostic - .struct_span_warn( - *span, - "unknown version literal format, assuming it refers to a future version", - ) - .emit(); + sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span }); return false; }; let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap(); @@ -688,7 +694,7 @@ pub fn eval_condition( handle_errors( sess, mi.span(), - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), ); return false; } @@ -713,13 +719,9 @@ pub fn eval_condition( }), sym::not => { if mis.len() != 1 { - struct_span_err!( - sess.span_diagnostic, - cfg.span, - E0536, - "expected 1 cfg-pattern" - ) - .emit(); + sess.emit_err(session_diagnostics::ExpectedOneCfgPattern { + span: cfg.span, + }); return false; } @@ -745,21 +747,16 @@ pub fn eval_condition( }) } _ => { - struct_span_err!( - sess.span_diagnostic, - cfg.span, - E0537, - "invalid predicate `{}`", - pprust::path_to_string(&cfg.path) - ) - .emit(); + sess.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 => { - sess.span_diagnostic - .span_err(cfg.path.span, "`cfg` predicate key must be an identifier"); + sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); true } MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => { @@ -767,7 +764,7 @@ pub fn eval_condition( sess, lit.span, AttrError::UnsupportedLiteral( - "literal in `cfg` predicate value must be a string", + UnsupportedLiteralReason::CfgString, lit.kind.is_bytestr(), ), ); @@ -811,7 +808,6 @@ where I: Iterator, { let mut depr: Option<(Deprecation, Span)> = None; - let diagnostic = &sess.parse_sess.span_diagnostic; let is_rustc = sess.features_untracked().staged_api; 'outer: for attr in attrs_iter { @@ -847,14 +843,14 @@ where &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( - "literal in `deprecated` \ - value must be a string", + UnsupportedLiteralReason::DeprecatedString, lit.kind.is_bytestr(), ), ); } else { - struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item") - .emit(); + sess.emit_err(session_diagnostics::IncorrectMetaItem2 { + span: meta.span, + }); } false @@ -876,14 +872,11 @@ where } sym::suggestion => { if !sess.features_untracked().deprecated_suggestion { - let mut diag = sess.struct_span_err( - mi.span, - "suggestions on deprecated items are unstable", - ); - if sess.is_nightly_build() { - diag.help("add `#![feature(deprecated_suggestion)]` to the crate root"); - } - diag.note("see #94785 for more details").emit(); + sess.emit_err(session_diagnostics::DeprecatedItemSuggestion { + span: mi.span, + is_nightly: sess.is_nightly_build().then_some(()), + details: (), + }); } if !get(mi, &mut suggestion) { @@ -911,7 +904,7 @@ where &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( - "item in `deprecated` must be a key/value pair", + UnsupportedLiteralReason::DeprecatedKvPair, false, ), ); @@ -929,7 +922,7 @@ where } if note.is_none() { - struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit(); + sess.emit_err(session_diagnostics::MissingNote { span: attr.span }); continue; } } @@ -999,19 +992,9 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), sym::align => { - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0589, - "invalid `repr(align)` attribute: `align` needs an argument" - ); - err.span_suggestion( - item.span(), - "supply an argument here", - "align(...)", - Applicability::HasPlaceholders, - ); - err.emit(); + sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg { + span: item.span(), + }); recognised = true; None } @@ -1040,109 +1023,64 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { || int_type_of_word(name).is_some() { recognised = true; - struct_span_err!( - diagnostic, - item.span(), - E0552, - "invalid representation hint: `{}` does not take a parenthesized argument list", - name.to_ident_string(), - ).emit(); + sess.emit_err(session_diagnostics::InvalidReprHintNoParen { + span: item.span(), + name: name.to_ident_string(), + }); } if let Some(literal_error) = literal_error { - struct_span_err!( - diagnostic, - item.span(), - E0589, - "invalid `repr({})` attribute: {}", - name.to_ident_string(), - literal_error - ) - .emit(); + sess.emit_err(session_diagnostics::InvalidReprGeneric { + span: item.span(), + repr_arg: name.to_ident_string(), + error_part: literal_error, + }); } } else if let Some(meta_item) = item.meta_item() { if let MetaItemKind::NameValue(ref value) = meta_item.kind { 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; - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0693, - "incorrect `repr({})` attribute format", - name, - ); - match value.kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, int), - Applicability::MachineApplicable, - ); - } - ast::LitKind::Str(s, _) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, s), - Applicability::MachineApplicable, - ); - } - _ => {} - } - err.emit(); - } else { - if matches!( - meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "invalid representation hint: `{}` does not take a value", - meta_item.name_or_empty().to_ident_string(), - ) - .emit(); - } + sess.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::C | sym::simd | sym::transparent + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { + recognised = true; + sess.emit_err(session_diagnostics::InvalidReprHintNoValue { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); } } else if let MetaItemKind::List(_) = meta_item.kind { if meta_item.has_name(sym::align) { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0693, - "incorrect `repr(align)` attribute format: \ - `align` takes exactly one argument in parentheses" - ) - .emit(); + sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { + span: meta_item.span, + }); } else if meta_item.has_name(sym::packed) { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "incorrect `repr(packed)` attribute format: \ - `packed` takes exactly one parenthesized argument, \ - or no parentheses at all" - ) - .emit(); + sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { + span: meta_item.span, + }); } else if matches!( meta_item.name_or_empty(), sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "invalid representation hint: `{}` does not take a parenthesized argument list", - meta_item.name_or_empty().to_ident_string(), - ).emit(); + sess.emit_err(session_diagnostics::InvalidReprHintNoParen { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); } } } @@ -1239,10 +1177,10 @@ fn allow_unstable<'a>( let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { - sess.diagnostic().span_err( - attr.span, - &format!("`{}` expects a list of feature names", symbol.to_ident_string()), - ); + sess.emit_err(session_diagnostics::ExpectsFeatureList { + span: attr.span, + name: symbol.to_ident_string(), + }); None }) }) @@ -1251,10 +1189,10 @@ fn allow_unstable<'a>( list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { - sess.diagnostic().span_err( - it.span(), - &format!("`{}` expects feature names", symbol.to_ident_string()), - ); + sess.emit_err(session_diagnostics::ExpectsFeatures { + span: it.span(), + name: symbol.to_ident_string(), + }); } name }) diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index c3f9f0cf3..52e65a9c7 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -5,12 +5,15 @@ //! to this crate. #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; mod builtin; +mod session_diagnostics; pub use builtin::*; pub use IntType::*; diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs new file mode 100644 index 000000000..085175d4b --- /dev/null +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -0,0 +1,398 @@ +use std::num::IntErrorKind; + +use rustc_ast as ast; +use rustc_errors::{ + error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, +}; +use rustc_macros::SessionDiagnostic; +use rustc_session::SessionDiagnostic; +use rustc_span::{Span, Symbol}; + +use crate::UnsupportedLiteralReason; + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_one_cfg_pattern, code = "E0536")] +pub(crate) struct ExpectedOneCfgPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_predicate, code = "E0537")] +pub(crate) struct InvalidPredicate { + #[primary_span] + pub span: Span, + + pub predicate: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::multiple_item, code = "E0538")] +pub(crate) struct MultipleItem { + #[primary_span] + pub span: Span, + + pub item: String, +} + +#[derive(SessionDiagnostic)] +#[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> SessionDiagnostic<'a> for UnknownMetaItem<'_> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::>(); + let mut diag = handler.struct_span_err_with_code( + self.span, + fluent::attr::unknown_meta_item, + error_code!(E0541), + ); + diag.set_arg("item", self.item); + diag.set_arg("expected", expected.join(", ")); + diag.span_label(self.span, fluent::attr::label); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_since, code = "E0542")] +pub(crate) struct MissingSince { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_note, code = "E0543")] +pub(crate) struct MissingNote { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::multiple_stability_levels, code = "E0544")] +pub(crate) struct MultipleStabilityLevels { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_issue_string, code = "E0545")] +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(SessionSubdiagnostic)] +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(SessionDiagnostic)] +#[diag(attr::missing_feature, code = "E0546")] +pub(crate) struct MissingFeature { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::non_ident_feature, code = "E0546")] +pub(crate) struct NonIdentFeature { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_issue, code = "E0547")] +pub(crate) struct MissingIssue { + #[primary_span] + pub span: Span, +} + +// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider +// changing this to `IncorrectMetaItem`. See #51489. +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_meta_item, code = "E0551")] +pub(crate) struct IncorrectMetaItem2 { + #[primary_span] + pub span: Span, +} + +// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? +// It is more similar to `IncorrectReprFormatGeneric`. +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] +pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")] +pub(crate) struct InvalidReprHintNoParen { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[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> SessionDiagnostic<'a> for UnsupportedLiteral { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( + self.span, + match self.reason { + UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic, + UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string, + UnsupportedLiteralReason::DeprecatedString => { + fluent::attr::unsupported_literal_deprecated_string + } + UnsupportedLiteralReason::DeprecatedKvPair => { + fluent::attr::unsupported_literal_deprecated_kv_pair + } + }, + error_code!(E0565), + ); + if self.is_bytestr { + diag.span_suggestion( + self.start_point_span, + fluent::attr::unsupported_literal_suggestion, + "", + Applicability::MaybeIncorrect, + ); + } + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_align_need_arg, code = "E0589")] +pub(crate) struct InvalidReprAlignNeedArg { + #[primary_span] + #[suggestion(code = "align(...)", applicability = "has-placeholders")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_generic, code = "E0589")] +pub(crate) struct InvalidReprGeneric<'a> { + #[primary_span] + pub span: Span, + + pub repr_arg: String, + pub error_part: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")] +pub(crate) struct IncorrectReprFormatAlignOneArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_generic, code = "E0693")] +pub(crate) struct IncorrectReprFormatGeneric<'a> { + #[primary_span] + pub span: Span, + + pub repr_arg: &'a str, + + #[subdiagnostic] + pub cause: Option>, +} + +#[derive(SessionSubdiagnostic)] +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 }) + } + ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), + _ => None, + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::rustc_promotable_pairing, code = "E0717")] +pub(crate) struct RustcPromotablePairing { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")] +pub(crate) struct RustcAllowedUnstablePairing { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::cfg_predicate_identifier)] +pub(crate) struct CfgPredicateIdentifier { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::deprecated_item_suggestion)] +pub(crate) struct DeprecatedItemSuggestion { + #[primary_span] + pub span: Span, + + #[help] + pub is_nightly: Option<()>, + + #[note] + pub details: (), +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_single_version_literal)] +pub(crate) struct ExpectedSingleVersionLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_version_literal)] +pub(crate) struct ExpectedVersionLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expects_feature_list)] +pub(crate) struct ExpectsFeatureList { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expects_features)] +pub(crate) struct ExpectsFeatures { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::soft_no_args)] +pub(crate) struct SoftNoArgs { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::unknown_version_literal)] +pub(crate) struct UnknownVersionLiteral { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 5e9cec5c3..144fd15fc 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -31,7 +31,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>( body, }; - for (bb, data) in body.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks.iter_enumerated() { cg.visit_basic_block_data(bb, data); } } diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index a504d0c91..df0412813 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> { impl<'tcx> OutlivesConstraintSet<'tcx> { pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { - debug!( - "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", - constraint.sup, constraint.sub, constraint.locations - ); + debug!("OutlivesConstraintSet::push({:?})", constraint); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting return; @@ -73,7 +70,7 @@ impl<'tcx> Index for OutlivesConstraintSet<'tcx> { } } -#[derive(Clone, PartialEq, Eq)] +#[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 @@ -105,8 +102,8 @@ 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 + "({:?}: {:?}) due to {:?} ({:?}) ({:?})", + self.sup, self.sub, self.locations, self.variance_info, self.category, ) } } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 97d5a8d15..9f7a4d499 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -143,7 +143,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> { impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> { fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { OutOfScopePrecomputer { - visited: BitSet::new_empty(body.basic_blocks().len()), + visited: BitSet::new_empty(body.basic_blocks.len()), visit_stack: vec![], body, regioncx, @@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) - | mir::StatementKind::CopyNonOverlapping(..) + | mir::StatementKind::Intrinsic(..) | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 1ef2b0ae9..b1def1892 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -484,9 +484,7 @@ fn try_extract_error_from_region_constraints<'tcx>( }; nice_error.try_report_from_nll().or_else(|| { if let SubregionOrigin::Subtype(trace) = cause { - Some( - infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch), - ) + Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch)) } else { None } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8bc8964bb..f2204c242 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -258,7 +258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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). - if is_loop_move & !in_pattern { + // 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( @@ -451,7 +452,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_borrow_fn_like( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, ty: Ty<'tcx>, move_sites: &[MoveSite], value_name: &str, @@ -526,12 +527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { true } - fn suggest_adding_copy_bounds( - &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ty: Ty<'tcx>, - span: Span, - ) { + fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id()); @@ -1124,6 +1120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// 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, @@ -1131,13 +1128,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_span: (Place<'tcx>, Span), kind: Option, ) { - debug!( - "report_borrowed_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}\ - )", - location, borrow, place_span, kind - ); - let drop_span = place_span.1; let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); @@ -1194,10 +1184,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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!( - "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})", - place_desc, explanation - ); + debug!(?place_desc, ?explanation); + let err = match (place_desc, explanation) { // If the outlives constraint comes from inside the closure, // for example: @@ -1469,6 +1457,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } + #[instrument(level = "debug", skip(self))] fn report_temporary_value_does_not_live_long_enough( &mut self, location: Location, @@ -1478,13 +1467,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { proper_span: Span, explanation: BorrowExplanation<'tcx>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - debug!( - "report_temporary_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}\ - )", - location, borrow, drop_span, proper_span - ); - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 72aee0267..1c01e78ab 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; -use crate::region_infer::BlameConstraint; +use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, WriteKind, @@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> { span: Span, region_name: RegionName, opt_place_desc: Option, + extra_info: Vec, }, Unexplained, } @@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ref region_name, ref opt_place_desc, from_closure: _, + ref extra_info, } => { region_name.highlight_region_name(err); @@ -268,18 +270,30 @@ impl<'tcx> BorrowExplanation<'tcx> { ); }; + for extra in extra_info { + match extra { + ExtraConstraintInfo::PlaceholderFromPredicate(span) => { + err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + } + } + } + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); } _ => {} } } - pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic( + + fn add_lifetime_bound_suggestion_to_diagnostic( &self, err: &mut Diagnostic, 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 }; @@ -305,18 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, borrow_region: RegionVid, outlived_region: RegionVid, - ) -> (ConstraintCategory<'tcx>, bool, Span, Option) { - let BlameConstraint { category, from_closure, cause, variance_info: _ } = - self.regioncx.best_blame_constraint( - &self.body, - borrow_region, - NllRegionVariableOrigin::FreeRegion, - |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), - ); + ) -> (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) + (category, from_closure, cause.span, outlived_fr_name, extra_info) } /// Returns structured explanation for *why* the borrow contains the @@ -332,26 +345,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// - 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> { - debug!( - "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", - location, borrow, kind_place - ); - let regioncx = &self.regioncx; let body: &Body<'_> = &self.body; let tcx = self.infcx.tcx; let borrow_region_vid = borrow.region; - debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid); + debug!(?borrow_region_vid); let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); - debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub); + debug!(?region_sub); match find_use::find(body, regioncx, tcx, region_sub, location) { Some(Cause::LiveVar(local, location)) => { @@ -392,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None => { if let Some(region) = self.to_error_region_vid(borrow_region_vid) { - let (category, from_closure, span, region_name) = + 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()); @@ -402,19 +411,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span, region_name, opt_place_desc, + extra_info, } } else { - debug!( - "explain_why_borrow_contains_point: \ - Could not generate a region name" - ); + debug!("Could not generate a region name"); BorrowExplanation::Unexplained } } else { - debug!( - "explain_why_borrow_contains_point: \ - Could not generate an error region vid" - ); + debug!("Could not generate an error region vid"); BorrowExplanation::Unexplained } } @@ -455,7 +459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return outmost_back_edge; } - let block = &self.body.basic_blocks()[location.block]; + let block = &self.body.basic_blocks[location.block]; if location.statement_index < block.statements.len() { let successor = location.successor_within_block(); @@ -514,7 +518,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if loop_head.dominates(from, &self.dominators) { - let block = &self.body.basic_blocks()[from.block]; + let block = &self.body.basic_blocks[from.block]; if from.statement_index < block.statements.len() { let successor = from.successor_within_block(); @@ -564,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { UseSpans::PatUse(span) | UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => { - let block = &self.body.basic_blocks()[location.block]; + let block = &self.body.basic_blocks[location.block]; let kind = if let Some(&Statement { kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 098e8de94..683084cf0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1086,14 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), ); } - if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` to borrow the type's contents", - "as_ref().", - Applicability::MachineApplicable, - ); - } // Avoid pointing to the same function in multiple different // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { @@ -1102,6 +1094,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) ); } + if is_option_or_result && maybe_reinitialized_locations_is_empty { + err.span_label( + var_span, + "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents", + ); + } } // Other desugarings takes &self, which cannot cause a move _ => {} diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index cb3cd479a..8d4c38d3a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(StatementKind::Assign(box ( place, Rvalue::Use(Operand::Move(move_from)), - ))) = self.body.basic_blocks()[location.block] + ))) = self.body.basic_blocks[location.block] .statements .get(location.statement_index) .map(|stmt| &stmt.kind) @@ -360,7 +360,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(upvar_span, "captured outer variable"); diag.span_label( - self.body.span, + self.infcx.tcx.def_span(def_id), format!("captured by this `{closure_kind}` closure"), ); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0ad4abbce..6b5014fa9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,23 +1,23 @@ +use rustc_errors::{ + Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, +}; use rustc_hir as hir; +use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::hir::map::Map; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, - mir::{ - self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo, - LocalKind, Location, - }, + mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location}, }; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{sym, BytePos, Span}; use crate::diagnostics::BorrowedContentSource; use crate::MirBorrowckCtxt; use rustc_const_eval::util::collect_writes::FindAssignments; -use rustc_errors::{Applicability, Diagnostic}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -309,7 +309,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && !matches!( decl.local_info, Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( - ImplicitSelfKind::MutRef + hir::ImplicitSelfKind::MutRef )))) ) { @@ -364,7 +364,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) && let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, + hir::BindingAnnotation::NONE, _, upvar_ident, _, @@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "trait `IndexMut` is required to modify indexed content, \ but it is not implemented for `{ty}`", )); + self.suggest_map_index_mut_alternatives(ty, &mut err, span); } _ => (), } @@ -627,6 +628,127 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.buffer_error(err); } + fn suggest_map_index_mut_alternatives( + &self, + ty: Ty<'_>, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + span: Span, + ) { + let Some(adt) = ty.ty_adt_def() else { return }; + let did = adt.did(); + if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did) + || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did) + { + struct V<'a, 'b, 'tcx, G: EmissionGuarantee> { + assign_span: Span, + err: &'a mut DiagnosticBuilder<'b, G>, + ty: Ty<'tcx>, + suggested: bool, + } + impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> { + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) { + hir::intravisit::walk_stmt(self, stmt); + let expr = match stmt.kind { + hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, + hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr, + _ => { + return; + } + }; + if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind + && let hir::ExprKind::Index(val, index) = place.kind + && (expr.span == self.assign_span || place.span == self.assign_span) + { + // val[index] = rv; + // ---------- place + self.err.multipart_suggestions( + &format!( + "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API", + self.ty, + ), + vec![ + vec![ // val.insert(index, rv); + ( + val.span.shrink_to_hi().with_hi(index.span.lo()), + ".insert(".to_string(), + ), + ( + index.span.shrink_to_hi().with_hi(rv.span.lo()), + ", ".to_string(), + ), + (rv.span.shrink_to_hi(), ")".to_string()), + ], + vec![ // val.get_mut(index).map(|v| { *v = rv; }); + ( + val.span.shrink_to_hi().with_hi(index.span.lo()), + ".get_mut(".to_string(), + ), + ( + index.span.shrink_to_hi().with_hi(place.span.hi()), + ").map(|val| { *val".to_string(), + ), + ( + rv.span.shrink_to_hi(), + "; })".to_string(), + ), + ], + vec![ // let x = val.entry(index).or_insert(rv); + (val.span.shrink_to_lo(), "let val = ".to_string()), + ( + val.span.shrink_to_hi().with_hi(index.span.lo()), + ".entry(".to_string(), + ), + ( + index.span.shrink_to_hi().with_hi(rv.span.lo()), + ").or_insert(".to_string(), + ), + (rv.span.shrink_to_hi(), ")".to_string()), + ], + ].into_iter(), + Applicability::MachineApplicable, + ); + self.suggested = true; + } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind + && let hir::ExprKind::Index(val, index) = receiver.kind + && expr.span == self.assign_span + { + // val[index].path(args..); + self.err.multipart_suggestion( + &format!("to modify a `{}` use `.get_mut()`", self.ty), + vec![ + ( + val.span.shrink_to_hi().with_hi(index.span.lo()), + ".get_mut(".to_string(), + ), + ( + index.span.shrink_to_hi().with_hi(receiver.span.hi()), + ").map(|val| val".to_string(), + ), + (sp.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + self.suggested = true; + } + } + } + let hir_map = self.infcx.tcx.hir(); + let def_id = self.body.source.def_id(); + let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap()); + let node = hir_map.find(hir_id); + let Some(hir::Node::Item(item)) = node else { return; }; + let hir::ItemKind::Fn(.., body_id) = item.kind else { return; }; + let body = self.infcx.tcx.hir().body(body_id); + let mut v = V { assign_span: span, err, ty, suggested: false }; + v.visit_body(body); + if !v.suggested { + err.help(&format!( + "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API", + )); + } + } + } + /// User cannot make signature of a trait mutable without changing the /// trait. So we find if this error belongs to a trait and if so we move /// suggestion to the trait or disable it if it is out of scope of this crate @@ -786,11 +908,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { [ Expr { kind: - MethodCall( - path_segment, - _args, - span, - ), + MethodCall(path_segment, _, _, span), hir_id, .. }, @@ -810,10 +928,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, ) = hir_map.body(fn_body_id).value.kind { - let opt_suggestions = path_segment - .hir_id - .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner)) - .and_then(|typeck| typeck.type_dependent_def_id(*hir_id)) + let opt_suggestions = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner) + .type_dependent_def_id(*hir_id) .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) .map(|def_id| self.infcx.tcx.associated_items(def_id)) .map(|assoc_items| { @@ -851,6 +970,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let hir = self.infcx.tcx.hir(); let closure_id = self.mir_hir_id(); + let closure_span = self.infcx.tcx.def_span(self.mir_def_id()); let fn_call_id = hir.get_parent_node(closure_id); let node = hir.get(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id); @@ -902,7 +1022,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(span) = arg { err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - err.span_label(self.body.span, "in this closure"); + err.span_label(closure_span, "in this closure"); look_at_return = false; } } @@ -928,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { sig.decl.output.span(), "change this to return `FnMut` instead of `Fn`", ); - err.span_label(self.body.span, "in this closure"); + err.span_label(closure_span, "in this closure"); } _ => {} } @@ -952,7 +1072,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option { // Otherwise, check if the name is the `self` keyword - in which case diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index d359d7efb..35c3df768 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -6,7 +6,6 @@ use rustc_errors::Diagnostic; use rustc_middle::ty::RegionVid; use smallvec::SmallVec; use std::collections::BTreeMap; -use tracing::debug; use crate::MirBorrowckCtxt; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 176090c3b..34be2874f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] //! Error reporting machinery for lifetime errors. use rustc_data_structures::fx::FxHashSet; @@ -23,10 +25,13 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use crate::borrowck_errors; -use crate::session_diagnostics::GenericDoesNotLiveLongEnough; +use crate::session_diagnostics::{ + FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, + LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote, +}; use super::{OutlivesSuggestionBuilder, RegionName}; -use crate::region_infer::BlameConstraint; +use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ nll::ConstraintDescription, region_infer::{values::RegionElement, TypeTest}, @@ -229,7 +234,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. let (_, cause) = self.regioncx.find_outlives_blame_span( - &self.body, longer_fr, NllRegionVariableOrigin::Placeholder(placeholder), error_vid, @@ -350,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let BlameConstraint { category, cause, variance_info, from_closure: _ } = - self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { + let (blame_constraint, extra_info) = + self.regioncx.best_blame_constraint(fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); + let BlameConstraint { category, cause, variance_info, .. } = blame_constraint; debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); @@ -462,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + for extra in extra_info { + match extra { + ExtraConstraintInfo::PlaceholderFromPredicate(span) => { + diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + } + } + } + self.buffer_error(diag); } @@ -488,12 +501,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; - let mut diag = self - .infcx - .tcx - .sess - .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body"); - let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; if let ty::Opaque(def_id, _) = *output_ty.kind() { output_ty = self.infcx.tcx.type_of(def_id) @@ -501,19 +508,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("report_fnmut_error: output_ty={:?}", output_ty); - let message = match output_ty.kind() { - ty::Closure(_, _) => { - "returns a closure that contains a reference to a captured variable, which then \ - escapes the closure body" - } - ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => { - "returns an `async` block that contains a reference to a captured variable, which then \ - escapes the closure body" - } - _ => "returns a reference to a captured variable which escapes the closure body", + let err = FnMutError { + span: *span, + ty_err: match output_ty.kind() { + ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span }, + ty::Adt(def, _) + if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => + { + FnMutReturnTypeErr::ReturnAsyncBlock { span: *span } + } + _ => FnMutReturnTypeErr::ReturnRef { span: *span }, + }, }; - diag.span_label(*span, message); + let mut diag = self.infcx.tcx.sess.create_err(err); if let ReturnConstraint::ClosureUpvar(upvar_field) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { @@ -532,20 +540,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); let upvar_def_span = self.infcx.tcx.hir().span(def_hir); let upvar_span = upvars_map.get(&def_hir).unwrap().span; - diag.span_label(upvar_def_span, "variable defined here"); - diag.span_label(upvar_span, "variable captured here"); + diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span }); + diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span }); } } if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { - diag.span_label(fr_span, "inferred to be a `FnMut` closure"); + diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span }); } - diag.note( - "`FnMut` closures only have access to their captured variables while they are \ - executing...", - ); - diag.note("...therefore, they cannot allow references to captured variables to escape"); + self.suggest_move_on_borrowing_closure(&mut diag); diag } @@ -562,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// LL | ref_obj(x) /// | ^^^^^^^^^^ `x` escapes the function body here /// ``` + #[instrument(level = "debug", skip(self))] fn report_escaping_data_error( &self, errci: &ErrorConstraintInfo<'tcx>, @@ -680,42 +685,37 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. } = errci; - let mut diag = - self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id()); + let err = LifetimeOutliveErr { span: *span }; + let mut diag = self.infcx.tcx.sess.create_err(err); + let fr_name = self.give_region_a_name(*fr).unwrap(); fr_name.highlight_region_name(&mut diag); let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap(); outlived_fr_name.highlight_region_name(&mut diag); - match (category, outlived_fr_is_local, fr_is_local) { - (ConstraintCategory::Return(_), true, _) => { - diag.span_label( - *span, - format!( - "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \ - data with lifetime `{fr_name}`", - ), - ); - } - _ => { - diag.span_label( - *span, - format!( - "{}requires that `{}` must outlive `{}`", - category.description(), - fr_name, - outlived_fr_name, - ), - ); - } - } + let err_category = match (category, outlived_fr_is_local, fr_is_local) { + (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn { + span: *span, + mir_def_name, + outlived_fr_name, + fr_name: &fr_name, + }, + _ => LifetimeReturnCategoryErr::ShortReturn { + span: *span, + category_desc: category.description(), + free_region_name: &fr_name, + outlived_fr_name, + }, + }; + + diag.subdiagnostic(err_category); self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); + self.suggest_move_on_borrowing_closure(&mut diag); diag } @@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn maybe_suggest_constrain_dyn_trait_impl( &self, - diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + diag: &mut Diagnostic, f: Region<'tcx>, o: Region<'tcx>, category: &ConstraintCategory<'tcx>, @@ -860,7 +860,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ident.span, "calling this method introduces the `impl`'s 'static` requirement", ); - err.span_note(multi_span, "the used `impl` has a `'static` requirement"); + err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( span.shrink_to_hi(), "consider relaxing the implicit `'static` requirement", @@ -901,4 +901,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag); } + + fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) { + let map = self.infcx.tcx.hir(); + let body_id = map.body_owned_by(self.mir_def_id()); + let expr = &map.body(body_id).value; + let mut closure_span = None::; + match expr.kind { + hir::ExprKind::MethodCall(.., args, _) => { + for arg in args { + if let hir::ExprKind::Closure(hir::Closure { + capture_clause: hir::CaptureBy::Ref, + .. + }) = arg.kind + { + closure_span = Some(arg.span.shrink_to_lo()); + break; + } + } + } + hir::ExprKind::Block(blk, _) => { + if let Some(ref expr) = blk.expr { + // only when the block is a closure + if let hir::ExprKind::Closure(hir::Closure { + capture_clause: hir::CaptureBy::Ref, + .. + }) = expr.kind + { + closure_span = Some(expr.span.shrink_to_lo()); + } + } + } + _ => {} + } + if let Some(closure_span) = closure_span { + diag.span_suggestion_verbose( + closure_span, + "consider adding 'move' keyword before the nested closure", + "move ", + Applicability::MaybeIncorrect, + ); + } + } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index a87e8bd5b..6c1eaa809 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -265,7 +265,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// *user* has a name for. In that case, we'll be able to map /// `fr` to a `Region<'tcx>`, and that region will be one of /// named variants. - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_from_error_region(&self, fr: RegionVid) -> Option { let error_region = self.to_error_region(fr)?; @@ -357,11 +357,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::BoundRegionKind::BrAnon(_) => None, }, - ty::ReLateBound(..) - | ty::ReVar(..) - | ty::RePlaceholder(..) - | ty::ReEmpty(_) - | ty::ReErased => None, + ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None, } } @@ -373,7 +369,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | fn foo(x: &u32) { .. } /// ------- fully elaborated type of `x` is `&'1 u32` /// ``` - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_arguments( &self, fr: RegionVid, @@ -662,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | let x = Some(&22); /// - fully elaborated type of `x` is `Option<&'1 u32>` /// ``` - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( @@ -682,7 +678,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// must be a closure since, in a free fn, such an argument would /// have to either also appear in an argument (if using elision) /// or be early bound (named, not in argument). - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option { let tcx = self.infcx.tcx; let hir = tcx.hir(); @@ -772,7 +768,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { let hir = self.infcx.tcx.hir(); - let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", @@ -814,7 +810,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_yield_ty( &self, fr: RegionVid, diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index ec521b1cf..3157f861d 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -1,6 +1,6 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue}; +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}; @@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { StatementKind::FakeRead(box (_, _)) => { // Only relevant for initialized/liveness/safety checks. } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { + self.consume_operand(location, op); + } + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { ref src, ref dst, ref count, - }) => { + })) => { self.consume_operand(location, src); self.consume_operand(location, dst); self.consume_operand(location, count); } - StatementKind::Nop + // Only relevant for mir typeck + StatementKind::AscribeUserType(..) + // Doesn't have any language semantics | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { LocalMutationIsAllowed::Yes, ); } - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { + StatementKind::Nop + | StatementKind::Retag { .. } + | StatementKind::Deinit(..) + | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3d8b07382..86da87d06 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,7 +3,7 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] @@ -19,15 +19,15 @@ extern crate tracing; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, - PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, + Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; @@ -51,6 +51,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveE use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::MoveDataParamEnv; +use crate::session_diagnostics::VarNeedNotMut; + use self::diagnostics::{AccessKind, RegionName}; use self::location::LocationTable; use self::prefixes::PrefixSet; @@ -425,17 +427,9 @@ fn do_mir_borrowck<'a, 'tcx>( continue; } - tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| { - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - lint.build("variable does not need to be mutable") - .span_suggestion_short( - mut_span, - "remove this `mut`", - "", - Applicability::MachineApplicable, - ) - .emit(); - }) + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); + + tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) } let tainted_by_errors = mbcx.emit_errors(); @@ -597,22 +591,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx flow_state, ); } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => { - span_bug!( + StatementKind::Intrinsic(box ref 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::Nop + // Only relevant for mir typeck + StatementKind::AscribeUserType(..) + // Doesn't have any language semantics | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -622,7 +613,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx flow_state, ); } - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { + StatementKind::Nop + | StatementKind::Retag { .. } + | StatementKind::Deinit(..) + | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } @@ -982,6 +976,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self, flow_state))] fn check_access_for_conflict( &mut self, location: Location, @@ -990,11 +985,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { rw: ReadOrWrite, flow_state: &Flows<'cx, 'tcx>, ) -> bool { - debug!( - "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})", - location, place_span, sd, rw, - ); - let mut error_reported = false; let tcx = self.infcx.tcx; let body = self.body; @@ -1458,13 +1448,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// 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, ) { - debug!("check_for_invalidation_at_exit({:?})", borrow); let place = borrow.borrowed_place; let mut root_place = PlaceRef { local: place.local, projection: &[] }; diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs index 70a311694..877944d3d 100644 --- a/compiler/rustc_borrowck/src/location.rs +++ b/compiler/rustc_borrowck/src/location.rs @@ -33,7 +33,7 @@ impl LocationTable { pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block = body - .basic_blocks() + .basic_blocks .iter() .map(|block_data| { let v = num_points; @@ -86,8 +86,7 @@ impl LocationTable { let (block, &first_index) = self .statements_before_block .iter_enumerated() - .filter(|(_, first_index)| **first_index <= point_index) - .last() + .rfind(|&(_, &first_index)| first_index <= point_index) .unwrap(); let statement_index = (point_index - first_index) / 2; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 0961203d7..12b2481cc 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -389,8 +389,9 @@ pub(super) fn dump_annotation<'a, 'tcx>( // 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.sess.diagnostic().span_note_diag(body.span, "external requirements"); + let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -409,7 +410,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( err } else { - let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); + let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements"); regioncx.annotate(tcx, &mut err); err diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 97335fd0d..6e5a96bee 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -44,6 +44,7 @@ pub(crate) fn places_conflict<'tcx>( /// 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. +#[instrument(level = "debug", skip(tcx, body))] pub(super) fn borrow_conflicts_with_place<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -53,11 +54,6 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( access: AccessDepth, bias: PlaceConflictBias, ) -> bool { - debug!( - "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})", - borrow_place, access_place, access, bias, - ); - // 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 let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() { @@ -140,10 +136,9 @@ fn place_components_conflict<'tcx>( for (i, (borrow_c, &access_c)) in iter::zip(borrow_place.projection, access_place.projection).enumerate() { - debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); - let borrow_proj_base = &borrow_place.projection[..i]; + debug!(?borrow_c, ?access_c); - debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); + let borrow_proj_base = &borrow_place.projection[..i]; // Borrow and access path both have more components. // @@ -180,7 +175,7 @@ fn place_components_conflict<'tcx>( // 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!("borrow_conflicts_with_place: arbitrary -> conflict"); + debug!("arbitrary -> conflict"); return true; } Overlap::EqualOrDisjoint => { @@ -189,7 +184,7 @@ fn place_components_conflict<'tcx>( Overlap::Disjoint => { // We have proven the borrow disjoint - further // projections will remain disjoint. - debug!("borrow_conflicts_with_place: disjoint"); + debug!("disjoint"); return false; } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2894c6d29..244e6e342 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> { /// 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(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub(crate) struct AppliedMemberConstraint { /// The SCC that was affected. (The "member region".) /// @@ -246,6 +245,11 @@ enum Trace<'tcx> { NotVisited, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ExtraConstraintInfo { + PlaceholderFromPredicate(Span), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -591,13 +595,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraints were too strong, and if so, emit or propagate those errors. if infcx.tcx.sess.opts.unstable_opts.polonius { self.check_polonius_subset_errors( - body, outlives_requirements.as_mut(), &mut errors_buffer, polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { - self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); + self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); } if errors_buffer.is_empty() { @@ -1139,7 +1142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { debug!(r = %self.region_value_str(r)); @@ -1151,8 +1154,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } - debug!(?lub); - lub } @@ -1167,8 +1168,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 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!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + debug!("{}", self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -1177,7 +1179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + 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 @@ -1201,7 +1203,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); + debug!(?r, ?lub); lub } @@ -1332,15 +1334,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Evaluate whether `sup_region: sub_region`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!( - "eval_outlives: sup_region's value = {:?} universal={:?}", + "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), self.universal_regions.is_universal_region(sup_region), ); debug!( - "eval_outlives: sub_region's value = {:?} universal={:?}", + "sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), self.universal_regions.is_universal_region(sub_region), ); @@ -1353,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // true if `'sup` outlives static. if !self.universe_compatible(sub_region_scc, sup_region_scc) { debug!( - "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \ + "sub universe `{sub_region_scc:?}` is not nameable \ by super `{sup_region_scc:?}`, promoting to static", ); @@ -1374,9 +1376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); if !universal_outlives { - debug!( - "eval_outlives: returning false because sub region contains a universal region not present in super" - ); + debug!("sub region contains a universal region not present in super"); return false; } @@ -1385,15 +1385,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { if self.universal_regions.is_universal_region(sup_region) { // Micro-opt: universal regions contain all points. - debug!( - "eval_outlives: returning true because super is universal and hence contains all points" - ); + debug!("super is universal and hence contains all points"); return true; } - let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc); - debug!("returning {} because of comparison between points in sup/sub", result); - result + 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 @@ -1415,7 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_universal_regions( &self, - body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { @@ -1426,7 +1423,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. self.check_universal_region( - body, fr, &mut propagated_outlives_requirements, errors_buffer, @@ -1467,7 +1463,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_polonius_subset_errors( &self, - body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, polonius_output: Rc, @@ -1514,7 +1509,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { let propagated = self.try_propagate_universal_region_error( *longer_fr, *shorter_fr, - body, &mut propagated_outlives_requirements, ); if propagated == RegionRelationCheckResult::Error { @@ -1554,13 +1548,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. - #[instrument( - skip(self, body, propagated_outlives_requirements, errors_buffer), - level = "debug" - )] + #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")] fn check_universal_region( &self, - body: &Body<'tcx>, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, @@ -1583,7 +1573,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, representative, - body, propagated_outlives_requirements, ) { errors_buffer.push(RegionErrorKind::RegionError { @@ -1603,7 +1592,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, shorter_fr, - body, propagated_outlives_requirements, ) { // We only report the first region error. Subsequent errors are hidden so as @@ -1628,7 +1616,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec>>, ) -> RegionRelationCheckResult { // If it is known that `fr: o`, carry on. @@ -1644,7 +1631,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.try_propagate_universal_region_error( longer_fr, shorter_fr, - body, propagated_outlives_requirements, ) } @@ -1656,7 +1642,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec>>, ) -> RegionRelationCheckResult { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { @@ -1668,7 +1653,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); let blame_span_category = self.find_outlives_blame_span( - body, longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr, @@ -1822,50 +1806,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn retrieve_closure_constraint_info( &self, - _body: &Body<'tcx>, - constraint: &OutlivesConstraint<'tcx>, - ) -> BlameConstraint<'tcx> { - let loc = match constraint.locations { - Locations::All(span) => { - return BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::dummy_with_span(span), - variance_info: constraint.variance_info, - }; + constraint: OutlivesConstraint<'tcx>, + ) -> Option<(ConstraintCategory<'tcx>, Span)> { + match constraint.locations { + Locations::All(_) => None, + Locations::Single(loc) => { + self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied() } - Locations::Single(loc) => loc, - }; - - let opt_span_category = - self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); - opt_span_category - .map(|&(category, span)| BlameConstraint { - category, - from_closure: true, - cause: ObligationCause::dummy_with_span(span), - variance_info: constraint.variance_info, - }) - .unwrap_or(BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::dummy_with_span(constraint.span), - variance_info: constraint.variance_info, - }) + } } /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. pub(crate) fn find_outlives_blame_span( &self, - body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { - let BlameConstraint { category, cause, .. } = - self.best_blame_constraint(body, fr1, fr1_origin, |r| { - self.provides_universal_region(r, fr1, fr2) - }); + let BlameConstraint { category, cause, .. } = self + .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) + .0; (category, cause) } @@ -1970,7 +1930,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds some region R such that `fr1: R` and `R` is live at `elem`. - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); @@ -2048,23 +2008,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 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, - body: &Body<'tcx>, from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, - ) -> BlameConstraint<'tcx> { - debug!( - "best_blame_constraint(from_region={:?}, from_region_origin={:?})", - from_region, from_region_origin - ); - + ) -> (BlameConstraint<'tcx>, Vec) { // Find all paths let (path, target_region) = self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); debug!( - "best_blame_constraint: path={:#?}", + "path={:#?}", path.iter() .map(|c| format!( "{:?} ({:?}: {:?})", @@ -2075,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { .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` @@ -2100,23 +2067,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut categorized_path: Vec> = path .iter() .map(|constraint| { - if constraint.category == ConstraintCategory::ClosureBounds { - self.retrieve_closure_constraint_info(body, &constraint) - } else { - BlameConstraint { - category: constraint.category, - from_closure: false, - cause: ObligationCause::new( - constraint.span, - CRATE_HIR_ID, - cause_code.clone(), - ), - variance_info: constraint.variance_info, - } + let (category, span, from_closure, cause_code) = + if constraint.category == ConstraintCategory::ClosureBounds { + if let Some((category, span)) = + self.retrieve_closure_constraint_info(*constraint) + { + (category, span, true, ObligationCauseCode::MiscObligation) + } else { + ( + constraint.category, + constraint.span, + false, + ObligationCauseCode::MiscObligation, + ) + } + } else { + (constraint.category, constraint.span, false, cause_code.clone()) + }; + BlameConstraint { + category, + from_closure, + cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code), + variance_info: constraint.variance_info, + outlives_constraint: *constraint, } }) .collect(); - debug!("best_blame_constraint: categorized_path={:#?}", categorized_path); + 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 @@ -2214,10 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let best_choice = if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - debug!( - "best_blame_constraint: best_choice={:?} blame_source={}", - best_choice, blame_source - ); + debug!(?best_choice, ?blame_source, ?extra_info); if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { @@ -2226,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { // 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(); + return (next.clone(), extra_info); } } @@ -2246,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - return categorized_path[i].clone(); + return (categorized_path[i].clone(), extra_info); } // If that search fails, that is.. unusual. Maybe everything @@ -2254,9 +2228,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // appears to be the most interesting point to report to the // user via an even more ad-hoc guess. categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); - debug!("best_blame_constraint: sorted_path={:#?}", categorized_path); + debug!("sorted_path={:#?}", categorized_path); - categorized_path.remove(0) + (categorized_path.remove(0), extra_info) } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { @@ -2338,7 +2312,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", region, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate( + region.into(), + outlived_region, + )), + ConstraintCategory::BoringNoLocation, + ) } ClosureOutlivesSubject::Ty(ty) => { @@ -2348,7 +2328,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", ty, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)), + ConstraintCategory::BoringNoLocation, + ) } } }) @@ -2362,4 +2345,5 @@ pub struct BlameConstraint<'tcx> { pub from_closure: bool, pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub outlives_constraint: OutlivesConstraint<'tcx>, } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d6712b6a4..9d088642f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -16,6 +16,8 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; +use crate::session_diagnostics::ConstNotUsedTraitAlias; + use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -58,7 +60,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, /// which has no `external_name` in which case we use `'empty` as the /// region to pass to `infer_opaque_definition_from_instantiation`. - #[instrument(level = "debug", skip(self, infcx))] + #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, @@ -107,7 +109,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + .unwrap_or(infcx.tcx.lifetimes.re_erased), _ => region, }); @@ -431,7 +433,7 @@ struct ReverseMapper<'tcx> { key: ty::OpaqueTypeKey<'tcx>, map: FxHashMap, GenericArg<'tcx>>, - map_missing_regions_to_empty: bool, + do_not_error: bool, /// initially `Some`, set to `None` once error has been reported hidden_ty: Option>, @@ -448,29 +450,19 @@ impl<'tcx> ReverseMapper<'tcx> { hidden_ty: Ty<'tcx>, span: Span, ) -> Self { - Self { - tcx, - key, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - span, - } + Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span } } - fn fold_kind_mapping_missing_regions_to_empty( - &mut self, - kind: GenericArg<'tcx>, - ) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; + fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + self.do_not_error = true; let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; + self.do_not_error = false; kind } fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); + assert!(!self.do_not_error); kind.fold_with(self) } } @@ -494,9 +486,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { ty::ReErased => return r, // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} + ty::ReEarlyBound(_) | ty::ReFree(_) => {} - ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { + ty::RePlaceholder(_) | ty::ReVar(_) => { // All of the regions in the type should either have been // erased by writeback, or mapped back to named regions by // borrow checking. @@ -508,7 +500,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&r.into()).map(|k| k.unpack()) { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, + None if self.do_not_error => self.tcx.lifetimes.re_static, None if generics.parent.is_some() => { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( @@ -520,7 +512,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); } - self.tcx.lifetimes.re_root_empty + self.tcx.lifetimes.re_static } None => { self.tcx @@ -572,7 +564,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) + self.fold_kind_no_missing_regions_error(kind) } else { // ...but not elsewhere. self.fold_kind_normally(kind) @@ -587,7 +579,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) + self.fold_kind_no_missing_regions_error(kind) } else { // ...but not elsewhere. self.fold_kind_normally(kind) @@ -639,17 +631,10 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ct - ), - ) - .emit(); + self.tcx.sess.emit_err(ConstNotUsedTraitAlias { + ct: ct.to_string(), + span: self.span, + }); self.tcx().const_error(ct.ty()) } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c81ef10f7..de20a4bb4 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -25,7 +25,7 @@ impl RegionValueElements { pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block: IndexVec = body - .basic_blocks() + .basic_blocks .iter() .map(|block_data| { let v = num_points; @@ -37,7 +37,7 @@ impl RegionValueElements { debug!("RegionValueElements: num_points={:#?}", num_points); let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks().iter_enumerated() { + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 7a8ce621c..63b2088f7 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -2,6 +2,7 @@ use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::mir::visit::{MutVisitor, TyContext}; use rustc_middle::mir::{Body, Location, Promoted}; +use rustc_middle::mir::{Constant, ConstantKind}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -37,6 +38,21 @@ where }) } +// FIXME(valtrees): This function is necessary because `fold_regions` +// panics for mir constants in the visitor. +// +// Once `visit_mir_constant` is removed we can also remove this function +// and just use `renumber_regions`. +fn renumber_regions_in_mir_constant<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + value: ConstantKind<'tcx>, +) -> ConstantKind<'tcx> { + infcx.tcx.super_fold_regions(value, |_region, _depth| { + let origin = NllRegionVariableOrigin::Existential { from_forall: false }; + infcx.next_nll_region_var(origin) + }) +} + struct NllVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, } @@ -48,6 +64,13 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> { { renumber_regions(self.infcx, value) } + + fn renumber_regions_in_mir_constant( + &mut self, + value: ConstantKind<'tcx>, + ) -> ConstantKind<'tcx> { + renumber_regions_in_mir_constant(self.infcx, value) + } } impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { @@ -77,7 +100,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { debug!(?region); } - fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) { - *constant = self.renumber_regions(*constant); + #[instrument(skip(self), level = "debug")] + fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) { + let literal = constant.literal; + constant.literal = self.renumber_regions_in_mir_constant(literal); + debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 895723d44..5d750c6ca 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,9 +1,12 @@ -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::{IntoDiagnosticArg, MultiSpan}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; +use crate::diagnostics::RegionName; + #[derive(SessionDiagnostic)] -#[error(borrowck::move_unsized, code = "E0161")] +#[diag(borrowck::move_unsized, code = "E0161")] pub(crate) struct MoveUnsized<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -12,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> { } #[derive(SessionDiagnostic)] -#[error(borrowck::higher_ranked_lifetime_error)] +#[diag(borrowck::higher_ranked_lifetime_error)] pub(crate) struct HigherRankedLifetimeError { #[subdiagnostic] pub cause: Option, @@ -29,16 +32,128 @@ pub(crate) enum HigherRankedErrorCause { } #[derive(SessionDiagnostic)] -#[error(borrowck::higher_ranked_subtype_error)] +#[diag(borrowck::higher_ranked_subtype_error)] pub(crate) struct HigherRankedSubtypeError { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(borrowck::generic_does_not_live_long_enough)] +#[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_short(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(borrowck::const_not_used_in_type_alias)] +pub(crate) struct ConstNotUsedTraitAlias { + pub ct: String, + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(borrowck::var_cannot_escape_closure)] +#[note] +#[note(borrowck::cannot_escape)] +pub(crate) struct FnMutError { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub ty_err: FnMutReturnTypeErr, +} + +#[derive(SessionSubdiagnostic)] +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(SessionSubdiagnostic)] +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(SessionDiagnostic)] +#[diag(borrowck::lifetime_constraints_error)] +pub(crate) struct LifetimeOutliveErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionSubdiagnostic)] +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, + }, +} + +impl IntoDiagnosticArg for &RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{}", self).into_diagnostic_arg() + } +} + +impl IntoDiagnosticArg for RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{}", self).into_diagnostic_arg() + } +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum RequireStaticErr { + #[note(borrowck::used_impl_require_static)] + UsedImpl { + #[primary_span] + multi_span: MultiSpan, + }, +} diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 6cfe5efb6..9271a2f4d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -24,8 +24,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// **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, category, op), level = "trace")] - pub(super) fn fully_perform_op( + #[instrument(skip(self, op), level = "trace")] + pub(super) fn fully_perform_op( &mut self, locations: Locations, category: ConstraintCategory<'tcx>, @@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; + debug!(?output, ?constraints); + if let Some(data) = constraints { self.push_region_constraints(locations, category, data); } @@ -90,17 +92,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) { - self.prove_predicates( - Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + self.prove_predicate( + ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, - }))), + })) + .to_predicate(self.tcx()), 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 @@ -115,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .zip(instantiated_predicates.spans.into_iter()) { debug!(?predicate); - let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); + let category = ConstraintCategory::Predicate(span); + let predicate = self.normalize_with_category(predicate, locations, category); + self.prove_predicate(predicate, locations, category); } } @@ -152,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }) } - #[instrument(skip(self), level = "debug")] 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; self.fully_perform_op( location.to_locations(), - ConstraintCategory::Boring, + category, param_env.and(type_op::normalize::Normalize::new(value)), ) .unwrap_or_else(|NoSolution| { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 167960918..71eae0583 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Span, DUMMY_SP}; @@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { + fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. @@ -98,34 +98,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // region constraints like `for<'a> 'a: 'b`. At some point // when we move to universes, we will, and this assertion // will start to fail. - let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", query_constraint,); - }); + let ty::OutlivesPredicate(k1, r2) = + query_constraint.0.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", query_constraint,); + }); + + let constraint_category = query_constraint.1; 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); + self.add_outlives(r1_vid, r2_vid, constraint_category); } - GenericArgKind::Type(mut t1) => { + GenericArgKind::Type(t1) => { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(DUMMY_SP, t1, None); - // Placeholder regions need to be converted now because it may - // create new region variables, which can't be done later when - // verifying these bounds. - if t1.has_placeholders() { - t1 = tcx.fold_regions(t1, |r, _| match *r { - ty::RePlaceholder(placeholder) => { - self.constraints.placeholder_region(self.infcx, placeholder) - } - _ => r, - }); - } - TypeOutlives::new( &mut *self, tcx, @@ -133,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { Some(implicit_region_bound), param_env, ) - .type_must_outlive(origin, t1, r2); + .type_must_outlive(origin, t1, r2, constraint_category); } GenericArgKind::Const(_) => { @@ -143,6 +134,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } + /// 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>, @@ -150,7 +160,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { verify_bound: VerifyBound<'tcx>, ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); - TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } } @@ -162,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { + 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: self.category, + category, span: self.span, sub, sup, @@ -185,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' _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); + self.add_outlives(b, a, constraint_category); } fn push_verify( @@ -198,6 +217,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' 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); } 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 cc0318ede..f1b1c33a1 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,5 +1,5 @@ use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::transitive_relation::TransitiveRelation; +use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -61,25 +61,13 @@ pub(crate) fn create<'tcx>( constraints, universal_regions: universal_regions.clone(), region_bound_pairs: Default::default(), - relations: UniversalRegionRelations { - universal_regions: universal_regions.clone(), - outlives: Default::default(), - inverse_outlives: Default::default(), - }, + outlives: Default::default(), + inverse_outlives: Default::default(), } .create() } impl UniversalRegionRelations<'_> { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the - /// builder below. - 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); - } - /// Given two universal regions, returns the postdominating /// upper-bound (effectively the least upper bound). /// @@ -216,11 +204,20 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> { constraints: &'this mut MirTypeckRegionConstraints<'tcx>, // outputs: - relations: UniversalRegionRelations<'tcx>, + 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); + } + pub(crate) fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions @@ -242,10 +239,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let constraint_sets: Vec<_> = unnormalized_input_output_tys .flat_map(|ty| { debug!("build: input_or_output={:?}", ty); - // We only add implied bounds for the normalized type as the unnormalized - // type may not actually get checked by the caller. - // - // Can otherwise be unsound, see #91068. + // We add implied bounds from both the unnormalized and normalized ty. + // See issue #87748 + let constraints_implied1 = self.add_implied_bounds(ty); let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) @@ -269,13 +265,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // } // impl Foo for () { // type Bar = (); - // fn foo(&self) ->&() {} + // fn foo(&self) -> &() {} // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied = self.add_implied_bounds(norm_ty); + let constraints_implied2 = + if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied) + constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2) }) .collect(); @@ -292,9 +289,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { 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.relations.relate_universal_regions(fr, fr); - self.relations.relate_universal_regions(fr_static, fr); - self.relations.relate_universal_regions(fr, fr_fn_body); + self.relate_universal_regions(fr, fr); + self.relate_universal_regions(fr_static, fr); + self.relate_universal_regions(fr, fr_fn_body); } for data in &constraint_sets { @@ -313,7 +310,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } CreateResult { - universal_region_relations: Frozen::freeze(self.relations), + universal_region_relations: Frozen::freeze(UniversalRegionRelations { + universal_regions: self.universal_regions, + outlives: self.outlives.freeze(), + inverse_outlives: self.inverse_outlives.freeze(), + }), region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, } @@ -346,17 +347,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { - // `where Type:` is lowered to `where Type: 'empty` so that - // we check `Type` is well formed, but there's no use for - // this bound here. - if r1.is_empty() { - return; - } - // 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.relations.relate_universal_regions(r2, r1); + self.relate_universal_regions(r2, r1); } OutlivesBound::RegionSubParam(r_a, param_b) => { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d32b1edcd..3713ec3f5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, - OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, + OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, + UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -178,97 +179,15 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars, }; - let opaque_type_values = type_check_internal( + let mut checker = TypeChecker::new( infcx, - param_env, body, - promoted, + param_env, ®ion_bound_pairs, implicit_region_bound, &mut borrowck_context, - |mut cx| { - debug!("inside extra closure of type_check_internal"); - cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); - liveness::generate( - &mut cx, - body, - elements, - flow_inits, - move_data, - location_table, - use_polonius, - ); - - translate_outlives_facts(&mut cx); - let opaque_type_values = - infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - - opaque_type_values - .into_iter() - .map(|(opaque_type_key, decl)| { - cx.fully_perform_op( - Locations::All(body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.register_member_constraints( - param_env, - opaque_type_key, - decl.hidden_type.ty, - decl.hidden_type.span, - ); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - ) - .unwrap(); - let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); - trace!( - "finalized opaque type {:?} to {:#?}", - opaque_type_key, - hidden_type.ty.kind() - ); - if hidden_type.has_infer_types_or_consts() { - infcx.tcx.sess.delay_span_bug( - decl.hidden_type.span, - &format!("could not resolve {:#?}", hidden_type.ty.kind()), - ); - hidden_type.ty = infcx.tcx.ty_error(); - } - - (opaque_type_key, (hidden_type, decl.origin)) - }) - .collect() - }, ); - MirTypeckResults { constraints, universal_region_relations, opaque_type_values } -} - -#[instrument( - skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra), - level = "debug" -)] -fn type_check_internal<'a, 'tcx, R>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &'a Body<'tcx>, - promoted: &'a IndexVec>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, -) -> R { - debug!("body: {:#?}", body); - let mut checker = TypeChecker::new( - infcx, - body, - param_env, - region_bound_pairs, - implicit_region_bound, - borrowck_context, - ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, promoted); verifier.visit_body(&body); @@ -280,7 +199,56 @@ fn type_check_internal<'a, 'tcx, R>( checker.typeck_mir(body); } - extra(checker) + checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); + liveness::generate( + &mut checker, + body, + elements, + flow_inits, + move_data, + location_table, + use_polonius, + ); + + translate_outlives_facts(&mut checker); + let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + let opaque_type_values = opaque_type_values + .into_iter() + .map(|(opaque_type_key, decl)| { + checker + .fully_perform_op( + Locations::All(body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.register_member_constraints( + param_env, + opaque_type_key, + decl.hidden_type.ty, + decl.hidden_type.span, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + ) + .unwrap(); + let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); + if hidden_type.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + decl.hidden_type.span, + &format!("could not resolve {:#?}", hidden_type.ty.kind()), + ); + hidden_type.ty = infcx.tcx.ty_error(); + } + + (opaque_type_key, (hidden_type, decl.origin)) + }) + .collect(); + + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -344,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + debug!(?constant, ?location, "visit_constant"); + self.super_constant(constant, location); let ty = self.sanitize_type(constant, constant.literal.ty()); @@ -387,11 +357,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let maybe_uneval = match constant.literal { ConstantKind::Ty(ct) => match ct.kind() { - ty::ConstKind::Unevaluated(uv) => Some(uv), + ty::ConstKind::Unevaluated(_) => { + bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct) + } _ => None, }, + ConstantKind::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>, @@ -1076,6 +1050,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); + debug!(?annotation); match annotation { UserType::Ty(mut ty) => { ty = self.normalize(ty, Locations::All(span)); @@ -1334,12 +1309,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => span_bug!( - stmt.source_info.span, - "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), + StatementKind::Intrinsic(box ref 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(..) @@ -1448,9 +1424,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )) }); debug!(?sig); - let sig = self.normalize(sig, term_location); - self.check_call_dest(body, term, &sig, *destination, target, term_location); - + // 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( sig.inputs_and_output .iter() @@ -1458,6 +1439,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term_location.to_locations(), ConstraintCategory::Boring, ); + let sig = self.normalize(sig, term_location); + 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 @@ -1834,14 +1817,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } 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.literal { - ConstantKind::Ty(ct) => match ct.kind() { - ty::ConstKind::Unevaluated(uv) => Some(uv), - _ => None, - }, - _ => None, + ConstantKind::Val(..) | ConstantKind::Ty(_) => None, + ConstantKind::Unevaluated(uv, _) => Some(uv), }; + if let Some(uv) = maybe_uneval { if uv.promoted.is_none() { let tcx = self.tcx(); @@ -1904,7 +1887,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(_, ty) => { + &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2033,6 +2016,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } + 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, + ); + + let outlives_predicate = + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + ))); + self.prove_predicate( + outlives_predicate, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + CastKind::Pointer(PointerCast::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, @@ -2584,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .enumerate() .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = - constraint.no_bound_vars().unwrap_or_else(|| { + constraint.0.no_bound_vars().unwrap_or_else(|| { bug!("query_constraint {:?} contained bound vars", constraint,); }); @@ -2659,7 +2672,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_local(&body, local, local_decl); } - for (block, block_data) in body.basic_blocks().iter_enumerated() { + 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() { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 2a7713bc4..8cf9ed53d 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -54,13 +54,6 @@ pub struct UniversalRegions<'tcx> { /// The total number of universal region variables instantiated. num_universals: usize, - /// A special region variable created for the `'empty(U0)` region. - /// Note that this is **not** a "universal" region, as it doesn't - /// represent a universally bound placeholder or any such thing. - /// But we do create it here in this type because it's a useful region - /// to have around in a few limited cases. - pub root_empty: RegionVid, - /// The "defining" type for this function, with all universal /// regions instantiated. For a closure or generator, this is the /// closure type, but for a top-level function it's the `FnDef`. @@ -323,11 +316,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// See `UniversalRegionIndices::to_region_vid`. pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r { - self.root_empty - } else { - self.indices.to_region_vid(r) - } + self.indices.to_region_vid(r) } /// As part of the NLL unit tests, you can annotate a function with @@ -501,16 +490,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { _ => None, }; - let root_empty = self - .infcx - .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true }) - .to_region_vid(); - UniversalRegions { indices, fr_static, fr_fn_body, - root_empty, first_extern_index, first_local_index, num_universals, @@ -768,10 +751,9 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { mir_def_id: LocalDefId, indices: &mut UniversalRegionIndices<'tcx>, ) { - debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id()); for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| { - debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); + debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); debug!(?region_vid); diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 8d8e9d9b5..6469d0d7b 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -7,20 +7,21 @@ edition = "2021" doctest = false [dependencies] -rustc_parse_format = { path = "../rustc_parse_format" } -tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } +rustc_parse_format = { path = "../rustc_parse_format" } rustc_parse = { path = "../rustc_parse" } -rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -rustc_ast = { path = "../rustc_ast" } -rustc_expand = { path = "../rustc_expand" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +thin-vec = "0.2.8" +tracing = "0.1" diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1a0ea8f41..a1051d990 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -852,7 +852,7 @@ pub(super) fn expand_global_asm<'cx>( if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { MacEager::items(smallvec![P(ast::Item { ident: Ident::empty(), - attrs: Vec::new(), + attrs: ast::AttrVec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), vis: ast::Visibility { diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 925c36edb..119724b50 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -52,7 +52,7 @@ pub fn expand_assert<'cx>( let expr = if let Some(tokens) = custom_message { let then = cx.expr( call_site_span, - ExprKind::MacCall(MacCall { + ExprKind::MacCall(P(MacCall { path: panic_path(), args: P(MacArgs::Delimited( DelimSpan::from_single(call_site_span), @@ -60,7 +60,7 @@ pub fn expand_assert<'cx>( tokens, )), prior_type_ascription: None, - }), + })), ); expr_if_not(cx, call_site_span, cond_expr, then, None) } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index dcea883a5..f80215a3c 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -13,6 +13,7 @@ use rustc_span::{ symbol::{sym, Ident, Symbol}, Span, }; +use thin_vec::thin_vec; pub(super) struct Context<'cx, 'a> { // An optimization. @@ -116,7 +117,7 @@ impl<'cx, 'a> Context<'cx, 'a> { self.cx.item( self.span, Ident::empty(), - vec![self.cx.attribute(attr::mk_list_item( + thin_vec![self.cx.attribute(attr::mk_list_item( Ident::new(sym::allow, self.span), vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))], ))], @@ -177,7 +178,7 @@ impl<'cx, 'a> Context<'cx, 'a> { }); self.cx.expr( self.span, - ExprKind::MacCall(MacCall { + ExprKind::MacCall(P(MacCall { path: panic_path, args: P(MacArgs::Delimited( DelimSpan::from_single(self.span), @@ -185,7 +186,7 @@ impl<'cx, 'a> Context<'cx, 'a> { initial.into_iter().chain(captures).collect::(), )), prior_type_ascription: None, - }), + })), ) } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index aa355150b..9046bf130 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -36,7 +36,7 @@ pub fn expand_cfg( } #[derive(SessionDiagnostic)] -#[error(builtin_macros::requires_cfg_pattern)] +#[diag(builtin_macros::requires_cfg_pattern)] struct RequiresCfgPattern { #[primary_span] #[label] @@ -44,7 +44,7 @@ struct RequiresCfgPattern { } #[derive(SessionDiagnostic)] -#[error(builtin_macros::expected_one_cfg_pattern)] +#[diag(builtin_macros::expected_one_cfg_pattern)] struct OneCfgPattern { #[primary_span] span: Span, diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 89b2c3292..e673dff0d 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -188,14 +188,14 @@ impl CfgEval<'_, '_> { let orig_tokens = annotatable.to_tokens().flattened(); // Re-parse the tokens, setting the `capture_cfg` flag to save extra information - // to the captured `AttrAnnotatedTokenStream` (specifically, we capture - // `AttrAnnotatedTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // 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.parse_sess, orig_tokens, None); parser.capture_cfg = true; annotatable = parse_annotatable_with(&mut parser); - // Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring + // Now that we have our re-parsed `AttrTokenStream`, recursively configuring // our attribute target will correctly the tokens as well. flat_map_annotatable(self, annotatable) } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 747e48ece..db05c00d2 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -28,7 +28,13 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - continue; } - krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span))); + krate.attrs.push(mk_attr( + &parse_sess.attr_id_generator, + AttrStyle::Inner, + path, + args, + start_span.to(end_span), + )); } krate diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index a23dd1d12..41f4e8c23 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -39,7 +39,7 @@ pub fn expand_concat( ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => { cx.span_err(e.span, "cannot concatenate a byte string literal"); } - ast::LitKind::Err(_) => { + ast::LitKind::Err => { has_errors = true; } }, diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a1afec410..66e86bf21 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,5 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; @@ -43,7 +42,7 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne ast::LitKind::Bool(_) => { cx.span_err(expr.span, "cannot concatenate boolean literals"); } - ast::LitKind::Err(_) => {} + ast::LitKind::Err => {} ast::LitKind::Int(_, _) if !is_nested => { let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { @@ -185,5 +184,5 @@ pub fn expand_concat_bytes( return base::MacEager::expr(DummyResult::raw_expr(sp, true)); } let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(accumulator)))) + base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index d3de10ca4..e0fb7affb 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -32,7 +32,8 @@ impl MultiItemModifier for Expander { ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; - let attr = attr::mk_attr_outer(meta_item.clone()); + let attr = + attr::mk_attr_outer(&sess.parse_sess.attr_id_generator, meta_item.clone()); validate_attr::check_builtin_attribute( &sess.parse_sess, &attr, @@ -126,9 +127,9 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { } fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) { - let help_msg = match lit.token.kind { - token::Str if rustc_lexer::is_ident(lit.token.symbol.as_str()) => { - format!("try using `#[derive({})]`", lit.token.symbol) + let help_msg = match lit.token_lit.kind { + token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => { + format!("try using `#[derive({})]`", lit.token_lit.symbol) } _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), }; diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 5ef68c6ae..77e0b6c55 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -15,7 +15,6 @@ pub fn expand_deriving_copy( ) { let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(marker::Copy), additional_bounds: Vec::new(), generics: Bounds::empty(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 7755ff779..c7f2d95e7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,12 +1,12 @@ 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; pub fn expand_deriving_clone( cx: &mut ExtCtxt<'_>, @@ -68,10 +68,9 @@ pub fn expand_deriving_clone( } let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attribute(inline)]; let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(clone::Clone), additional_bounds: bounds, generics: Bounds::empty(), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 4e798bf6a..5b556c5c9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -7,6 +7,7 @@ use rustc_data_structures::fx::FxHashSet; 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_eq( cx: &mut ExtCtxt<'_>, @@ -20,10 +21,9 @@ pub fn expand_deriving_eq( let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); let no_coverage = cx.meta_word(span, sym::no_coverage); - let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)]; + let attrs = thin_vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)]; let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(cmp::Eq), additional_bounds: Vec::new(), generics: Bounds::empty(), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1612be862..726258695 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -1,11 +1,11 @@ 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: &mut ExtCtxt<'_>, @@ -15,10 +15,9 @@ pub fn expand_deriving_ord( push: &mut dyn FnMut(Annotatable), ) { let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attribute(inline)]; let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(cmp::Ord), additional_bounds: Vec::new(), generics: Bounds::empty(), 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 0141b3377..42ee65b57 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,12 +1,12 @@ 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: &mut ExtCtxt<'_>, @@ -15,14 +15,8 @@ pub fn expand_deriving_partial_eq( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { - fn cs_op( - cx: &mut ExtCtxt<'_>, - span: Span, - substr: &Substructure<'_>, - op: BinOpKind, - combiner: BinOpKind, - base: bool, - ) -> BlockOrExpr { + fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { + let base = true; let expr = cs_fold( true, // use foldl cx, @@ -47,39 +41,22 @@ pub fn expand_deriving_partial_eq( cx.expr_deref(field.span, expr.clone()) } }; - cx.expr_binary(field.span, op, convert(&field.self_expr), convert(other_expr)) + 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::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2), CsFold::Fieldless => cx.expr_bool(span, base), }, ); BlockOrExpr::new_expr(expr) } - fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true) - } - fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false) - } - - macro_rules! md { - ($name:expr, $f:ident) => {{ - let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; - MethodDef { - name: $name, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], - ret_ty: Path(path_local!(bool)), - attributes: attrs, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))), - } - }}; - } - super::inject_impl_of_structural_trait( cx, span, @@ -88,17 +65,23 @@ pub fn expand_deriving_partial_eq( push, ); - // avoid defining `ne` if we can - // c-like enums, enums without any fields and structs without fields - // can safely define only `eq`. - let mut methods = vec![md!(sym::eq, cs_eq)]; - if !is_type_without_fields(item) { - methods.push(md!(sym::ne, cs_ne)); - } + // No need to generate `ne`, the default suffices, and not generating it is + // faster. + let inline = cx.meta_word(span, sym::inline); + let attrs = thin_vec![cx.attribute(inline)]; + 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: attrs, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), + }]; let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(cmp::PartialEq), additional_bounds: Vec::new(), generics: Bounds::empty(), 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 2ebb01cc8..516892aed 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,11 +1,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_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_partial_ord( cx: &mut ExtCtxt<'_>, @@ -19,7 +19,7 @@ pub fn expand_deriving_partial_ord( Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attribute(inline)]; let partial_cmp_def = MethodDef { name: sym::partial_cmp, @@ -36,7 +36,6 @@ pub fn expand_deriving_partial_ord( let trait_def = TraitDef { span, - attributes: vec![], path: path_std!(cmp::PartialOrd), additional_bounds: vec![], generics: Bounds::empty(), diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index ceef893e8..4af7fd816 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -19,7 +19,6 @@ pub fn expand_deriving_debug( let trait_def = TraitDef { span, - attributes: Vec::new(), path: path_std!(fmt::Debug), additional_bounds: Vec::new(), generics: Bounds::empty(), @@ -30,7 +29,7 @@ pub fn expand_deriving_debug( explicit_self: true, nonself_args: vec![(fmtr, sym::f)], ret_ty: Path(path_std!(fmt::Result)), - attributes: Vec::new(), + attributes: ast::AttrVec::new(), unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { show_substructure(a, b, c) @@ -52,7 +51,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> // 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 name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); + 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, @@ -89,10 +88,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> for i in 0..fields.len() { let field = &fields[i]; if is_struct { - let name = cx.expr_lit( - field.span, - ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), - ); + let name = cx.expr_str(field.span, field.name.unwrap().name); args.push(name); } // Use an extra indirection to make sure this works for unsized types. @@ -108,10 +104,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> for field in fields { if is_struct { - name_exprs.push(cx.expr_lit( - field.span, - ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), - )); + name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name)); } // Use an extra indirection to make sure this works for unsized types. diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index d688143a2..7174dbbe7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -22,7 +22,6 @@ pub fn expand_deriving_rustc_decodable( let trait_def = TraitDef { span, - attributes: Vec::new(), path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), additional_bounds: Vec::new(), generics: Bounds::empty(), @@ -48,7 +47,7 @@ pub fn expand_deriving_rustc_decodable( ], PathKind::Std, )), - attributes: Vec::new(), + attributes: ast::AttrVec::new(), unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { decodable_substructure(a, b, c, krate) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 517769091..a94c8a996 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,16 +1,14 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; - use rustc_ast as ast; -use rustc_ast::walk_list; -use rustc_ast::EnumDef; -use rustc_ast::VariantData; +use rustc_ast::{walk_list, EnumDef, VariantData}; use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use smallvec::SmallVec; +use thin_vec::thin_vec; pub fn expand_deriving_default( cx: &mut ExtCtxt<'_>, @@ -22,10 +20,9 @@ pub fn expand_deriving_default( item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); let inline = cx.meta_word(span, sym::inline); - let attrs = vec![cx.attribute(inline)]; + let attrs = thin_vec![cx.attribute(inline)]; let trait_def = TraitDef { span, - attributes: Vec::new(), path: Path::new(vec![kw::Default, sym::Default]), additional_bounds: Vec::new(), generics: Bounds::empty(), diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 70167cac6..b220e5423 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -89,7 +89,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; -use rustc_ast::{ExprKind, MetaItem, Mutability}; +use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -106,7 +106,6 @@ pub fn expand_deriving_rustc_encodable( let trait_def = TraitDef { span, - attributes: Vec::new(), path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), additional_bounds: Vec::new(), generics: Bounds::empty(), @@ -132,7 +131,7 @@ pub fn expand_deriving_rustc_encodable( ], PathKind::Std, )), - attributes: Vec::new(), + attributes: AttrVec::new(), unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { encodable_substructure(a, b, c, krate) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 735017aa5..3cc160adb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -162,30 +162,28 @@ pub use StaticFields::*; pub use SubstructureFields::*; -use std::cell::RefCell; -use std::iter; -use std::vec; - +use crate::deriving; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind}; +use rustc_ast::{ + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, +}; use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; - +use std::cell::RefCell; +use std::iter; +use std::vec; +use thin_vec::thin_vec; use ty::{Bounds, Path, Ref, Self_, Ty}; -use crate::deriving; - pub mod ty; pub struct TraitDef<'a> { /// The span for the current #[derive(Foo)] header. pub span: Span, - pub attributes: Vec, - /// Path of the trait, including any type parameters pub path: Path, @@ -219,7 +217,7 @@ pub struct MethodDef<'a> { /// Returns type pub ret_ty: Ty, - pub attributes: Vec, + pub attributes: ast::AttrVec, /// Can we combine fieldless variants for enums into a single match arm? /// If true, indicates that the trait operation uses the enum tag in some @@ -383,16 +381,11 @@ fn find_type_parameters( } // 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, - modifier: &'a ast::TraitBoundModifier, - ) { + 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.clone().into_iter()); + self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned()); - visit::walk_poly_trait_ref(self, trait_ref, modifier); + visit::walk_poly_trait_ref(self, trait_ref); self.bound_generic_params_stack.truncate(stack_len); } @@ -568,7 +561,7 @@ impl<'a> TraitDef<'a> { kind: ast::VisibilityKind::Inherited, tokens: None, }, - attrs: Vec::new(), + attrs: ast::AttrVec::new(), kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias { defaultness: ast::Defaultness::Final, generics: Generics::default(), @@ -609,7 +602,7 @@ impl<'a> TraitDef<'a> { param.bounds.iter().cloned() ).collect(); - cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None) + cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) } GenericParamKind::Const { ty, kw_span, .. } => { let const_nodefault_kind = GenericParamKind::Const { @@ -644,11 +637,7 @@ impl<'a> TraitDef<'a> { } ast::WherePredicate::EqPredicate(we) => { let span = we.span.with_ctxt(ctxt); - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - id: ast::DUMMY_NODE_ID, - span, - ..we.clone() - }) + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() }) } } })); @@ -726,15 +715,13 @@ impl<'a> TraitDef<'a> { let self_type = cx.ty_path(path); let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived)); + let attrs = thin_vec![attr]; let opt_trait_ref = Some(trait_ref); - let mut a = vec![attr]; - a.extend(self.attributes.iter().cloned()); - cx.item( self.span, Ident::empty(), - a, + attrs, ast::ItemKind::Impl(Box::new(ast::Impl { unsafety: ast::Unsafe::No, polarity: ast::ImplPolarity::Positive, @@ -1078,9 +1065,9 @@ impl<'a> MethodDef<'a> { let mut body = mk_body(cx, selflike_fields); let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); - let use_ref_pat = is_packed && !always_copy; + let by_ref = ByRef::from(is_packed && !always_copy); let patterns = - trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat); + trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref); // Do the let-destructuring. let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) @@ -1262,13 +1249,13 @@ impl<'a> MethodDef<'a> { let sp = variant.span.with_ctxt(trait_.span.ctxt()); let variant_path = cx.path(sp, vec![type_ident, variant.ident]); - let use_ref_pat = false; // because enums can't be repr(packed) + let by_ref = ByRef::No; // because enums can't be repr(packed) let mut subpats: Vec<_> = trait_.create_struct_patterns( cx, variant_path, &variant.data, &prefixes, - use_ref_pat, + by_ref, ); // `(VariantK, VariantK, ...)` or just `VariantK`. @@ -1429,7 +1416,7 @@ impl<'a> TraitDef<'a> { struct_path: ast::Path, struct_def: &'a VariantData, prefixes: &[String], - use_ref_pat: bool, + by_ref: ByRef, ) -> Vec> { prefixes .iter() @@ -1437,17 +1424,19 @@ impl<'a> TraitDef<'a> { let pieces_iter = struct_def.fields().iter().enumerate().map(|(i, struct_field)| { let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let binding_mode = if use_ref_pat { - ast::BindingMode::ByRef(ast::Mutability::Not) - } else { - ast::BindingMode::ByValue(ast::Mutability::Not) - }; 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(binding_mode, path, None)), + cx.pat( + path.span, + PatKind::Ident( + BindingAnnotation(by_ref, Mutability::Not), + path, + None, + ), + ), ) }); @@ -1637,19 +1626,3 @@ where StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } - -/// Returns `true` if the type has no value fields -/// (for an enum, no variant has any fields) -pub fn is_type_without_fields(item: &Annotatable) -> bool { - if let Annotatable::Item(ref item) = *item { - match item.kind { - ast::ItemKind::Enum(ref enum_def, _) => { - enum_def.variants.iter().all(|v| v.data.fields().is_empty()) - } - ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(), - _ => false, - } - } else { - false - } -} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 4d46f7cd4..36e2e2930 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -146,7 +146,6 @@ fn mk_ty_param( cx: &ExtCtxt<'_>, span: Span, name: Symbol, - attrs: &[ast::Attribute], bounds: &[Path], self_ident: Ident, self_generics: &Generics, @@ -158,7 +157,7 @@ fn mk_ty_param( cx.trait_bound(path) }) .collect(); - cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None) + cx.typaram(span, Ident::new(name, span), bounds, None) } /// Bounds on type parameters. @@ -183,7 +182,7 @@ impl Bounds { .iter() .map(|t| { let (name, ref bounds) = *t; - mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics) + mk_ty_param(cx, span, name, &bounds, self_ty, self_generics) }) .collect(); diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 32ae3d344..f1f02e7ce 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -2,7 +2,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::{MetaItem, Mutability}; +use rustc_ast::{AttrVec, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -21,7 +21,6 @@ pub fn expand_deriving_hash( let arg = Path::new_local(typaram); let hash_trait_def = TraitDef { span, - attributes: Vec::new(), path, additional_bounds: Vec::new(), generics: Bounds::empty(), @@ -32,7 +31,7 @@ pub fn expand_deriving_hash( explicit_self: true, nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], ret_ty: Unit, - attributes: vec![], + attributes: AttrVec::new(), unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index c1ca089da..a65d0bad6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -164,7 +164,7 @@ fn inject_impl_of_structural_trait( // Keep the lint and stability attributes of the original item, to control // how the generated implementation is linted. - let mut attrs = Vec::new(); + let mut attrs = ast::AttrVec::new(); attrs.extend( item.attrs .iter() diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index ea0e768a5..3f1a8b3bc 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -48,7 +48,7 @@ fn expand<'cx>( MacEager::expr( cx.expr( sp, - ExprKind::MacCall(MacCall { + ExprKind::MacCall(P(MacCall { path: Path { span: sp, segments: cx @@ -64,7 +64,7 @@ fn expand<'cx>( tts, )), prior_type_ascription: None, - }), + })), ), ) } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9eb96ec76..210048710 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -130,64 +130,46 @@ impl PositionalNamedArgsLint { /// CountIsParam, which contains an index into the arguments. fn maybe_add_positional_named_arg( &mut self, - current_positional_arg: usize, - total_args_length: usize, - format_argument_index: usize, + arg: Option<&FormatArg>, ty: PositionalNamedArgType, cur_piece: usize, inner_span_to_replace: Option, - names: &FxHashMap, has_formatting: bool, ) { - let start_of_named_args = total_args_length - names.len(); - if current_positional_arg >= start_of_named_args { - self.maybe_push( - format_argument_index, - ty, - cur_piece, - inner_span_to_replace, - names, - has_formatting, - ) + if let Some(arg) = arg { + if let Some(name) = arg.name { + self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting) + } } } - /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional - /// named arguments. If a named arg associated with `format_argument_index` cannot be found, - /// a new item will not be added as the lint cannot be emitted in this case. - fn maybe_push( + /// Construct a PositionalNamedArg struct and push it into the vec of positional + /// named arguments. + fn push( &mut self, - format_argument_index: usize, + arg_name: Ident, ty: PositionalNamedArgType, cur_piece: usize, inner_span_to_replace: Option, - names: &FxHashMap, has_formatting: bool, ) { - let named_arg = names - .iter() - .find(|&(_, &(index, _))| index == format_argument_index) - .map(|found| found.clone()); - - if let Some((&replacement, &(_, positional_named_arg_span))) = named_arg { - // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in - // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is - // `Precision`. - let inner_span_to_replace = if ty == PositionalNamedArgType::Precision { - inner_span_to_replace - .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end }) - } else { - inner_span_to_replace - }; - self.positional_named_args.push(PositionalNamedArg { - ty, - cur_piece, - inner_span_to_replace, - replacement, - positional_named_arg_span, - has_formatting, - }); - } + // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in + // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is + // `Precision`. + let inner_span_to_replace = if ty == PositionalNamedArgType::Precision { + inner_span_to_replace + .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end }) + } else { + inner_span_to_replace + }; + self.positional_named_args.push(PositionalNamedArg { + ty, + cur_piece, + inner_span_to_replace, + replacement: arg_name.name, + positional_named_arg_span: arg_name.span, + has_formatting, + }); } } @@ -211,7 +193,7 @@ struct Context<'a, 'b> { /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]` /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]` /// * `names` (in JSON): `{"foo": 2}` - args: Vec>, + args: Vec, /// The number of arguments that were added by implicit capturing. num_captured_args: usize, /// Placeholder slot numbers indexed by argument. @@ -219,7 +201,7 @@ struct Context<'a, 'b> { /// Unique format specs seen for each argument. arg_unique_types: Vec>, /// Map from named arguments to their resolved indices. - names: FxHashMap, + names: FxHashMap, /// The latest consecutive literal strings, or empty if there weren't any. literal: String, @@ -282,7 +264,7 @@ struct Context<'a, 'b> { pub struct FormatArg { expr: P, - named: bool, + name: Option, } /// Parses the arguments from the given list of tokens, returning the diagnostic @@ -298,9 +280,9 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> PResult<'a, (P, Vec, FxHashMap)> { +) -> PResult<'a, (P, Vec, FxHashMap)> { let mut args = Vec::::new(); - let mut names = FxHashMap::::default(); + let mut names = FxHashMap::::default(); let mut p = ecx.new_parser_from_tts(tts); @@ -365,9 +347,9 @@ fn parse_args<'a>( p.bump(); p.expect(&token::Eq)?; let e = p.parse_expr()?; - if let Some((prev, _)) = names.get(&ident.name) { + if let Some(&prev) = names.get(&ident.name) { ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) - .span_label(args[*prev].expr.span, "previously here") + .span_label(args[prev].expr.span, "previously here") .span_label(e.span, "duplicate argument") .emit(); continue; @@ -378,8 +360,8 @@ fn parse_args<'a>( // if the input is valid, we can simply append to the positional // args. And remember the names. let slot = args.len(); - names.insert(ident.name, (slot, ident.span)); - args.push(FormatArg { expr: e, named: true }); + names.insert(ident.name, slot); + args.push(FormatArg { expr: e, name: Some(ident) }); } _ => { let e = p.parse_expr()?; @@ -389,12 +371,12 @@ fn parse_args<'a>( "positional arguments cannot follow named arguments", ); err.span_label(e.span, "positional arguments must be before named arguments"); - for pos in names.values() { - err.span_label(args[pos.0].expr.span, "named argument"); + for &pos in names.values() { + err.span_label(args[pos].expr.span, "named argument"); } err.emit(); } - args.push(FormatArg { expr: e, named: false }); + args.push(FormatArg { expr: e, name: None }); } } } @@ -410,8 +392,7 @@ impl<'a, 'b> Context<'a, 'b> { fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) { // NOTE: the `unwrap_or` branch is needed in case of invalid format // arguments, e.g., `format_args!("{foo}")`. - let lookup = - |s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0; + let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0); match *p { parse::String(_) => {} @@ -432,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Verifies one piece of a parse string, and remembers it if valid. /// All errors are not emitted as fatal so we can continue giving errors /// about this and possibly other format strings. - fn verify_piece(&mut self, p: &parse::Piece<'_>) { + fn verify_piece(&mut self, p: &parse::Piece<'a>) { match *p { parse::String(..) => {} parse::NextArgument(ref arg) => { @@ -452,18 +433,20 @@ impl<'a, 'b> Context<'a, 'b> { let has_precision = arg.format.precision != Count::CountImplied; let has_width = arg.format.width != Count::CountImplied; + if has_precision || has_width { + // push before named params are resolved to aid diagnostics + self.arg_with_formatting.push(arg.format); + } + // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { parse::ArgumentIs(i) => { self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, + self.args.get(i), PositionalNamedArgType::Arg, self.curpiece, Some(arg.position_span), - &self.names, has_precision || has_width, ); @@ -471,13 +454,10 @@ impl<'a, 'b> Context<'a, 'b> { } parse::ArgumentImplicitlyIs(i) => { self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, + self.args.get(i), PositionalNamedArgType::Arg, self.curpiece, None, - &self.names, has_precision || has_width, ); Exact(i) @@ -561,15 +541,12 @@ impl<'a, 'b> Context<'a, 'b> { ) { match c { parse::CountImplied | parse::CountIs(..) => {} - parse::CountIsParam(i) => { + parse::CountIsParam(i) | parse::CountIsStar(i) => { self.unused_names_lint.maybe_add_positional_named_arg( - i, - self.args.len(), - i, + self.args.get(i), named_arg_type, self.curpiece, *inner_span, - &self.names, true, ); self.verify_arg_type(Exact(i), Count); @@ -609,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> { let mut zero_based_note = false; let count = self.pieces.len() - + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count(); + + self + .arg_with_formatting + .iter() + .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) + .count(); if self.names.is_empty() && !numbered_position_args && count != self.num_args() { e = self.ecx.struct_span_err( sp, @@ -622,7 +603,7 @@ impl<'a, 'b> Context<'a, 'b> { ); for arg in &self.args { // Point at the arguments that will be formatted. - e.span_label(arg.span, ""); + e.span_label(arg.expr.span, ""); } } else { let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip(); @@ -658,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> { if let Some(span) = fmt.precision_span { let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); match fmt.precision { - parse::CountIsParam(pos) if pos > self.num_args() => { + parse::CountIsParam(pos) if pos >= self.num_args() => { e.span_label( span, &format!( @@ -670,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> { ); zero_based_note = true; } - parse::CountIsParam(pos) => { + parse::CountIsStar(pos) => { let count = self.pieces.len() + self .arg_with_formatting .iter() - .filter(|fmt| fmt.precision_span.is_some()) + .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) .count(); e.span_label( span, @@ -692,7 +673,7 @@ impl<'a, 'b> Context<'a, 'b> { ); if let Some(arg) = self.args.get(pos) { e.span_label( - arg.span, + arg.expr.span, "this parameter corresponds to the precision flag", ); } @@ -771,7 +752,7 @@ impl<'a, 'b> Context<'a, 'b> { match self.names.get(&name) { Some(&idx) => { // Treat as positional arg. - self.verify_arg_type(Capture(idx.0), ty) + self.verify_arg_type(Capture(idx), ty) } None => { // For the moment capturing variables from format strings expanded from macros is @@ -787,8 +768,11 @@ impl<'a, 'b> Context<'a, 'b> { self.fmtsp }; self.num_captured_args += 1; - self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); - self.names.insert(name, (idx, span)); + self.args.push(FormatArg { + expr: self.ecx.expr_ident(span, Ident::new(name, span)), + name: Some(Ident::new(name, span)), + }); + self.names.insert(name, idx); self.verify_arg_type(Capture(idx), ty) } else { let msg = format!("there is no argument named `{}`", name); @@ -853,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> { }; match c { parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))), - parse::CountIsParam(i) => { + parse::CountIsParam(i) | parse::CountIsStar(i) => { // This needs mapping too, as `i` is referring to a macro // argument. If `i` is not found in `count_positions` then // the error had already been emitted elsewhere. @@ -924,31 +908,27 @@ impl<'a, 'b> Context<'a, 'b> { }, position_span: arg.position_span, format: parse::FormatSpec { - fill: arg.format.fill, + fill: None, align: parse::AlignUnknown, flags: 0, precision: parse::CountImplied, - precision_span: None, + precision_span: arg.format.precision_span, width: parse::CountImplied, - width_span: None, + width_span: arg.format.width_span, ty: arg.format.ty, ty_span: arg.format.ty_span, }, }; let fill = arg.format.fill.unwrap_or(' '); - let pos_simple = arg.position.index() == simple_arg.position.index(); - if arg.format.precision_span.is_some() || arg.format.width_span.is_some() { - self.arg_with_formatting.push(arg.format); - } - if !pos_simple || arg.format != simple_arg.format || fill != ' ' { + if !pos_simple || arg.format != simple_arg.format { self.all_pieces_simple = false; } // Build the format - let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill)); + let fill = self.ecx.expr_char(sp, fill); let align = |name| { let mut p = Context::rtpath(self.ecx, sym::Alignment); p.push(Ident::new(name, sp)); @@ -1054,11 +1034,11 @@ impl<'a, 'b> Context<'a, 'b> { // evaluated a single time each, in the order written by the programmer, // and that the surrounding future/generator (if any) is Send whenever // possible. - let no_need_for_match = - nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e)); + let no_need_for_match = nicely_ordered + && !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr)); for (arg_index, arg_ty) in fmt_arg_index_and_ty { - let e = &mut original_args[arg_index]; + let e = &mut original_args[arg_index].expr; let span = e.span; let arg = if no_need_for_match { let expansion_span = e.span.with_ctxt(self.macsp.ctxt()); @@ -1087,7 +1067,9 @@ impl<'a, 'b> Context<'a, 'b> { // span is otherwise unavailable in the MIR used by borrowck). let heads = original_args .into_iter() - .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e)) + .map(|arg| { + self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr) + }) .collect(); let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp)); @@ -1199,7 +1181,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) cx.ecx.buffered_early_lint.push(BufferedEarlyLint { span: MultiSpan::from_span(named_arg.positional_named_arg_span), - msg: msg.clone(), + msg: msg.into(), node_id: ast::CRATE_NODE_ID, lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { @@ -1220,7 +1202,7 @@ pub fn expand_preparsed_format_args( sp: Span, efmt: P, args: Vec, - names: FxHashMap, + names: FxHashMap, append_newline: bool, ) -> P { // NOTE: this verbose way of initializing `Vec>` is because @@ -1312,16 +1294,17 @@ pub fn expand_preparsed_format_args( if err.should_be_replaced_with_positional_argument { let captured_arg_span = fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - let positional_args = args.iter().filter(|arg| !arg.named).collect::>(); + let n_positional_args = + args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1); if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { - let span = match positional_args.last() { + let span = match args[..n_positional_args].last() { Some(arg) => arg.expr.span, None => fmt_sp, }; e.multipart_suggestion_verbose( "consider using a positional formatting argument instead", vec![ - (captured_arg_span, positional_args.len().to_string()), + (captured_arg_span, n_positional_args.to_string()), (span.shrink_to_hi(), format!(", {}", arg)), ], Applicability::MachineApplicable, @@ -1338,11 +1321,9 @@ pub fn expand_preparsed_format_args( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(); - let named_pos: FxHashSet = names.values().cloned().map(|(i, _)| i).collect(); - let mut cx = Context { ecx, - args: args.into_iter().map(|arg| arg.expr).collect(), + args, num_captured_args: 0, arg_types, arg_unique_types, @@ -1410,14 +1391,12 @@ pub fn expand_preparsed_format_args( .enumerate() .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i)) .map(|(i, _)| { - let msg = if named_pos.contains(&i) { - // named argument + let msg = if cx.args[i].name.is_some() { "named argument never used" } else { - // positional argument "argument never used" }; - (cx.args[i].span, msg) + (cx.args[i].expr.span, msg) }) .collect::>(); diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 36cfbba45..45b9b8ab6 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -4,11 +4,12 @@ use rustc_ast::expand::allocator::{ AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS, }; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; +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; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -113,10 +114,10 @@ impl AllocFnFactory<'_, '_> { self.cx.expr_call(self.ty_span, method, args) } - fn attrs(&self) -> Vec { + fn attrs(&self) -> AttrVec { let special = sym::rustc_std_internal_symbol; let special = self.cx.meta_word(self.span, special); - vec![self.cx.attribute(special)] + thin_vec![self.cx.attribute(special)] } fn arg_ty( diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 11565ba72..8aeb3b82a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,13 +9,16 @@ #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] extern crate proc_macro; +#[macro_use] +extern crate tracing; + use crate::deriving::*; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 5cfda3349..ebe1c3663 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -281,7 +281,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { 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, Vec::new(), ast::ItemKind::ExternCrate(None)); + 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); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 8bf3a0799..d78bbc3c9 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -216,7 +216,7 @@ pub fn expand_include_bytes( } }; match cx.source_map().load_binary_file(&file) { - Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))), + Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)), Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 09ad5f9b3..49ef538f0 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -6,6 +6,7 @@ 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( mut krate: ast::Crate, @@ -51,7 +52,7 @@ pub fn inject( cx.item( span, ident, - vec![cx.attribute(cx.meta_word(span, sym::macro_use))], + thin_vec![cx.attribute(cx.meta_word(span, sym::macro_use))], ast::ItemKind::ExternCrate(None), ), ); @@ -78,7 +79,7 @@ pub fn inject( let use_item = cx.item( span, Ident::empty(), - vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], + thin_vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e20375689..7efb6cc61 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,7 +1,6 @@ /// 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 as ast; use rustc_ast::attr; use rustc_ast::ptr::P; @@ -11,8 +10,8 @@ use rustc_expand::base::*; use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; - use std::iter; +use thin_vec::thin_vec; // #[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 @@ -219,7 +218,7 @@ pub fn expand_test_or_bench( let mut test_const = cx.item( sp, Ident::new(item.ident.name, sp), - vec![ + thin_vec![ // #[cfg(test)] cx.attribute(attr::mk_list_item( Ident::new(sym::cfg, attr_sp), @@ -334,9 +333,9 @@ pub fn expand_test_or_bench( }); // extern crate test - let test_extern = cx.item(sp, test_id, vec![], ast::ItemKind::ExternCrate(None)); + let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); - tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); + debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); if is_stmt { vec![ diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0ebe29df9..561ca00c7 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; use smallvec::{smallvec, SmallVec}; -use tracing::debug; +use thin_vec::thin_vec; use std::{iter, mem}; @@ -187,7 +187,10 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let dc_nested = attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site)); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); - let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); + let allow_dead_code = attr::mk_attr_outer( + &self.sess.parse_sess.attr_id_generator, + allow_dead_code_item, + ); let attrs = attrs .into_iter() .filter(|attr| { @@ -298,8 +301,10 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { 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, vec![], ast::ItemKind::ExternCrate(None))); + let test_extern_stmt = ecx.stmt_item( + sp, + ecx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)), + ); // #[rustc_main] let main_meta = ecx.meta_word(sp, sym::rustc_main); @@ -333,7 +338,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let main = P(ast::Item { ident: main_id, - attrs: vec![main_attr], + attrs: thin_vec![main_attr], id: ast::DUMMY_NODE_ID, kind: main, vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml index 61da6a249..732edd661 100644 --- a/compiler/rustc_codegen_cranelift/.cirrus.yml +++ b/compiler/rustc_codegen_cranelift/.cirrus.yml @@ -22,4 +22,4 @@ task: - # Reduce amount of benchmark runs as they are slow - export COMPILE_RUNS=2 - export RUN_RUNS=2 - - ./test.sh + - ./y.rs test diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index aa556a21b..e8897e9ae 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -103,7 +103,7 @@ jobs: # Enable extra checks export CG_CLIF_ENABLE_VERIFIER=1 - ./test.sh + ./y.rs test - name: Package prebuilt cg_clif run: tar cvfJ cg_clif.tar.xz build @@ -162,14 +162,14 @@ jobs: #name: Test run: | # Enable backtraces for easier debugging - #export RUST_BACKTRACE=1 + #$Env:RUST_BACKTRACE=1 # Reduce amount of benchmark runs as they are slow - #export COMPILE_RUNS=2 - #export RUN_RUNS=2 + #$Env:COMPILE_RUNS=2 + #$Env:RUN_RUNS=2 # Enable extra checks - #export CG_CLIF_ENABLE_VERIFIER=1 + #$Env:CG_CLIF_ENABLE_VERIFIER=1 ./y.exe build diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 532049c85..edae7e471 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" [[package]] name = "ar" @@ -50,18 +50,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8" +checksum = "93945adbccc8d731503d3038814a51e8317497c9e205411820348132fa01a358" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea" +checksum = "2b482acc9d0d0d1ad3288a90a8150ee648be3dce8dc8c8669ff026f72debdc31" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", @@ -77,30 +77,30 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6" +checksum = "f9ec188d71e663192ef9048f204e410a7283b609942efc9fcc77da6d496edbb8" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2" +checksum = "3ad794b1b1c2c7bd9f7b76cfe0f084eaf7753e55d56191c3f7d89e8fa4978b99" [[package]] name = "cranelift-entity" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d" +checksum = "342da0d5056f4119d3c311c4aab2460ceb6ee6e127bb395b76dd2279a09ea7a5" [[package]] name = "cranelift-frontend" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c" +checksum = "dfff792f775b07d4d9cfe9f1c767ce755c6cbadda1bbd6db18a1c75ff9f7376a" dependencies = [ "cranelift-codegen", "log", @@ -110,15 +110,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b" +checksum = "8d51089478849f2ac8ef60a8a2d5346c8d4abfec0e45ac5b24530ef9f9499e1e" [[package]] name = "cranelift-jit" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3c5ed067f2c81577e431f3039148a9c187b33cc79e0d1731fede27d801ec56" +checksum = "095936e41720f86004b4c57ce88e6a13af28646bb3a6fb4afbebd5ae90c50029" dependencies = [ "anyhow", "cranelift-codegen", @@ -129,14 +129,14 @@ dependencies = [ "log", "region", "target-lexicon", - "winapi", + "windows-sys", ] [[package]] name = "cranelift-module" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee6784303bf9af235237a4885f7417e09a35df896d38ea969a0081064b3ede4" +checksum = "704a1aea4723d97eafe0fb7af110f6f6868b1ac95f5380bbc9adb2a3b8cf97e8" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6" +checksum = "885debe62f2078638d6585f54c9f05f5c2008f22ce5a2a9100ada785fc065dbd" dependencies = [ "cranelift-codegen", "libc", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.85.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf38b2c505db749276793116c0cb30bd096206c7810e471677a453134881881" +checksum = "aac1310cf1081ae8eca916c92cd163b977c77cab6e831fa812273c26ff921816" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", @@ -198,28 +198,22 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "indexmap", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "indexmap" version = "1.9.1" @@ -227,14 +221,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] name = "libc" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" [[package]] name = "libloading" @@ -248,9 +242,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -266,33 +260,33 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "object" -version = "0.28.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown 0.11.2", + "hashbrown", "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "regalloc2" -version = "0.2.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c" +checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" dependencies = [ "fxhash", "log", @@ -340,15 +334,15 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "smallvec" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "target-lexicon" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" [[package]] name = "version_check" @@ -358,9 +352,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" @@ -383,3 +377,46 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 61e977e3e..e7c342748 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.85.3", features = ["unwind", "all-arch"] } -cranelift-frontend = "0.85.3" -cranelift-module = "0.85.3" -cranelift-native = "0.85.3" -cranelift-jit = { version = "0.85.3", optional = true } -cranelift-object = "0.85.3" +cranelift-codegen = { version = "0.87.0", features = ["unwind", "all-arch"] } +cranelift-frontend = "0.87.0" +cranelift-module = "0.87.0" +cranelift-native = "0.87.0" +cranelift-jit = { version = "0.87.0", optional = true } +cranelift-object = "0.87.0" target-lexicon = "0.12.0" gimli = { version = "0.26.0", default-features = false, features = ["write"]} -object = { version = "0.28.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.9.1" diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 8a2db5a43..1e84c7fa3 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -52,9 +52,7 @@ configuration options. ## Not yet supported * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041)) - * On Linux there is support for invoking an external assembler for `global_asm!` and `asm!`. - `llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You - have to specify specific registers instead. + * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`. * SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work) ## License diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 7b2cdd273..6c5043bb6 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.75" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e3183e88f659a862835db8f4b67dbeed3d93e44dd4927eef78edb1c149d784" +checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca" dependencies = [ "rustc-std-workspace-core", ] @@ -69,9 +69,9 @@ version = "0.0.0" [[package]] name = "dlmalloc" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6fe28e0bf9357092740362502f5cc7955d8dc125ebda71dec72336c2e15c62e" +checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" dependencies = [ "compiler_builtins", "libc", @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "fortanix-sgx-abi" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6" +checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7668753748e445859e4e373c3d41117235d9feed578392f5a3a73efdc751ca4a" +checksum = "897cd85af6387be149f55acf168e41be176a02de7872403aaab184afc2f327e6" dependencies = [ "compiler_builtins", "libc", @@ -135,9 +135,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs b/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs new file mode 100644 index 000000000..67dbd0a38 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs @@ -0,0 +1,60 @@ +use super::build_sysroot; +use super::config; +use super::utils::spawn_and_wait; +use build_system::SysrootKind; +use std::env; +use std::path::Path; +use std::process::Command; + +pub(crate) fn run( + channel: &str, + sysroot_kind: SysrootKind, + target_dir: &Path, + cg_clif_build_dir: &Path, + host_triple: &str, + target_triple: &str, +) { + if !config::get_bool("testsuite.abi-checker") { + eprintln!("[SKIP] abi-checker"); + return; + } + + if host_triple != target_triple { + eprintln!("[SKIP] abi-checker (cross-compilation not supported)"); + return; + } + + eprintln!("Building sysroot for abi-checker"); + build_sysroot::build_sysroot( + channel, + sysroot_kind, + target_dir, + cg_clif_build_dir, + host_triple, + target_triple, + ); + + eprintln!("Running abi-checker"); + let mut abi_checker_path = env::current_dir().unwrap(); + abi_checker_path.push("abi-checker"); + env::set_current_dir(abi_checker_path.clone()).unwrap(); + + let build_dir = abi_checker_path.parent().unwrap().join("build"); + let cg_clif_dylib_path = build_dir.join(if cfg!(windows) { "bin" } else { "lib" }).join( + env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, + ); + + let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; + + let mut cmd = Command::new("cargo"); + cmd.arg("run"); + cmd.arg("--target"); + cmd.arg(target_triple); + cmd.arg("--"); + cmd.arg("--pairs"); + cmd.args(pairs); + cmd.arg("--add-rustc-codegen-backend"); + cmd.arg(format!("cgclif:{}", cg_clif_dylib_path.display())); + + spawn_and_wait(cmd); +} diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index 48faec8bc..9e59b8199 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -2,6 +2,8 @@ use std::env; use std::path::{Path, PathBuf}; use std::process::Command; +use super::utils::is_ci; + pub(crate) fn build_backend( channel: &str, host_triple: &str, @@ -14,7 +16,7 @@ pub(crate) fn build_backend( let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); - if env::var("CI").as_ref().map(|val| &**val) == Ok("true") { + if is_ci() { // Deny warnings on CI rustflags += " -Dwarnings"; diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 16cce83dd..7e205b0fd 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -2,7 +2,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use super::rustc_info::{get_file_name, get_rustc_version}; +use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name}; use super::utils::{spawn_and_wait, try_hard_link}; use super::SysrootKind; @@ -10,10 +10,12 @@ pub(crate) fn build_sysroot( channel: &str, sysroot_kind: SysrootKind, target_dir: &Path, - cg_clif_build_dir: PathBuf, + cg_clif_build_dir: &Path, host_triple: &str, target_triple: &str, ) { + eprintln!("[BUILD] sysroot {:?}", sysroot_kind); + if target_dir.exists() { fs::remove_dir_all(target_dir).unwrap(); } @@ -35,11 +37,13 @@ pub(crate) fn build_sysroot( // Build and copy rustc and cargo wrappers for wrapper in ["rustc-clif", "cargo-clif"] { + let wrapper_name = get_wrapper_file_name(wrapper, "bin"); + let mut build_cargo_wrapper_cmd = Command::new("rustc"); build_cargo_wrapper_cmd .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs"))) .arg("-o") - .arg(target_dir.join(wrapper)) + .arg(target_dir.join(wrapper_name)) .arg("-g"); spawn_and_wait(build_cargo_wrapper_cmd); } diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs index b897b7fba..c3706dc6f 100644 --- a/compiler/rustc_codegen_cranelift/build_system/mod.rs +++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs @@ -2,11 +2,15 @@ use std::env; use std::path::PathBuf; use std::process; +use self::utils::is_ci; + +mod abi_checker; mod build_backend; mod build_sysroot; mod config; mod prepare; mod rustc_info; +mod tests; mod utils; fn usage() { @@ -15,6 +19,9 @@ fn usage() { eprintln!( " ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]" ); + eprintln!( + " ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]" + ); } macro_rules! arg_error { @@ -25,11 +32,13 @@ macro_rules! arg_error { }}; } +#[derive(PartialEq, Debug)] enum Command { Build, + Test, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) enum SysrootKind { None, Clif, @@ -42,16 +51,22 @@ pub fn main() { // The target dir is expected in the default location. Guard against the user changing it. env::set_var("CARGO_TARGET_DIR", "target"); + 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"); + } + let mut args = env::args().skip(1); let command = match args.next().as_deref() { Some("prepare") => { if args.next().is_some() { - arg_error!("./x.rs prepare doesn't expect arguments"); + arg_error!("./y.rs prepare doesn't expect arguments"); } prepare::prepare(); process::exit(0); } Some("build") => Command::Build, + Some("test") => Command::Test, Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), Some(command) => arg_error!("Unknown command {}", command), None => { @@ -117,12 +132,35 @@ pub fn main() { let cg_clif_build_dir = build_backend::build_backend(channel, &host_triple, use_unstable_features); - build_sysroot::build_sysroot( - channel, - sysroot_kind, - &target_dir, - cg_clif_build_dir, - &host_triple, - &target_triple, - ); + match command { + Command::Test => { + tests::run_tests( + channel, + sysroot_kind, + &target_dir, + &cg_clif_build_dir, + &host_triple, + &target_triple, + ); + + abi_checker::run( + channel, + sysroot_kind, + &target_dir, + &cg_clif_build_dir, + &host_triple, + &target_triple, + ); + } + Command::Build => { + build_sysroot::build_sysroot( + channel, + sysroot_kind, + &target_dir, + &cg_clif_build_dir, + &host_triple, + &target_triple, + ); + } + } } diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 8bb00352d..d23b7f00d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -14,6 +14,14 @@ pub(crate) fn prepare() { eprintln!("[INSTALL] hyperfine"); Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap(); + clone_repo_shallow_github( + "abi-checker", + "Gankra", + "abi-checker", + "a2232d45f202846f5c02203c9f27355360f9a2ff", + ); + apply_patches("abi-checker", Path::new("abi-checker")); + clone_repo_shallow_github( "rand", "rust-random", @@ -50,8 +58,7 @@ pub(crate) fn prepare() { spawn_and_wait(build_cmd); fs::copy( Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")), - // FIXME use get_file_name here too once testing is migrated to rust - "simple-raytracer/raytracer_cg_llvm", + Path::new("simple-raytracer").join(get_file_name("raytracer_cg_llvm", "bin")), ) .unwrap(); } diff --git a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs index 9206bb02b..913b589af 100644 --- a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs +++ b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs @@ -63,3 +63,12 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String { assert!(file_name.contains(crate_name)); file_name } + +/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to +/// underscores (`_`). This is specially made for the the rustc and cargo wrappers +/// which have a dash in the name, and that is not allowed in a crate name. +pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String { + let crate_name = crate_name.replace('-', "_"); + let wrapper_name = get_file_name(&crate_name, crate_type); + wrapper_name.replace('_', "-") +} diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs new file mode 100644 index 000000000..e21397cec --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -0,0 +1,619 @@ +use super::build_sysroot; +use super::config; +use super::rustc_info::get_wrapper_file_name; +use super::utils::{spawn_and_wait, spawn_and_wait_with_input}; +use build_system::SysrootKind; +use std::env; +use std::ffi::OsStr; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +struct TestCase { + config: &'static str, + func: &'static dyn Fn(&TestRunner), +} + +impl TestCase { + const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self { + Self { config, func } + } +} + +const NO_SYSROOT_SUITE: &[TestCase] = &[ + TestCase::new("build.mini_core", &|runner| { + runner.run_rustc([ + "example/mini_core.rs", + "--crate-name", + "mini_core", + "--crate-type", + "lib,dylib", + "--target", + &runner.target_triple, + ]); + }), + TestCase::new("build.example", &|runner| { + runner.run_rustc([ + "example/example.rs", + "--crate-type", + "lib", + "--target", + &runner.target_triple, + ]); + }), + TestCase::new("jit.mini_core_hello_world", &|runner| { + let mut jit_cmd = runner.rustc_command([ + "-Zunstable-options", + "-Cllvm-args=mode=jit", + "-Cprefer-dynamic", + "example/mini_core_hello_world.rs", + "--cfg", + "jit", + "--target", + &runner.host_triple, + ]); + jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd"); + spawn_and_wait(jit_cmd); + + eprintln!("[JIT-lazy] mini_core_hello_world"); + let mut jit_cmd = runner.rustc_command([ + "-Zunstable-options", + "-Cllvm-args=mode=jit-lazy", + "-Cprefer-dynamic", + "example/mini_core_hello_world.rs", + "--cfg", + "jit", + "--target", + &runner.host_triple, + ]); + jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd"); + spawn_and_wait(jit_cmd); + }), + TestCase::new("aot.mini_core_hello_world", &|runner| { + runner.run_rustc([ + "example/mini_core_hello_world.rs", + "--crate-name", + "mini_core_hello_world", + "--crate-type", + "bin", + "-g", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]); + }), +]; + +const BASE_SYSROOT_SUITE: &[TestCase] = &[ + TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| { + runner.run_rustc([ + "example/arbitrary_self_types_pointers_and_wrappers.rs", + "--crate-name", + "arbitrary_self_types_pointers_and_wrappers", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []); + }), + TestCase::new("aot.issue_91827_extern_types", &|runner| { + runner.run_rustc([ + "example/issue-91827-extern-types.rs", + "--crate-name", + "issue_91827_extern_types", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("issue_91827_extern_types", []); + }), + TestCase::new("build.alloc_system", &|runner| { + runner.run_rustc([ + "example/alloc_system.rs", + "--crate-type", + "lib", + "--target", + &runner.target_triple, + ]); + }), + TestCase::new("aot.alloc_example", &|runner| { + runner.run_rustc([ + "example/alloc_example.rs", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("alloc_example", []); + }), + TestCase::new("jit.std_example", &|runner| { + runner.run_rustc([ + "-Zunstable-options", + "-Cllvm-args=mode=jit", + "-Cprefer-dynamic", + "example/std_example.rs", + "--target", + &runner.host_triple, + ]); + + eprintln!("[JIT-lazy] std_example"); + runner.run_rustc([ + "-Zunstable-options", + "-Cllvm-args=mode=jit-lazy", + "-Cprefer-dynamic", + "example/std_example.rs", + "--target", + &runner.host_triple, + ]); + }), + TestCase::new("aot.std_example", &|runner| { + runner.run_rustc([ + "example/std_example.rs", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("std_example", ["arg"]); + }), + TestCase::new("aot.dst_field_align", &|runner| { + runner.run_rustc([ + "example/dst-field-align.rs", + "--crate-name", + "dst_field_align", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("dst_field_align", []); + }), + TestCase::new("aot.subslice-patterns-const-eval", &|runner| { + runner.run_rustc([ + "example/subslice-patterns-const-eval.rs", + "--crate-type", + "bin", + "-Cpanic=abort", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("subslice-patterns-const-eval", []); + }), + TestCase::new("aot.track-caller-attribute", &|runner| { + runner.run_rustc([ + "example/track-caller-attribute.rs", + "--crate-type", + "bin", + "-Cpanic=abort", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("track-caller-attribute", []); + }), + TestCase::new("aot.float-minmax-pass", &|runner| { + runner.run_rustc([ + "example/float-minmax-pass.rs", + "--crate-type", + "bin", + "-Cpanic=abort", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("float-minmax-pass", []); + }), + TestCase::new("aot.mod_bench", &|runner| { + runner.run_rustc([ + "example/mod_bench.rs", + "--crate-type", + "bin", + "--target", + &runner.target_triple, + ]); + runner.run_out_command("mod_bench", []); + }), +]; + +const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ + TestCase::new("test.rust-random/rand", &|runner| { + runner.in_dir(["rand"], |runner| { + runner.run_cargo(["clean"]); + + if runner.host_triple == runner.target_triple { + eprintln!("[TEST] rust-random/rand"); + runner.run_cargo(["test", "--workspace"]); + } else { + eprintln!("[AOT] rust-random/rand"); + runner.run_cargo([ + "build", + "--workspace", + "--target", + &runner.target_triple, + "--tests", + ]); + } + }); + }), + TestCase::new("bench.simple-raytracer", &|runner| { + runner.in_dir(["simple-raytracer"], |runner| { + let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()); + + if runner.host_triple == runner.target_triple { + eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); + let mut bench_compile = Command::new("hyperfine"); + bench_compile.arg("--runs"); + bench_compile.arg(&run_runs); + bench_compile.arg("--warmup"); + bench_compile.arg("1"); + bench_compile.arg("--prepare"); + bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"]))); + + if cfg!(windows) { + bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\""); + } else { + bench_compile.arg("RUSTFLAGS='' cargo build"); + } + + bench_compile.arg(format!("{:?}", runner.cargo_command(["build"]))); + spawn_and_wait(bench_compile); + + eprintln!("[BENCH RUN] ebobby/simple-raytracer"); + fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif")) + .unwrap(); + + let mut bench_run = Command::new("hyperfine"); + bench_run.arg("--runs"); + bench_run.arg(&run_runs); + bench_run.arg(PathBuf::from("./raytracer_cg_llvm")); + bench_run.arg(PathBuf::from("./raytracer_cg_clif")); + spawn_and_wait(bench_run); + } else { + runner.run_cargo(["clean"]); + eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)"); + eprintln!("[COMPILE] ebobby/simple-raytracer"); + runner.run_cargo(["build", "--target", &runner.target_triple]); + eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)"); + } + }); + }), + TestCase::new("test.libcore", &|runner| { + runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| { + runner.run_cargo(["clean"]); + + if runner.host_triple == runner.target_triple { + runner.run_cargo(["test"]); + } else { + eprintln!("Cross-Compiling: Not running tests"); + runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]); + } + }); + }), + TestCase::new("test.regex-shootout-regex-dna", &|runner| { + runner.in_dir(["regex"], |runner| { + runner.run_cargo(["clean"]); + + // newer aho_corasick versions throw a deprecation warning + let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags); + + let mut build_cmd = runner.cargo_command([ + "build", + "--example", + "shootout-regex-dna", + "--target", + &runner.target_triple, + ]); + build_cmd.env("RUSTFLAGS", lint_rust_flags.clone()); + spawn_and_wait(build_cmd); + + if runner.host_triple == runner.target_triple { + let mut run_cmd = runner.cargo_command([ + "run", + "--example", + "shootout-regex-dna", + "--target", + &runner.target_triple, + ]); + run_cmd.env("RUSTFLAGS", lint_rust_flags); + + let input = + fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap(); + let expected_path = PathBuf::from("examples/regexdna-output.txt"); + let expected = fs::read_to_string(&expected_path).unwrap(); + + let output = spawn_and_wait_with_input(run_cmd, input); + // Make sure `[codegen mono items] start` doesn't poison the diff + let output = output + .lines() + .filter(|line| !line.contains("codegen mono items")) + .chain(Some("")) // This just adds the trailing newline + .collect::>() + .join("\r\n"); + + let output_matches = expected.lines().eq(output.lines()); + if !output_matches { + let res_path = PathBuf::from("res.txt"); + fs::write(&res_path, &output).unwrap(); + + if cfg!(windows) { + println!("Output files don't match!"); + println!("Expected Output:\n{}", expected); + println!("Actual Output:\n{}", output); + } else { + let mut diff = Command::new("diff"); + diff.arg("-u"); + diff.arg(res_path); + diff.arg(expected_path); + spawn_and_wait(diff); + } + + std::process::exit(1); + } + } + }); + }), + TestCase::new("test.regex", &|runner| { + runner.in_dir(["regex"], |runner| { + runner.run_cargo(["clean"]); + + // newer aho_corasick versions throw a deprecation warning + let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags); + + if runner.host_triple == runner.target_triple { + let mut run_cmd = runner.cargo_command([ + "test", + "--tests", + "--", + "--exclude-should-panic", + "--test-threads", + "1", + "-Zunstable-options", + "-q", + ]); + run_cmd.env("RUSTFLAGS", lint_rust_flags); + spawn_and_wait(run_cmd); + } else { + eprintln!("Cross-Compiling: Not running tests"); + let mut build_cmd = + runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]); + build_cmd.env("RUSTFLAGS", lint_rust_flags.clone()); + spawn_and_wait(build_cmd); + } + }); + }), + TestCase::new("test.portable-simd", &|runner| { + runner.in_dir(["portable-simd"], |runner| { + runner.run_cargo(["clean"]); + runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]); + + if runner.host_triple == runner.target_triple { + runner.run_cargo(["test", "-q"]); + } + }); + }), +]; + +pub(crate) fn run_tests( + channel: &str, + sysroot_kind: SysrootKind, + target_dir: &Path, + cg_clif_build_dir: &Path, + host_triple: &str, + target_triple: &str, +) { + let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string()); + + if config::get_bool("testsuite.no_sysroot") { + build_sysroot::build_sysroot( + channel, + SysrootKind::None, + &target_dir, + cg_clif_build_dir, + &host_triple, + &target_triple, + ); + + let _ = fs::remove_dir_all(Path::new("target").join("out")); + runner.run_testsuite(NO_SYSROOT_SUITE); + } else { + eprintln!("[SKIP] no_sysroot tests"); + } + + let run_base_sysroot = config::get_bool("testsuite.base_sysroot"); + let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot"); + + if run_base_sysroot || run_extended_sysroot { + build_sysroot::build_sysroot( + channel, + sysroot_kind, + &target_dir, + cg_clif_build_dir, + &host_triple, + &target_triple, + ); + } + + 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 { + root_dir: PathBuf, + out_dir: PathBuf, + jit_supported: bool, + rust_flags: String, + run_wrapper: Vec, + host_triple: String, + target_triple: String, +} + +impl TestRunner { + pub fn new(host_triple: String, target_triple: String) -> Self { + let root_dir = env::current_dir().unwrap(); + + let mut out_dir = root_dir.clone(); + out_dir.push("target"); + out_dir.push("out"); + + let is_native = host_triple == target_triple; + let jit_supported = + target_triple.contains("x86_64") && is_native && !host_triple.contains("windows"); + + let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string()); + let mut run_wrapper = Vec::new(); + + if !is_native { + match target_triple.as_str() { + "aarch64-unknown-linux-gnu" => { + // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags); + run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"]; + } + "x86_64-pc-windows-gnu" => { + // We are cross-compiling for Windows. Run tests in wine. + run_wrapper = vec!["wine"]; + } + _ => { + println!("Unknown non-native platform"); + } + } + } + + // FIXME fix `#[linkage = "extern_weak"]` without this + if host_triple.contains("darwin") { + rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags); + } + + Self { + root_dir, + out_dir, + jit_supported, + rust_flags, + run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(), + host_triple, + target_triple, + } + } + + pub fn run_testsuite(&self, tests: &[TestCase]) { + for &TestCase { config, func } in tests { + let (tag, testname) = config.split_once('.').unwrap(); + let tag = tag.to_uppercase(); + let is_jit_test = tag == "JIT"; + + if !config::get_bool(config) || (is_jit_test && !self.jit_supported) { + eprintln!("[{tag}] {testname} (skipped)"); + continue; + } else { + eprintln!("[{tag}] {testname}"); + } + + func(self); + } + } + + fn in_dir<'a, I, F>(&self, dir: I, callback: F) + where + I: IntoIterator, + F: FnOnce(&TestRunner), + { + let current = env::current_dir().unwrap(); + let mut new = current.clone(); + for d in dir { + new.push(d); + } + + env::set_current_dir(new).unwrap(); + callback(self); + env::set_current_dir(current).unwrap(); + } + + fn rustc_command(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut rustc_clif = self.root_dir.clone(); + rustc_clif.push("build"); + rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin")); + + let mut cmd = Command::new(rustc_clif); + cmd.args(self.rust_flags.split_whitespace()); + cmd.arg("-L"); + cmd.arg(format!("crate={}", self.out_dir.display())); + cmd.arg("--out-dir"); + cmd.arg(format!("{}", self.out_dir.display())); + cmd.arg("-Cdebuginfo=2"); + 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<'a, I>(&self, name: &str, args: I) + where + I: IntoIterator, + { + let mut full_cmd = vec![]; + + // Prepend the RUN_WRAPPER's + if !self.run_wrapper.is_empty() { + full_cmd.extend(self.run_wrapper.iter().cloned()); + } + + full_cmd.push({ + let mut out_path = self.out_dir.clone(); + out_path.push(name); + out_path.to_str().unwrap().to_string() + }); + + for arg in args.into_iter() { + 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); + } + + fn cargo_command(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut cargo_clif = self.root_dir.clone(); + cargo_clif.push("build"); + cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin")); + + let mut cmd = Command::new(cargo_clif); + cmd.args(args); + cmd.env("RUSTFLAGS", &self.rust_flags); + cmd + } + + fn run_cargo<'a, I>(&self, args: I) + where + I: IntoIterator, + { + spawn_and_wait(self.cargo_command(args)); + } +} diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index 12b5d70fa..bdf8f8ecd 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -1,6 +1,8 @@ +use std::env; use std::fs; +use std::io::Write; use std::path::Path; -use std::process::{self, Command}; +use std::process::{self, Command, Stdio}; #[track_caller] pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { @@ -18,6 +20,27 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { } } +#[track_caller] +pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String { + let mut child = cmd + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to spawn child process"); + + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + std::thread::spawn(move || { + stdin.write_all(input.as_bytes()).expect("Failed to write to stdin"); + }); + + let output = child.wait_with_output().expect("Failed to read stdout"); + if !output.status.success() { + process::exit(1); + } + + String::from_utf8(output.stdout).unwrap() +} + pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { for entry in fs::read_dir(from).unwrap() { let entry = entry.unwrap(); @@ -33,3 +56,7 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { } } } + +pub(crate) fn is_ci() -> bool { + env::var("CI").as_ref().map(|val| &**val) == Ok("true") +} diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index ea1f8c1e8..62e52bd19 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -3,4 +3,4 @@ set -e rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} rm -rf target/ build/ perf.data{,.old} y.bin -rm -rf rand/ regex/ simple-raytracer/ portable-simd/ +rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt index b14db27d6..2264d301d 100644 --- a/compiler/rustc_codegen_cranelift/config.txt +++ b/compiler/rustc_codegen_cranelift/config.txt @@ -15,3 +15,38 @@ # This option can be changed while the build system is already running for as long as sysroot # building hasn't started yet. #keep_sysroot + + +# Testsuite +# +# Each test suite item has a corresponding key here. The default is to run all tests. +# Comment any of these lines to skip individual tests. + +testsuite.no_sysroot +build.mini_core +build.example +jit.mini_core_hello_world +aot.mini_core_hello_world + +testsuite.base_sysroot +aot.arbitrary_self_types_pointers_and_wrappers +aot.issue_91827_extern_types +build.alloc_system +aot.alloc_example +jit.std_example +aot.std_example +aot.dst_field_align +aot.subslice-patterns-const-eval +aot.track-caller-attribute +aot.float-minmax-pass +aot.mod_bench + +testsuite.extended_sysroot +test.rust-random/rand +bench.simple-raytracer +test.libcore +test.regex-shootout-regex-dna +test.regex +test.portable-simd + +testsuite.abi-checker diff --git a/compiler/rustc_codegen_cranelift/example/alloc_system.rs b/compiler/rustc_codegen_cranelift/example/alloc_system.rs index cf95c89bc..50261c193 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_system.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_system.rs @@ -94,7 +94,7 @@ mod platform { 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).offset(-1) + &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))); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 8b6042a3d..42f8aa50b 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -535,7 +535,7 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { } #[lang = "box_free"] -unsafe fn box_free(ptr: Unique, alloc: ()) { +unsafe fn box_free(ptr: Unique, _alloc: ()) { libc::free(ptr.pointer.0 as *mut u8); } @@ -575,11 +575,19 @@ pub mod intrinsics { } pub mod libc { + // With the new Universal CRT, msvc has switched to all the printf functions being inline wrapper + // functions. legacy_stdio_definitions.lib which provides the printf wrapper functions as normal + // symbols to link against. + #[cfg_attr(unix, link(name = "c"))] + #[cfg_attr(target_env="msvc", link(name="legacy_stdio_definitions"))] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } + #[cfg_attr(unix, link(name = "c"))] #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] extern "C" { pub fn puts(s: *const i8) -> i32; - pub fn printf(format: *const i8, ...) -> i32; pub fn malloc(size: usize) -> *mut u8; pub fn free(ptr: *mut u8); pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index aa1f239ba..e83be3a3d 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -139,7 +139,7 @@ pub struct bool_11 { field10: bool, } -extern "C" fn bool_struct_in_11(arg0: bool_11) {} +extern "C" fn bool_struct_in_11(_arg0: bool_11) {} #[allow(unreachable_code)] // FIXME false positive fn main() { @@ -321,7 +321,7 @@ fn main() { #[cfg(not(any(jit, windows)))] test_tls(); - #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))] + #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))] unsafe { global_asm_test(); } @@ -343,7 +343,7 @@ fn main() { } } -#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))] +#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))] extern "C" { fn global_asm_test(); } @@ -358,6 +358,16 @@ global_asm! { " } +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "darwin"))] +global_asm! { + " + .global _global_asm_test + _global_asm_test: + // comment that would normally be removed by LLVM + ret + " +} + #[repr(C)] enum c_void { _1, @@ -375,6 +385,7 @@ struct pthread_attr_t { } #[link(name = "pthread")] +#[cfg(unix)] extern "C" { fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; @@ -391,6 +402,91 @@ extern "C" { ) -> c_int; } +type DWORD = u32; +type LPDWORD = *mut u32; + +type LPVOID = *mut c_void; +type HANDLE = *mut c_void; + +#[link(name = "msvcrt")] +#[cfg(windows)] +extern "C" { + fn WaitForSingleObject( + hHandle: LPVOID, + dwMilliseconds: DWORD + ) -> DWORD; + + fn CreateThread( + lpThreadAttributes: LPVOID, // Technically LPSECURITY_ATTRIBUTES, but we don't use it anyway + dwStackSize: usize, + lpStartAddress: extern "C" fn(_: *mut c_void) -> *mut c_void, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpThreadId: LPDWORD + ) -> HANDLE; +} + +struct Thread { + #[cfg(windows)] + handle: HANDLE, + #[cfg(unix)] + handle: pthread_t, +} + +impl Thread { + unsafe fn create(f: extern "C" fn(_: *mut c_void) -> *mut c_void) -> Self { + #[cfg(unix)] + { + let mut attr: pthread_attr_t = zeroed(); + let mut thread: pthread_t = 0; + + if pthread_attr_init(&mut attr) != 0 { + assert!(false); + } + + if pthread_create(&mut thread, &attr, f, 0 as *mut c_void) != 0 { + assert!(false); + } + + Thread { + handle: thread, + } + } + + #[cfg(windows)] + { + let handle = CreateThread(0 as *mut c_void, 0, f, 0 as *mut c_void, 0, 0 as *mut u32); + + if (handle as u64) == 0 { + assert!(false); + } + + Thread { + handle, + } + } + } + + + unsafe fn join(self) { + #[cfg(unix)] + { + let mut res = 0 as *mut c_void; + pthread_join(self.handle, &mut res); + } + + #[cfg(windows)] + { + // The INFINITE macro is used to signal operations that do not timeout. + let infinite = 0xffffffff; + assert!(WaitForSingleObject(self.handle, infinite) == 0); + } + } +} + + + + #[thread_local] #[cfg(not(jit))] static mut TLS: u8 = 42; @@ -404,21 +500,10 @@ extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void { #[cfg(not(jit))] fn test_tls() { unsafe { - let mut attr: pthread_attr_t = zeroed(); - let mut thread: pthread_t = 0; - assert_eq!(TLS, 42); - if pthread_attr_init(&mut attr) != 0 { - assert!(false); - } - - if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 { - assert!(false); - } - - let mut res = 0 as *mut c_void; - pthread_join(thread, &mut res); + let thread = Thread::create(mutate_tls); + thread.join(); // TLS of main thread must not have been changed by the other thread. assert_eq!(TLS, 42); diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch new file mode 100644 index 000000000..526366a75 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch @@ -0,0 +1,36 @@ +From 1a315ba225577dbbd1f449d9609f16f984f68708 Mon Sep 17 00:00:00 2001 +From: Afonso Bordado +Date: Fri, 12 Aug 2022 22:51:58 +0000 +Subject: [PATCH] Disable abi-checker tests + +--- + src/report.rs | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/report.rs b/src/report.rs +index 7346f5e..8347762 100644 +--- a/src/report.rs ++++ b/src/report.rs +@@ -45,6 +45,20 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl + // + // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES + ++ // Currently MSVC has some broken ABI issues. Furthermore, they cause ++ // a STATUS_ACCESS_VIOLATION, so we can't even run them. Ensure that they compile and link. ++ if cfg!(windows) && (test.test_name == "bool" || test.test_name == "ui128") { ++ result.run = Link; ++ result.check = Pass(Link); ++ } ++ ++ // structs is broken in the current release of cranelift for aarch64. ++ // It has been fixed for cranelift 0.88: https://github.com/bytecodealliance/wasmtime/pull/4634 ++ if cfg!(target_arch = "aarch64") && test.test_name == "structs" { ++ result.run = Link; ++ result.check = Pass(Link); ++ } ++ + // END OF VENDOR RESERVED AREA + // + // +-- +2.34.1 diff --git a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch index 50ef0bd94..f3cd7ee77 100644 --- a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch @@ -46,5 +46,17 @@ index 4bc44e9..8e3c7a4 100644 #[test] fn cell_allows_array_cycle() { +diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs +index 13b12db..96fe4b9 100644 +--- a/library/core/tests/atomic.rs ++++ b/library/core/tests/atomic.rs +@@ -185,6 +185,7 @@ fn ptr_bitops() { + } + + #[test] ++#[cfg_attr(target_arch = "s390x", ignore)] // s390x backend doesn't support stack alignment >8 bytes + #[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins + fn ptr_bitops_tagging() { + #[repr(align(16))] -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 3ab395d89..14f2746ec 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-25" +channel = "nightly-2022-08-24" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh deleted file mode 100755 index 9b5ffa409..000000000 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env bash - -set -e - -export CG_CLIF_DISPLAY_CG_TIME=1 -export CG_CLIF_DISABLE_INCR_CACHE=1 - -export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") -export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE} - -export RUN_WRAPPER='' - -case "$TARGET_TRIPLE" in - x86_64*) - export JIT_SUPPORTED=1 - ;; - *) - export JIT_SUPPORTED=0 - ;; -esac - -if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then - export JIT_SUPPORTED=0 - if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then - # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS - export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' - elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then - # We are cross-compiling for Windows. Run tests in wine. - export RUN_WRAPPER='wine' - else - echo "Unknown non-native platform" - fi -fi - -# FIXME fix `#[linkage = "extern_weak"]` without this -if [[ "$(uname)" == 'Darwin' ]]; then - export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" -fi - -MY_RUSTC="$(pwd)/build/rustc-clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2" - -function no_sysroot_tests() { - echo "[BUILD] mini_core" - $MY_RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target "$TARGET_TRIPLE" - - echo "[BUILD] example" - $MY_RUSTC example/example.rs --crate-type lib --target "$TARGET_TRIPLE" - - if [[ "$JIT_SUPPORTED" = "1" ]]; then - echo "[JIT] mini_core_hello_world" - CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE" - - echo "[JIT-lazy] mini_core_hello_world" - CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE" - else - echo "[JIT] mini_core_hello_world (skipped)" - fi - - echo "[AOT] mini_core_hello_world" - $MY_RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd - # (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd -} - -function base_sysroot_tests() { - echo "[AOT] arbitrary_self_types_pointers_and_wrappers" - $MY_RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers - - echo "[AOT] issue_91827_extern_types" - $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/issue_91827_extern_types - - echo "[BUILD] alloc_system" - $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE" - - echo "[AOT] alloc_example" - $MY_RUSTC example/alloc_example.rs --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/alloc_example - - if [[ "$JIT_SUPPORTED" = "1" ]]; then - echo "[JIT] std_example" - $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE" - - echo "[JIT-lazy] std_example" - $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE" - else - echo "[JIT] std_example (skipped)" - fi - - echo "[AOT] std_example" - $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/std_example arg - - echo "[AOT] dst_field_align" - $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/dst_field_align - - echo "[AOT] subslice-patterns-const-eval" - $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/subslice-patterns-const-eval - - echo "[AOT] track-caller-attribute" - $MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/track-caller-attribute - - echo "[AOT] float-minmax-pass" - $MY_RUSTC example/float-minmax-pass.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/float-minmax-pass - - echo "[AOT] mod_bench" - $MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/mod_bench -} - -function extended_sysroot_tests() { - pushd rand - ../build/cargo-clif clean - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - echo "[TEST] rust-random/rand" - ../build/cargo-clif test --workspace - else - echo "[AOT] rust-random/rand" - ../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests - fi - popd - - pushd simple-raytracer - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - echo "[BENCH COMPILE] ebobby/simple-raytracer" - hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \ - "RUSTFLAGS='' cargo build" \ - "../build/cargo-clif build" - - echo "[BENCH RUN] ebobby/simple-raytracer" - cp ./target/debug/main ./raytracer_cg_clif - hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif - else - ../build/cargo-clif clean - echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" - echo "[COMPILE] ebobby/simple-raytracer" - ../build/cargo-clif build --target $TARGET_TRIPLE - echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" - fi - popd - - pushd build_sysroot/sysroot_src/library/core/tests - echo "[TEST] libcore" - ../../../../../build/cargo-clif clean - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../../../../../build/cargo-clif test - else - ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests - fi - popd - - pushd regex - echo "[TEST] rust-lang/regex example shootout-regex-dna" - ../build/cargo-clif clean - export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning - # Make sure `[codegen mono items] start` doesn't poison the diff - ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - cat examples/regexdna-input.txt \ - | ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \ - | grep -v "Spawned thread" > res.txt - diff -u res.txt examples/regexdna-output.txt - fi - - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - echo "[TEST] rust-lang/regex tests" - ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q - else - echo "[AOT] rust-lang/regex tests" - ../build/cargo-clif build --tests --target $TARGET_TRIPLE - fi - popd - - pushd portable-simd - echo "[TEST] rust-lang/portable-simd" - ../build/cargo-clif clean - ../build/cargo-clif build --all-targets --target $TARGET_TRIPLE - if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../build/cargo-clif test -q - fi - popd -} - -case "$1" in - "no_sysroot") - no_sysroot_tests - ;; - "base_sysroot") - base_sysroot_tests - ;; - "extended_sysroot") - extended_sysroot_tests - ;; - *) - echo "unknown test suite" - ;; -esac diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 37d2679c1..7f4619b5c 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -24,7 +24,7 @@ pub(super) fn add_arg_comment<'tcx>( local: Option, local_field: Option, params: &[Value], - arg_abi_mode: PassMode, + arg_abi_mode: &PassMode, arg_layout: TyAndLayout<'tcx>, ) { if !fx.clif_comments.enabled() { diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 815450f68..0497c2570 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -342,7 +342,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let ret_place = codegen_place(fx, destination); - // Handle special calls like instrinsics and empty drop glue. + // Handle special calls like intrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs) .unwrap() diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 6c10baa53..96e25d3a8 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -23,7 +23,7 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { (RegKind::Integer, 9..=16) => types::I128, (RegKind::Float, 4) => types::F32, (RegKind::Float, 8) => types::F64, - (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(), + (RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(), _ => unreachable!("{:?}", reg), }; AbiParam::new(clif_ty) @@ -38,7 +38,7 @@ fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) - param } -fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> { +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 { @@ -100,7 +100,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Cast(cast) => cast_target_to_abi_params(cast), + PassMode::Cast(ref cast, pad_i32) => { + assert!(!pad_i32, "padding support not yet implemented"); + cast_target_to_abi_params(cast) + } PassMode::Indirect { attrs, extra_attrs: None, on_stack } => { if on_stack { // Abi requires aligning struct size to pointer size @@ -145,7 +148,9 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()), + PassMode::Cast(ref cast, _) => { + (None, cast_target_to_abi_params(cast).into_iter().collect()) + } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => { assert!(!on_stack); (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) @@ -160,7 +165,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { pub(super) fn to_casted_value<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, arg: CValue<'tcx>, - cast: CastTarget, + cast: &CastTarget, ) -> SmallVec<[Value; 2]> { let (ptr, meta) = arg.force_stack(fx); assert!(meta.is_none()); @@ -179,12 +184,12 @@ pub(super) fn from_casted_value<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, block_params: &[Value], layout: TyAndLayout<'tcx>, - cast: CastTarget, + 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 stack_slot = fx.bcx.create_stack_slot(StackSlotData { + let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to // specify stack slot alignment. @@ -193,7 +198,7 @@ pub(super) fn from_casted_value<'tcx>( // larger alignment than the integer. size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16, }); - let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0)); + let ptr = Pointer::stack_slot(stack_slot); let mut offset = 0; let mut block_params_iter = block_params.iter().copied(); for param in abi_params { @@ -224,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>( let (a, b) = arg.load_scalar_pair(fx); smallvec![a, b] } - PassMode::Cast(cast) => to_casted_value(fx, arg, cast), + PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast), PassMode::Indirect { .. } => { if is_owned { match arg.force_stack(fx) { @@ -268,7 +273,7 @@ pub(super) fn cvalue_for_param<'tcx>( local, local_field, &block_params, - arg_abi.mode, + &arg_abi.mode, arg_abi.layout, ); @@ -282,7 +287,9 @@ pub(super) fn cvalue_for_param<'tcx>( assert_eq!(block_params.len(), 2, "{:?}", block_params); Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) } - PassMode::Cast(cast) => Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)), + PassMode::Cast(ref cast, _) => { + Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) + } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { assert_eq!(block_params.len(), 1, "{:?}", block_params); Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)) diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index ff3bb2dfd..aaa141876 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>( block_params_iter: &mut impl Iterator, ) -> CPlace<'tcx> { let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { - PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => { + PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => { let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa; ( super::make_local_place( @@ -44,7 +44,7 @@ pub(super) fn codegen_return_param<'tcx>( Some(RETURN_PLACE), None, &ret_param, - fx.fn_abi.as_ref().unwrap().ret.mode, + &fx.fn_abi.as_ref().unwrap().ret.mode, fx.fn_abi.as_ref().unwrap().ret.layout, ); @@ -75,7 +75,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } - PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None), + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None), }; let call_inst = f(fx, return_ptr); @@ -92,7 +92,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ret_place .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); } - PassMode::Cast(cast) => { + PassMode::Cast(ref cast, _) => { let results = fx.bcx.inst_results(call_inst).iter().copied().collect::>(); let result = @@ -131,7 +131,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { 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(cast) => { + 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); diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index 35b89358b..0cbb9f3ec 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -26,7 +26,7 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec { }) .collect::>(); - for bb in fx.mir.basic_blocks().iter() { + 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 { diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index b4c790961..fb5313f17 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &Path, + _is_direct_dependency: bool, ) -> PathBuf { bug!("creating dll imports is not supported"); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 122e103ff..399474d79 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -6,21 +6,43 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use indexmap::IndexSet; - use crate::constant::ConstantCx; +use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; use crate::pretty_clif::CommentWriter; -pub(crate) fn codegen_fn<'tcx>( - cx: &mut crate::CodegenCx<'tcx>, +pub(crate) struct CodegenedFunction { + symbol_name: String, + func_id: FuncId, + func: Function, + clif_comments: CommentWriter, + func_debug_cx: Option, +} + +#[cfg_attr(not(feature = "jit"), allow(dead_code))] +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>, ) { - let tcx = cx.tcx; - 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 = codegen_fn(tcx, cx, cached_func, module, instance); + + compile_fn(cx, cached_context, module, codegened_func); +} + +pub(crate) fn codegen_fn<'tcx>( + tcx: TyCtxt<'tcx>, + cx: &mut crate::CodegenCx, + cached_func: Function, + module: &mut dyn Module, + instance: Instance<'tcx>, +) -> CodegenedFunction { debug_assert!(!instance.substs.needs_infer()); let mir = tcx.instance_mir(instance.def); @@ -34,15 +56,14 @@ pub(crate) fn codegen_fn<'tcx>( }); // Declare function - let symbol_name = tcx.symbol_name(instance); + let symbol_name = tcx.symbol_name(instance).name.to_string(); let sig = get_function_sig(tcx, module.isa().triple(), instance); - let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap(); - - cx.cached_context.clear(); + let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap(); // Make the FunctionBuilder let mut func_ctx = FunctionBuilderContext::new(); - let mut func = std::mem::replace(&mut cx.cached_context.func, Function::new()); + let mut func = cached_func; + func.clear(); func.name = ExternalName::user(0, func_id.as_u32()); func.signature = sig; func.collect_debug_info(); @@ -52,13 +73,19 @@ pub(crate) fn codegen_fn<'tcx>( // Predefine blocks let start_block = bcx.create_block(); let block_map: IndexVec = - (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect(); + (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 func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { + Some(debug_context.define_function(tcx, &symbol_name, mir.span)) + } else { + None + }; + let mut fx = FunctionCx { cx, module, @@ -66,6 +93,7 @@ pub(crate) fn codegen_fn<'tcx>( target_config, pointer_type, constants_cx: ConstantCx::new(), + func_debug_cx, instance, symbol_name, @@ -78,81 +106,48 @@ pub(crate) fn codegen_fn<'tcx>( caller_location: None, // set by `codegen_fn_prelude` clif_comments, - source_info_set: indexmap::IndexSet::new(), + last_source_file: None, next_ssa_var: 0, }; - let arg_uninhabited = fx - .mir - .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); - - if !crate::constant::check_constants(&mut fx) { - fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); - fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); - crate::trap::trap_unreachable(&mut fx, "compilation should have been aborted"); - } else 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); - } else { - tcx.sess.time("codegen clif ir", || { - tcx.sess - .time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block)); - codegen_fn_content(&mut fx); - }); - } + tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block)); // Recover all necessary data from fx, before accessing func will prevent future access to it. - let instance = fx.instance; + let symbol_name = fx.symbol_name; let clif_comments = fx.clif_comments; - let source_info_set = fx.source_info_set; - let local_map = fx.local_map; + let func_debug_cx = fx.func_debug_cx; fx.constants_cx.finalize(fx.tcx, &mut *fx.module); - crate::pretty_clif::write_clif_file( - tcx, - "unopt", - module.isa(), - instance, - &func, - &clif_comments, - ); + 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); - compile_fn( - cx, - module, - instance, - symbol_name.name, - func_id, - func, - clif_comments, - source_info_set, - local_map, - ); + CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx } } -fn compile_fn<'tcx>( - cx: &mut crate::CodegenCx<'tcx>, +pub(crate) fn compile_fn( + cx: &mut crate::CodegenCx, + cached_context: &mut Context, module: &mut dyn Module, - instance: Instance<'tcx>, - symbol_name: &str, - func_id: FuncId, - func: Function, - mut clif_comments: CommentWriter, - source_info_set: IndexSet, - local_map: IndexVec>, + codegened_func: CodegenedFunction, ) { - let tcx = cx.tcx; + let clif_comments = codegened_func.clif_comments; // Store function in context - let context = &mut cx.cached_context; + let context = cached_context; context.clear(); - context.func = func; + context.func = codegened_func.func; // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128` // instruction, which doesn't have an encoding. @@ -164,17 +159,6 @@ fn compile_fn<'tcx>( // invalidate it when it would change. context.domtree.clear(); - // Perform rust specific optimizations - tcx.sess.time("optimize clif ir", || { - crate::optimize::optimize_function( - tcx, - module.isa(), - instance, - context, - &mut clif_comments, - ); - }); - #[cfg(any())] // This is never true let _clif_guard = { use std::fmt::Write; @@ -203,46 +187,44 @@ fn compile_fn<'tcx>( }; // Define function - tcx.sess.time("define function", || { - context.want_disasm = crate::pretty_clif::should_write_ir(tcx); - module.define_function(func_id, context).unwrap(); + cx.profiler.verbose_generic_activity("define function").run(|| { + context.want_disasm = cx.should_write_ir; + module.define_function(codegened_func.func_id, context).unwrap(); }); - // Write optimized function to file for debugging - crate::pretty_clif::write_clif_file( - tcx, - "opt", - module.isa(), - instance, - &context.func, - &clif_comments, - ); + 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.mach_compile_result.as_ref().unwrap().disasm { - crate::pretty_clif::write_ir_file( - tcx, - || format!("{}.vcode", tcx.symbol_name(instance).name), - |file| file.write_all(disasm.as_bytes()), - ) + if let Some(disasm) = &context.compiled_code().unwrap().disasm { + 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; - tcx.sess.time("generate debug info", || { + cx.profiler.verbose_generic_activity("generate debug info").run(|| { if let Some(debug_context) = debug_context { - debug_context.define_function( - instance, - func_id, - symbol_name, - isa, + codegened_func.func_debug_cx.unwrap().finalize( + debug_context, + codegened_func.func_id, context, - &source_info_set, - local_map, ); } - unwind_context.add_function(func_id, &context, isa); + unwind_context.add_function(codegened_func.func_id, &context, isa); }); } @@ -268,8 +250,28 @@ pub(crate) fn verify_func( }); } -fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { - for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() { +fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { + if !crate::constant::check_constants(fx) { + fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); + fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); + // compilation should have been aborted + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + return; + } + + 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.sess.time("codegen prelude", || 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); @@ -457,17 +459,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { template, operands, *options, + *destination, ); - - match *destination { - Some(destination) => { - let destination_block = fx.get_block(destination); - fx.bcx.ins().jump(destination_block, &[]); - } - None => { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } - } } TerminatorKind::Resume | TerminatorKind::Abort => { // FIXME implement unwinding @@ -708,12 +701,14 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); - let discr = - crate::discriminant::codegen_get_discriminant(fx, value, dest_layout); - lval.write_cvalue(fx, discr); + crate::discriminant::codegen_get_discriminant(fx, lval, value, dest_layout); } Rvalue::Repeat(ref operand, times) => { let operand = codegen_operand(fx, operand); @@ -803,20 +798,31 @@ fn codegen_stmt<'tcx>( | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), - StatementKind::CopyNonOverlapping(inner) => { - let dst = codegen_operand(fx, &inner.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, &inner.src).load_scalar(fx); - let count = codegen_operand(fx, &inner.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); - } + 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); + } + }, } } @@ -934,8 +940,11 @@ pub(crate) fn codegen_panic_inner<'tcx>( args: &[Value], span: Span, ) { - let def_id = - fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s)); + let def_id = fx + .tcx + .lang_items() + .require(lang_item) + .unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string())); let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); let symbol_name = fx.tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index f9dc1b516..589594465 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,14 +1,18 @@ use cranelift_codegen::isa::TargetFrontendConfig; +use gimli::write::FileId; + +use rustc_data_structures::sync::Lrc; use rustc_index::vec::IndexVec; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; -use rustc_middle::ty::SymbolName; +use rustc_span::SourceFile; 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 { @@ -74,7 +78,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option unreachable!(), }; - match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) { + match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) { // Cranelift currently only implements icmp for 128bit vectors. Some(vector_ty) if vector_ty.bits() == 128 => vector_ty, _ => return None, @@ -232,15 +236,16 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool { } pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { - pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>, + 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: SymbolName<'tcx>, + pub(crate) symbol_name: String, pub(crate) mir: &'tcx Body<'tcx>, pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>, @@ -252,7 +257,11 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) caller_location: Option>, pub(crate) clif_comments: crate::pretty_clif::CommentWriter, - pub(crate) source_info_set: indexmap::IndexSet, + + /// Last accessed source file and it's debuginfo file id. + /// + /// For optimization purposes only + pub(crate) last_source_file: Option<(Lrc, FileId)>, /// This should only be accessed by `CPlace::new_var`. pub(crate) next_ssa_var: u32, @@ -336,8 +345,31 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { } pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { - let (index, _) = self.source_info_set.insert_full(source_info); - self.bcx.set_srcloc(SourceLoc::new(index as u32)); + if let Some(debug_context) = &mut self.cx.debug_context { + let (file, line, column) = + DebugContext::get_span_loc(self.tcx, self.mir.span, source_info.span); + + // add_source_file is very slow. + // Optimize for the common case of the current file not being changed. + let mut cached_file_id = None; + if let Some((ref last_source_file, last_file_id)) = self.last_source_file { + // If the allocations are not equal, the files may still be equal, but that + // doesn't matter, as this is just an optimization. + if rustc_data_structures::sync::Lrc::ptr_eq(last_source_file, &file) { + cached_file_id = Some(last_file_id); + } + } + + let file_id = if let Some(file_id) = cached_file_id { + file_id + } else { + debug_context.add_source_file(&file) + }; + + let source_loc = + self.func_debug_cx.as_mut().unwrap().add_dbg_loc(file_id, line, column); + self.bcx.set_srcloc(source_loc); + } } // Note: must be kept in sync with get_caller_location from cg_ssa diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs new file mode 100644 index 000000000..dfde97920 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -0,0 +1,168 @@ +use std::sync::{Arc, Condvar, Mutex}; + +use rustc_session::Session; + +use jobserver::HelperThread; + +// FIXME don't panic when a worker thread panics + +pub(super) struct ConcurrencyLimiter { + helper_thread: Option, + state: Arc>, + available_token_condvar: Arc, +} + +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(); + state.add_new_token(token.unwrap()); + available_token_condvar_helper.notify_one(); + }) + .unwrap(); + ConcurrencyLimiter { + helper_thread: Some(helper_thread), + state, + available_token_condvar: Arc::new(Condvar::new()), + } + } + + pub(super) fn acquire(&mut self) -> ConcurrencyLimiterToken { + let mut state = self.state.lock().unwrap(); + loop { + state.assert_invariants(); + + if state.try_start_job() { + return ConcurrencyLimiterToken { + state: self.state.clone(), + available_token_condvar: self.available_token_condvar.clone(), + }; + } + + 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(); + } +} + +impl Drop for ConcurrencyLimiter { + fn drop(&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(); + } +} + +#[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, + + // 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, 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) -> bool { + if self.active_jobs < self.tokens.len() { + // Using existing token + self.job_started(); + return true; + } + + 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(); + } + + 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(); + } + } +} diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 7f7fd0e9c..6b4ed9b9d 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -41,36 +41,30 @@ impl ConstantCx { pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { let mut all_constants_ok = true; for constant in &fx.mir.required_consts { - let const_ = match fx.monomorphize(constant.literal) { - ConstantKind::Ty(ct) => ct, + let unevaluated = match fx.monomorphize(constant.literal) { + ConstantKind::Ty(ct) => match ct.kind() { + ConstKind::Unevaluated(uv) => uv.expand(), + ConstKind::Value(_) => continue, + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(_, _) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => unreachable!("{:?}", ct), + }, + ConstantKind::Unevaluated(uv, _) => uv, ConstantKind::Val(..) => continue, }; - match const_.kind() { - ConstKind::Value(_) => {} - ConstKind::Unevaluated(unevaluated) => { - if let Err(err) = - fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) - { - all_constants_ok = false; - match err { - ErrorHandled::Reported(_) | ErrorHandled::Linted => { - fx.tcx.sess.span_err(constant.span, "erroneous constant encountered"); - } - ErrorHandled::TooGeneric => { - span_bug!( - constant.span, - "codgen encountered polymorphic constant: {:?}", - err - ); - } - } + + if let Err(err) = fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { + all_constants_ok = false; + match err { + ErrorHandled::Reported(_) | ErrorHandled::Linted => { + fx.tcx.sess.span_err(constant.span, "erroneous constant encountered"); + } + ErrorHandled::TooGeneric => { + span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err); } } - ConstKind::Param(_) - | ConstKind::Infer(_) - | ConstKind::Bound(_, _) - | ConstKind::Placeholder(_) - | ConstKind::Error(_) => unreachable!("{:?}", const_), } } all_constants_ok @@ -122,36 +116,28 @@ pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let const_ = match fx.monomorphize(constant.literal) { - ConstantKind::Ty(ct) => ct, - ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), - }; - let const_val = match const_.kind() { - ConstKind::Value(valtree) => fx.tcx.valtree_to_const_val((const_.ty(), valtree)), - ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) + let (const_val, ty) = match fx.monomorphize(constant.literal) { + ConstantKind::Ty(const_) => unreachable!("{:?}", const_), + ConstantKind::Unevaluated(ty::Unevaluated { def, substs, promoted }, ty) if fx.tcx.is_static(def.did) => { assert!(substs.is_empty()); assert!(promoted.is_none()); - return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty())).to_cvalue(fx); + return codegen_static_ref(fx, def.did, fx.layout_of(ty)).to_cvalue(fx); } - ConstKind::Unevaluated(unevaluated) => { + ConstantKind::Unevaluated(unevaluated, ty) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { - Ok(const_val) => const_val, + Ok(const_val) => (const_val, ty), Err(_) => { span_bug!(constant.span, "erroneous constant not captured by required_consts"); } } } - ConstKind::Param(_) - | ConstKind::Infer(_) - | ConstKind::Bound(_, _) - | ConstKind::Placeholder(_) - | ConstKind::Error(_) => unreachable!("{:?}", const_), + ConstantKind::Val(val, ty) => (val, ty), }; - codegen_const_value(fx, const_val, const_.ty()) + codegen_const_value(fx, const_val, ty) } pub(crate) fn codegen_const_value<'tcx>( @@ -430,7 +416,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); data_ctx.define(bytes.into_boxed_slice()); - for &(offset, alloc_id) in alloc.relocations().iter() { + for &(offset, alloc_id) in alloc.provenance().iter() { let addend = { let endianness = tcx.data_layout.endian; let offset = offset.bytes() as usize; @@ -496,6 +482,9 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( .eval_for_mir(fx.tcx, ParamEnv::reveal_all()) .try_to_value(fx.tcx), ConstantKind::Val(val, _) => Some(val), + ConstantKind::Unevaluated(uv, _) => { + fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).ok() + } }, // 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. @@ -505,7 +494,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( return None; } let mut computed_const_val = None; - for bb_data in fx.mir.basic_blocks() { + 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 => { @@ -536,9 +525,11 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( { return None; } - StatementKind::CopyNonOverlapping(_) => { - return None; - } // conservative handling + StatementKind::Intrinsic(ref intrinsic) => match **intrinsic { + NonDivergingIntrinsic::CopyNonOverlapping(..) => return None, + NonDivergingIntrinsic::Assume(..) => {} + }, + // conservative handling StatementKind::Assign(_) | StatementKind::FakeRead(_) | StatementKind::SetDiscriminant { .. } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 589910ede..9583cd2ec 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -9,7 +9,7 @@ use gimli::{RunTimeEndian, SectionId}; use super::object::WriteDebugInfo; use super::DebugContext; -impl DebugContext<'_> { +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(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index bbcb95913..463de6a91 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -3,8 +3,10 @@ use std::ffi::OsStr; use std::path::{Component, Path}; +use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; +use rustc_data_structures::sync::Lrc; use rustc_span::{ FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, }; @@ -14,7 +16,6 @@ use cranelift_codegen::MachSrcLoc; use gimli::write::{ Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable, - UnitEntryId, }; // OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`. @@ -47,9 +48,9 @@ fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] { } } -pub(crate) const MD5_LEN: usize = 16; +const MD5_LEN: usize = 16; -pub(crate) fn make_file_info(hash: SourceFileHash) -> Option { +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()); @@ -59,160 +60,132 @@ pub(crate) fn make_file_info(hash: SourceFileHash) -> Option { } } -fn line_program_add_file( - line_program: &mut LineProgram, - line_strings: &mut LineStringTable, - file: &SourceFile, -) -> FileId { - match &file.name { - FileName::Real(path) => { - let (dir_path, file_name) = split_path_dir_and_file(path.remapped_path_if_available()); - 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); +impl DebugContext { + pub(crate) fn get_span_loc( + tcx: TyCtxt<'_>, + function_span: Span, + span: Span, + ) -> (Lrc, 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 = if tcx.should_collapse_debuginfo(span) { + span + } else { + // 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. + rustc_span::hygiene::walk_chain(span, function_span.ctxt()) + }; - let info = make_file_info(file.src_hash); + match tcx.sess.source_map().lookup_line(span.lo()) { + Ok(SourceFileAndLine { sf: file, line }) => { + let line_pos = file.line_begin_pos(span.lo()); - line_program.file_has_md5 &= info.is_some(); - line_program.add_file(file_name, dir_id, info) + ( + file, + u64::try_from(line).unwrap() + 1, + u64::from((span.lo() - line_pos).to_u32()) + 1, + ) + } + Err(file) => (file, 0, 0), } - // FIXME give more appropriate file names - filename => { - let dir_id = line_program.default_directory(); - let dummy_file_name = LineString::new( - filename.prefer_remapped().to_string().into_bytes(), - line_program.encoding(), - line_strings, - ); - line_program.add_file(dummy_file_name, dir_id, None) + } + + pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { + 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.remapped_path_if_available()); + 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) + } + // FIXME give more appropriate file names + filename => { + let dir_id = line_program.default_directory(); + let dummy_file_name = LineString::new( + filename.prefer_remapped().to_string().into_bytes(), + line_program.encoding(), + line_strings, + ); + line_program.add_file(dummy_file_name, dir_id, None) + } } } } -impl<'tcx> DebugContext<'tcx> { - pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) { - let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo()); - - let file_id = line_program_add_file( - &mut self.dwarf.unit.line_program, - &mut self.dwarf.line_strings, - &loc.file, - ); - - let entry = self.dwarf.unit.get_mut(entry_id); - - entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); - entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(loc.line as u64)); - entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(loc.col.to_usize() as u64)); +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, symbol: usize, - entry_id: UnitEntryId, context: &Context, - function_span: Span, - source_info_set: &indexmap::IndexSet, ) -> CodeOffset { - let tcx = self.tcx; - let line_program = &mut self.dwarf.unit.line_program; - - let line_strings = &mut self.dwarf.line_strings; - let mut last_span = None; - let mut last_file = None; - let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| { - if let Some(last_span) = last_span { - if span == last_span { - line_program.generate_row(); - return; - } - } - last_span = Some(span); - - // 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 - // (unless the crate is being compiled with `-Z debug-macros`). - let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros { - span - } else { - // 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. - rustc_span::hygiene::walk_chain(span, function_span.ctxt()) + 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(); }; - let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) { - Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.line_begin_pos(span.lo()); - - ( - file, - u64::try_from(line).unwrap() + 1, - u64::from((span.lo() - line_pos).to_u32()) + 1, - ) - } - Err(file) => (file, 0, 0), - }; - - // line_program_add_file is very slow. - // Optimize for the common case of the current file not being changed. - let current_file_changed = if let Some(last_file) = &last_file { - // If the allocations are not equal, then the files may still be equal, but that - // is not a problem, as this is just an optimization. - !rustc_data_structures::sync::Lrc::ptr_eq(last_file, &file) - } else { - true - }; - if current_file_changed { - let file_id = line_program_add_file(line_program, line_strings, &file); - line_program.row().file = file_id; - last_file = Some(file); - } - - line_program.row().line = line; - line_program.row().column = col; - line_program.generate_row(); - }; - - line_program.begin_sequence(Some(Address::Symbol { symbol, addend: 0 })); + debug_context + .dwarf + .unit + .line_program + .begin_sequence(Some(Address::Symbol { symbol, addend: 0 })); let mut func_end = 0; - let mcr = context.mach_compile_result.as_ref().unwrap(); + let mcr = context.compiled_code().unwrap(); for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() { - line_program.row().address_offset = u64::from(start); + debug_context.dwarf.unit.line_program.row().address_offset = u64::from(start); if !loc.is_default() { - let source_info = *source_info_set.get_index(loc.bits() as usize).unwrap(); - create_row_for_span(line_program, source_info.span); + let source_loc = *self.source_loc_set.get_index(loc.bits() as usize).unwrap(); + create_row_for_span(debug_context, source_loc); } else { - create_row_for_span(line_program, function_span); + create_row_for_span(debug_context, self.function_source_loc); } func_end = end; } - line_program.end_sequence(u64::from(func_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 = self.dwarf.unit.get_mut(entry_id); + let entry = debug_context.dwarf.unit.get_mut(self.entry_id); entry.set( gimli::DW_AT_low_pc, AttributeValue::Address(Address::Symbol { symbol, addend: 0 }), ); entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end))); - self.emit_location(entry_id, function_span); - func_end } } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 693092ba5..c55db2017 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -7,35 +7,34 @@ mod unwind; use crate::prelude::*; -use rustc_index::vec::IndexVec; - -use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel}; +use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::TargetIsa; -use cranelift_codegen::ValueLocRange; use gimli::write::{ - Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location, - LocationList, Range, RangeList, UnitEntryId, + Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList, + UnitEntryId, }; -use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64}; +use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; +use indexmap::IndexSet; pub(crate) use emit::{DebugReloc, DebugRelocName}; pub(crate) use unwind::UnwindContext; -pub(crate) struct DebugContext<'tcx> { - tcx: TyCtxt<'tcx>, - +pub(crate) struct DebugContext { endian: RunTimeEndian, dwarf: DwarfUnit, unit_range_list: RangeList, +} - types: FxHashMap, UnitEntryId>, +pub(crate) struct FunctionDebugContext { + entry_id: UnitEntryId, + function_source_loc: (FileId, u64, u64), + source_loc_set: indexmap::IndexSet<(FileId, u64, u64)>, } -impl<'tcx> DebugContext<'tcx> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self { +impl DebugContext { + pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { let encoding = Encoding { format: Format::Dwarf32, // FIXME this should be configurable @@ -101,127 +100,18 @@ impl<'tcx> DebugContext<'tcx> { root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } - DebugContext { - tcx, - - endian, - - dwarf, - unit_range_list: RangeList(Vec::new()), - - types: FxHashMap::default(), - } - } - - fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId { - if let Some(type_id) = self.types.get(&ty) { - return *type_id; - } - - let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag); - - let primitive = |dwarf: &mut DwarfUnit, ate| { - let type_id = new_entry(dwarf, gimli::DW_TAG_base_type); - let type_entry = dwarf.unit.get_mut(type_id); - type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate)); - type_id - }; - - let name = format!("{}", ty); - let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap(); - - let type_id = match ty.kind() { - ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean), - ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF), - ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned), - ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed), - ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float), - ty::Ref(_, pointee_ty, _mutbl) - | ty::RawPtr(ty::TypeAndMut { ty: pointee_ty, mutbl: _mutbl }) => { - let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type); - - // Ensure that type is inserted before recursing to avoid duplicates - self.types.insert(ty, type_id); - - let pointee = self.dwarf_ty(*pointee_ty); - - let type_entry = self.dwarf.unit.get_mut(type_id); - - //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut)); - type_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(pointee)); - - type_id - } - ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => { - let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type); - - // Ensure that type is inserted before recursing to avoid duplicates - self.types.insert(ty, type_id); - - let variant = adt_def.non_enum_variant(); - - for (field_idx, field_def) in variant.fields.iter().enumerate() { - let field_offset = layout.fields.offset(field_idx); - let field_layout = layout.field( - &layout::LayoutCx { tcx: self.tcx, param_env: ParamEnv::reveal_all() }, - field_idx, - ); - - let field_type = self.dwarf_ty(field_layout.ty); - - let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member); - let field_entry = self.dwarf.unit.get_mut(field_id); - - field_entry.set( - gimli::DW_AT_name, - AttributeValue::String(field_def.name.as_str().to_string().into_bytes()), - ); - field_entry.set( - gimli::DW_AT_data_member_location, - AttributeValue::Udata(field_offset.bytes()), - ); - field_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(field_type)); - } - - type_id - } - _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type), - }; - - let type_entry = self.dwarf.unit.get_mut(type_id); - - type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes())); - type_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - - self.types.insert(ty, type_id); - - type_id - } - - fn define_local(&mut self, scope: UnitEntryId, name: String, ty: Ty<'tcx>) -> UnitEntryId { - let dw_ty = self.dwarf_ty(ty); - - let var_id = self.dwarf.unit.add(scope, gimli::DW_TAG_variable); - let var_entry = self.dwarf.unit.get_mut(var_id); - - var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes())); - var_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); - - var_id + DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()) } } pub(crate) fn define_function( &mut self, - instance: Instance<'tcx>, - func_id: FuncId, + tcx: TyCtxt<'_>, name: &str, - isa: &dyn TargetIsa, - context: &Context, - source_info_set: &indexmap::IndexSet, - local_map: IndexVec>, - ) { - let symbol = func_id.as_u32() as usize; - let mir = self.tcx.instance_mir(instance.def); + function_span: Span, + ) -> FunctionDebugContext { + let (file, line, column) = DebugContext::get_span_loc(tcx, function_span, function_span); + + let file_id = self.add_source_file(&file); // FIXME: add to appropriate scope instead of root let scope = self.dwarf.unit.root(); @@ -233,14 +123,35 @@ impl<'tcx> DebugContext<'tcx> { entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id)); - let end = self.create_debug_lines(symbol, entry_id, context, mir.span, source_info_set); + 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_decl_column, AttributeValue::Udata(column)); - self.unit_range_list.0.push(Range::StartLength { + FunctionDebugContext { + entry_id, + function_source_loc: (file_id, line, column), + source_loc_set: IndexSet::new(), + } + } +} + +impl FunctionDebugContext { + pub(crate) fn finalize( + mut self, + debug_context: &mut DebugContext, + func_id: FuncId, + context: &Context, + ) { + let symbol = func_id.as_u32() as usize; + + let end = self.create_debug_lines(debug_context, symbol, context); + + debug_context.unit_range_list.0.push(Range::StartLength { begin: Address::Symbol { symbol, addend: 0 }, length: u64::from(end), }); - let func_entry = self.dwarf.unit.get_mut(entry_id); + 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, @@ -248,110 +159,5 @@ impl<'tcx> DebugContext<'tcx> { ); // Using Udata for DW_AT_high_pc requires at least DWARF4 func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); - - // FIXME make it more reliable and implement scopes before re-enabling this. - if false { - let value_labels_ranges = std::collections::HashMap::new(); // FIXME - - for (local, _local_decl) in mir.local_decls.iter_enumerated() { - let ty = self.tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - mir.local_decls[local].ty, - ); - let var_id = self.define_local(entry_id, format!("{:?}", local), ty); - - let location = place_location( - self, - isa, - symbol, - &local_map, - &value_labels_ranges, - Place { local, projection: ty::List::empty() }, - ); - - let var_entry = self.dwarf.unit.get_mut(var_id); - var_entry.set(gimli::DW_AT_location, location); - } - } - - // FIXME create locals for all entries in mir.var_debug_info - } -} - -fn place_location<'tcx>( - debug_context: &mut DebugContext<'tcx>, - isa: &dyn TargetIsa, - symbol: usize, - local_map: &IndexVec>, - #[allow(rustc::default_hash_types)] value_labels_ranges: &std::collections::HashMap< - ValueLabel, - Vec, - >, - place: Place<'tcx>, -) -> AttributeValue { - assert!(place.projection.is_empty()); // FIXME implement them - - match local_map[place.local].inner() { - CPlaceInner::Var(_local, var) => { - let value_label = cranelift_codegen::ir::ValueLabel::new(var.index()); - if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) { - let loc_list = LocationList( - value_loc_ranges - .iter() - .map(|value_loc_range| Location::StartEnd { - begin: Address::Symbol { - symbol, - addend: i64::from(value_loc_range.start), - }, - end: Address::Symbol { symbol, addend: i64::from(value_loc_range.end) }, - data: translate_loc(isa, value_loc_range.loc).unwrap(), - }) - .collect(), - ); - let loc_list_id = debug_context.dwarf.unit.locations.add(loc_list); - - AttributeValue::LocationListRef(loc_list_id) - } else { - // FIXME set value labels for unused locals - - AttributeValue::Exprloc(Expression::new()) - } - } - CPlaceInner::VarPair(_, _, _) => { - // FIXME implement this - - AttributeValue::Exprloc(Expression::new()) - } - CPlaceInner::VarLane(_, _, _) => { - // FIXME implement this - - AttributeValue::Exprloc(Expression::new()) - } - CPlaceInner::Addr(_, _) => { - // FIXME implement this (used by arguments and returns) - - AttributeValue::Exprloc(Expression::new()) - - // For PointerBase::Stack: - //AttributeValue::Exprloc(translate_loc(ValueLoc::Stack(*stack_slot)).unwrap()) - } - } -} - -// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137 -fn translate_loc(isa: &dyn TargetIsa, loc: LabelValueLoc) -> Option { - match loc { - LabelValueLoc::Reg(reg) => { - let machine_reg = isa.map_regalloc_reg_to_dwarf(reg).unwrap(); - let mut expr = Expression::new(); - expr.op_reg(gimli::Register(machine_reg)); - Some(expr) - } - LabelValueLoc::SPOffset(offset) => { - let mut expr = Expression::new(); - expr.op_breg(X86_64::RSP, offset); - Some(expr) - } } } diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index f619bb5ed..97b395bcd 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -42,10 +42,10 @@ pub(crate) fn codegen_set_discriminant<'tcx>( Variants::Multiple { tag: _, tag_field, - tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, variants: _, } => { - if variant_index != dataful_variant { + if variant_index != untagged_variant { let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = ty::ScalarInt::try_from_uint( @@ -62,16 +62,14 @@ pub(crate) fn codegen_set_discriminant<'tcx>( pub(crate) fn codegen_get_discriminant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, + dest: CPlace<'tcx>, value: CValue<'tcx>, dest_layout: TyAndLayout<'tcx>, -) -> CValue<'tcx> { +) { let layout = value.layout(); - if layout.abi == Abi::Uninhabited { - let true_ = fx.bcx.ins().iconst(types::I32, 1); - fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached); - // Return a dummy value - return CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout); + if layout.abi.is_uninhabited() { + return; } let (tag_scalar, tag_field, tag_encoding) = match &layout.variants { @@ -89,7 +87,9 @@ pub(crate) fn codegen_get_discriminant<'tcx>( } else { ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap() }; - return CValue::const_val(fx, dest_layout, discr_val); + 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) @@ -110,9 +110,10 @@ pub(crate) fn codegen_get_discriminant<'tcx>( _ => false, }; let val = clif_intcast(fx, tag, cast_to, signed); - CValue::by_val(val, dest_layout) + let res = CValue::by_val(val, dest_layout); + dest.write_cvalue(fx, res); } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. @@ -168,9 +169,11 @@ pub(crate) fn codegen_get_discriminant<'tcx>( fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32())) }; - let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32())); - let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant); - CValue::by_val(discr, dest_layout) + let untagged_variant = + fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32())); + let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant); + let res = CValue::by_val(discr, dest_layout); + dest.write_cvalue(fx, res); } } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 3cd1ef563..8eabe1cbc 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -1,33 +1,129 @@ //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a //! standalone executable. +use std::fs::File; use std::path::PathBuf; +use std::sync::Arc; +use std::thread::JoinHandle; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; 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::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::cgu_reuse_tracker::CguReuse; -use rustc_session::config::{DebugInfo, OutputType}; +use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; use rustc_session::Session; -use cranelift_codegen::isa::TargetIsa; use cranelift_object::{ObjectBuilder, ObjectModule}; +use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; +use crate::global_asm::GlobalAsmConfig; use crate::{prelude::*, BackendConfig}; -struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>); +struct ModuleCodegenResult { + module_regular: CompiledModule, + module_global_asm: Option, + existing_work_product: Option<(WorkProductId, WorkProduct)>, +} + +enum OngoingModuleCodegen { + Sync(Result), + Async(JoinHandle>), +} -impl HashStable for ModuleCodegenResult { +impl HashStable for OngoingModuleCodegen { fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { // do nothing } } -fn make_module(sess: &Session, isa: Box, name: String) -> ObjectModule { +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, + backend_config: &BackendConfig, + ) -> (CodegenResults, FxHashMap) { + let mut work_products = FxHashMap::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.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); + } + } + + drop(self.concurrency_limiter); + + ( + CodegenResults { + modules, + allocator_module: self.allocator_module, + metadata_module: self.metadata_module, + metadata: self.metadata, + crate_info: self.crate_info, + }, + work_products, + ) + } +} + +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 @@ -37,15 +133,15 @@ fn make_module(sess: &Session, isa: Box, name: String) -> ObjectM ObjectModule::new(builder) } -fn emit_module( - tcx: TyCtxt<'_>, - backend_config: &BackendConfig, +fn emit_cgu( + output_filenames: &OutputFilenames, + prof: &SelfProfilerRef, name: String, - kind: ModuleKind, module: ObjectModule, - debug: Option>, + debug: Option, unwind_context: UnwindContext, -) -> ModuleCodegenResult { + global_asm_object_file: Option, +) -> Result { let mut product = module.finish(); if let Some(mut debug) = debug { @@ -54,134 +150,191 @@ fn emit_module( unwind_context.emit(&mut product); - let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(&name)); - let obj = product.object.write().unwrap(); + let module_regular = + emit_module(output_filenames, prof, product.object, ModuleKind::Regular, name.clone())?; + + 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, + }) +} - tcx.sess.prof.artifact_size("object_file", name.clone(), obj.len().try_into().unwrap()); +fn emit_module( + output_filenames: &OutputFilenames, + prof: &SelfProfilerRef, + object: cranelift_object::object::write::Object<'_>, + kind: ModuleKind, + name: String, +) -> Result { + 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) = std::fs::write(&tmp_file, obj) { - tcx.sess.fatal(&format!("error writing object file: {}", err)); + if let Err(err) = object.write_stream(&mut file) { + return Err(format!("error writing object file: {}", err)); } - let work_product = if backend_config.disable_incr_cache { - None - } else { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( - tcx.sess, - &name, - &[("o", &tmp_file)], - ) - }; + prof.artifact_size("object_file", &*name, file.metadata().unwrap().len()); - ModuleCodegenResult( - CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None }, - work_product, - ) + Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None }) } fn reuse_workproduct_for_cgu( tcx: TyCtxt<'_>, cgu: &CodegenUnit<'_>, - work_products: &mut FxHashMap, -) -> CompiledModule { +) -> Result { let work_product = cgu.previous_work_product(tcx); - let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); - let source_file = rustc_incremental::in_incr_comp_dir_sess( + 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, &obj_out) { - tcx.sess.err(&format!( + + 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.display(), - obj_out.display(), + 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 + }; - work_products.insert(cgu.work_product_id(), work_product); - - CompiledModule { - name: cgu.name().to_string(), - kind: ModuleKind::Regular, - object: Some(obj_out), - dwarf_object: None, - bytecode: None, - } + 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: if has_global_asm { + Some(CompiledModule { + name: cgu.name().to_string(), + kind: ModuleKind::Regular, + object: Some(obj_out_global_asm), + dwarf_object: None, + bytecode: None, + }) + } else { + None + }, + existing_work_product: Some((cgu.work_product_id(), work_product)), + }) } fn module_codegen( tcx: TyCtxt<'_>, - (backend_config, cgu_name): (BackendConfig, rustc_span::Symbol), -) -> ModuleCodegenResult { - let cgu = tcx.codegen_unit(cgu_name); - let mono_items = cgu.items_in_deterministic_order(tcx); - - let isa = crate::build_isa(tcx.sess, &backend_config); - let mut module = make_module(tcx.sess, isa, 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, - ); - super::predefine_mono_items(tcx, &mut module, &mono_items); - for (mono_item, _) in mono_items { - match mono_item { - MonoItem::Fn(inst) => { - cx.tcx - .sess - .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst)); - } - MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id), - MonoItem::GlobalAsm(item_id) => { - let item = cx.tcx.hir().item(item_id); - if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { - if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - cx.global_asm.push_str("\n.intel_syntax noprefix\n"); - } else { - cx.global_asm.push_str("\n.att_syntax\n"); - } - for piece in asm.template { - match *piece { - InlineAsmTemplatePiece::String(ref s) => cx.global_asm.push_str(s), - InlineAsmTemplatePiece::Placeholder { .. } => todo!(), - } - } - cx.global_asm.push_str("\n.att_syntax\n\n"); - } else { - bug!("Expected GlobalAsm found {:?}", item); + (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.sess.time("codegen cgu", || { + 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, + ); + 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) => { + tcx.sess.time("codegen fn", || { + let codegened_function = crate::base::codegen_fn( + tcx, + &mut cx, + Function::new(), + &mut module, + inst, + ); + codegened_functions.push(codegened_function); + }); + } + MonoItem::Static(def_id) => { + crate::constant::codegen_static(tcx, &mut module, def_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 debug_context = cx.debug_context; - let unwind_context = cx.unwind_context; - let codegen_result = tcx.sess.time("write object file", || { - emit_module( + crate::main_shim::maybe_create_entry_wrapper( tcx, - &backend_config, - cgu.name().as_str().to_string(), - ModuleKind::Regular, - module, - debug_context, - unwind_context, - ) + &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) }); - codegen_global_asm(tcx, cgu.name().as_str(), &cx.global_asm); + OngoingModuleCodegen::Async(std::thread::spawn(move || { + cx.profiler.clone().verbose_generic_activity("compile functions").run(|| { + 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); + } + }); - codegen_result + let global_asm_object_file = + cx.profiler.verbose_generic_activity("compile assembly").run(|| { + crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm) + })?; + + let codegen_result = cx.profiler.verbose_generic_activity("write object file").run(|| { + emit_cgu( + &global_asm_config.output_filenames, + &cx.profiler, + cgu_name, + module, + cx.debug_context, + cx.unwind_context, + global_asm_object_file, + ) + }); + std::mem::drop(token); + codegen_result + })) } pub(crate) fn run_aot( @@ -189,9 +342,7 @@ pub(crate) fn run_aot( backend_config: BackendConfig, metadata: EncodedMetadata, need_metadata_module: bool, -) -> Box<(CodegenResults, FxHashMap)> { - let mut work_products = FxHashMap::default(); - +) -> Box { let cgus = if tcx.sess.opts.output_types.should_codegen() { tcx.collect_and_partition_mono_items(()).1 } else { @@ -206,62 +357,69 @@ pub(crate) fn run_aot( } } + let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); + + let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len()); + let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || { cgus.iter() .map(|cgu| { - let cgu_reuse = determine_cgu_reuse(tcx, cgu); + let cgu_reuse = if backend_config.disable_incr_cache { + CguReuse::No + } else { + determine_cgu_reuse(tcx, cgu) + }; tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); match cgu_reuse { - _ if backend_config.disable_incr_cache => {} - CguReuse::No => {} - CguReuse::PreLto => { - return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products); + 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(), + ), + module_codegen, + Some(rustc_middle::dep_graph::hash_result), + ) + .0 + } + CguReuse::PreLto => unreachable!(), + CguReuse::PostLto => { + concurrency_limiter.job_already_done(); + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, &*cgu)) } - CguReuse::PostLto => unreachable!(), - } - - let dep_node = cgu.codegen_dep_node(tcx); - let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task( - dep_node, - tcx, - (backend_config.clone(), cgu.name()), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ); - - if let Some((id, product)) = work_product { - work_products.insert(id, product); } - - module }) .collect::>() }); tcx.sess.abort_if_errors(); - let isa = crate::build_isa(tcx.sess, &backend_config); - let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); - assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); + 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 ModuleCodegenResult(module, work_product) = emit_module( - tcx, - &backend_config, - "allocator_shim".to_string(), + 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_module, - None, - allocator_unwind_context, - ); - if let Some((id, product)) = work_product { - work_products.insert(id, product); + "allocator_shim".to_owned(), + ) { + Ok(allocator_module) => Some(allocator_module), + Err(err) => tcx.sess.fatal(err), } - Some(module) } else { None }; @@ -308,102 +466,14 @@ pub(crate) fn run_aot( } .to_owned(); - Box::new(( - CodegenResults { - modules, - allocator_module, - metadata_module, - metadata, - crate_info: CrateInfo::new(tcx, target_cpu), - }, - work_products, - )) -} - -fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) { - use std::io::Write; - use std::process::{Command, Stdio}; - - if global_asm.is_empty() { - return; - } - - if cfg!(not(feature = "inline_asm")) - || tcx.sess.target.is_like_osx - || tcx.sess.target.is_like_windows - { - if global_asm.contains("__rust_probestack") { - return; - } - - // FIXME fix linker error on macOS - if cfg!(not(feature = "inline_asm")) { - tcx.sess.fatal( - "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift", - ); - } else { - tcx.sess.fatal("asm! and global_asm! are not yet supported on macOS and Windows"); - } - } - - let assembler = crate::toolchain::get_toolchain_binary(tcx.sess, "as"); - let linker = crate::toolchain::get_toolchain_binary(tcx.sess, "ld"); - - // Remove all LLVM style comments - let global_asm = global_asm - .lines() - .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line }) - .collect::>() - .join("\n"); - - let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name)); - - // Assemble `global_asm` - let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm"); - let mut child = Command::new(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() { - tcx.sess.fatal(&format!("Failed to assemble `{}`", global_asm)); - } - - // Link the global asm and main object file together - let main_object_file = add_file_stem_postfix(output_object_file.clone(), ".main"); - std::fs::rename(&output_object_file, &main_object_file).unwrap(); - let status = Command::new(linker) - .arg("-r") // Create a new object file - .arg("-o") - .arg(output_object_file) - .arg(&main_object_file) - .arg(&global_asm_object_file) - .status() - .unwrap(); - if !status.success() { - tcx.sess.fatal(&format!( - "Failed to link `{}` and `{}` together", - main_object_file.display(), - global_asm_object_file.display(), - )); - } - - std::fs::remove_file(global_asm_object_file).unwrap(); - std::fs::remove_file(main_object_file).unwrap(); -} - -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 + Box::new(OngoingCodegen { + modules, + allocator_module, + metadata_module, + metadata, + crate_info: CrateInfo::new(tcx, target_cpu), + concurrency_limiter, + }) } // Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953 @@ -432,5 +502,5 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR cgu.name() ); - if tcx.try_mark_green(&dep_node) { CguReuse::PreLto } else { CguReuse::No } + if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index a56a91000..0e77e4004 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -61,11 +61,11 @@ impl UnsafeMessage { } } -fn create_jit_module<'tcx>( - tcx: TyCtxt<'tcx>, +fn create_jit_module( + tcx: TyCtxt<'_>, backend_config: &BackendConfig, hotswap: bool, -) -> (JITModule, CodegenCx<'tcx>) { +) -> (JITModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info); @@ -111,6 +111,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { &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 @@ -128,11 +129,19 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { MonoItem::Fn(inst) => match backend_config.codegen_mode { CodegenMode::Aot => unreachable!(), CodegenMode::Jit => { - cx.tcx.sess.time("codegen fn", || { - crate::base::codegen_fn(&mut cx, &mut jit_module, inst) + tcx.sess.time("codegen fn", || { + crate::base::codegen_and_compile_fn( + tcx, + &mut cx, + &mut cached_context, + &mut jit_module, + inst, + ) }); } - CodegenMode::JitLazy => codegen_shim(&mut cx, &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); @@ -259,7 +268,15 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> false, Symbol::intern("dummy_cgu_name"), ); - tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance)); + tcx.sess.time("codegen fn", || { + crate::base::codegen_and_compile_fn( + tcx, + &mut cx, + &mut Context::new(), + jit_module, + instance, + ) + }); assert!(cx.global_asm.is_empty()); jit_module.finalize_definitions(); @@ -334,9 +351,13 @@ fn load_imported_symbols_for_jit( imported_symbols } -fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) { - let tcx = cx.tcx; - +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; @@ -357,8 +378,9 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In ) .unwrap(); - cx.cached_context.clear(); - let trampoline = &mut cx.cached_context.func; + let context = cached_context; + context.clear(); + let trampoline = &mut context.func; trampoline.signature = sig.clone(); let mut builder_ctx = FunctionBuilderContext::new(); @@ -381,5 +403,6 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); trampoline_builder.ins().return_(&ret_vals); - module.define_function(func_id, &mut cx.cached_context).unwrap(); + module.define_function(func_id, context).unwrap(); + cx.unwind_context.add_function(func_id, context, module.isa()); } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs new file mode 100644 index 000000000..dcbcaba30 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -0,0 +1,114 @@ +//! 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::ItemId; +use rustc_session::config::{OutputFilenames, OutputType}; + +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 { + 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 { .. } => todo!(), + } + } + global_asm.push_str("\n.att_syntax\n\n"); + } else { + bug!("Expected GlobalAsm found {:?}", item); + } +} + +#[derive(Debug)] +pub(crate) struct GlobalAsmConfig { + asm_enabled: bool, + assembler: PathBuf, + pub(crate) output_filenames: Arc, +} + +impl GlobalAsmConfig { + pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { + let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows; + + GlobalAsmConfig { + asm_enabled, + assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"), + 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); + } + + if !config.asm_enabled { + if global_asm.contains("__rust_probestack") { + return Ok(None); + } + + // FIXME fix linker error on macOS + if cfg!(not(feature = "inline_asm")) { + return Err( + "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift" + .to_owned(), + ); + } else { + return Err("asm! and global_asm! are not yet supported on Windows".to_owned()); + } + } + + // Remove all LLVM style comments + let global_asm = global_asm + .lines() + .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line }) + .collect::>() + .join("\n"); + + let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)); + + // Assemble `global_asm` + let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm"); + 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)); + } + + 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 +} diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 241de5e36..8b3d475cb 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -15,15 +15,19 @@ pub(crate) fn codegen_inline_asm<'tcx>( template: &[InlineAsmTemplatePiece], operands: &[InlineAsmOperand<'tcx>], options: InlineAsmOptions, + destination: Option, ) { // FIXME add .eh_frame unwind info directives if !template.is_empty() { + // Used by panic_abort if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { - let true_ = fx.bcx.ins().iconst(types::I32, 1); - fx.bcx.ins().trapnz(true_, TrapCode::User(1)); + fx.bcx.ins().trap(TrapCode::User(1)); return; - } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) + } + + // Used by stdarch + if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) && matches!( template[1], InlineAsmTemplatePiece::Placeholder { @@ -47,51 +51,46 @@ pub(crate) fn codegen_inline_asm<'tcx>( { assert_eq!(operands.len(), 4); let (leaf, eax_place) = match operands[1] { - InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)) - ); - ( - crate::base::codegen_operand(fx, in_value).load_scalar(fx), - crate::base::codegen_place(fx, out_place.unwrap()), - ) - } + InlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + late: true, + ref in_value, + out_place: Some(out_place), + } => ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place), + ), _ => unreachable!(), }; let ebx_place = match operands[0] { - InlineAsmOperand::Out { reg, late: true, place } => { - assert_eq!( - reg, + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86( - X86InlineAsmRegClass::reg - )) - ); - crate::base::codegen_place(fx, place.unwrap()) - } + X86InlineAsmRegClass::reg, + )), + late: true, + place: Some(place), + } => crate::base::codegen_place(fx, place), _ => unreachable!(), }; let (sub_leaf, ecx_place) = match operands[2] { - InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)) - ); - ( - crate::base::codegen_operand(fx, in_value).load_scalar(fx), - crate::base::codegen_place(fx, out_place.unwrap()), - ) - } + InlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), + late: true, + ref in_value, + out_place: Some(out_place), + } => ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place), + ), _ => unreachable!(), }; let edx_place = match operands[3] { - InlineAsmOperand::Out { reg, late: true, place } => { - assert_eq!( - reg, - InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)) - ); - crate::base::codegen_place(fx, place.unwrap()) - } + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + late: true, + place: Some(place), + } => crate::base::codegen_place(fx, place), _ => unreachable!(), }; @@ -101,12 +100,99 @@ pub(crate) fn codegen_inline_asm<'tcx>( ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); return; - } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") { + } + + // Used by compiler-builtins + if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") { // ___chkstk, ___chkstk_ms and __alloca are only used on Windows crate::trap::trap_unimplemented(fx, "Stack probes are not supported"); + return; } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" { crate::trap::trap_unimplemented(fx, "Alloca is not supported"); + return; + } + + // Used by measureme + if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string()) + && template[1] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[2] == InlineAsmTemplatePiece::String("mov %rbx, ".to_string()) + && matches!( + template[3], + InlineAsmTemplatePiece::Placeholder { + operand_idx: 0, + modifier: Some('r'), + span: _ + } + ) + && template[4] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[5] == InlineAsmTemplatePiece::String("cpuid".to_string()) + && template[6] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[7] == InlineAsmTemplatePiece::String("mov ".to_string()) + && matches!( + template[8], + InlineAsmTemplatePiece::Placeholder { + operand_idx: 0, + modifier: Some('r'), + span: _ + } + ) + && template[9] == InlineAsmTemplatePiece::String(", %rbx".to_string()) + { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } else if template[0] == InlineAsmTemplatePiece::String("rdpmc".to_string()) { + // Return zero dummy values for all performance counters + match operands[0] { + InlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), + value: _, + } => {} + _ => unreachable!(), + }; + let lo = match operands[1] { + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + late: true, + place: Some(place), + } => crate::base::codegen_place(fx, place), + _ => unreachable!(), + }; + let hi = match operands[2] { + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + late: true, + place: Some(place), + } => crate::base::codegen_place(fx, place), + _ => unreachable!(), + }; + + let u32_layout = fx.layout_of(fx.tcx.types.u32); + let zero = fx.bcx.ins().iconst(types::I32, 0); + lo.write_cvalue(fx, CValue::by_val(zero, u32_layout)); + hi.write_cvalue(fx, CValue::by_val(zero, u32_layout)); + + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; + } else if template[0] == InlineAsmTemplatePiece::String("lock xadd ".to_string()) + && matches!( + template[1], + InlineAsmTemplatePiece::Placeholder { operand_idx: 1, modifier: None, span: _ } + ) + && template[2] == InlineAsmTemplatePiece::String(", (".to_string()) + && matches!( + template[3], + InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: None, span: _ } + ) + && template[4] == InlineAsmTemplatePiece::String(")".to_string()) + { + let destination_block = fx.get_block(destination.unwrap()); + fx.bcx.ins().jump(destination_block, &[]); + return; } } @@ -175,6 +261,16 @@ pub(crate) fn codegen_inline_asm<'tcx>( } call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); + + match destination { + Some(destination) => { + let destination_block = fx.get_block(destination); + fx.bcx.ins().jump(destination_block, &[]); + } + None => { + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + } + } } struct InlineAssemblyGenerator<'a, 'tcx> { @@ -637,7 +733,7 @@ fn call_inline_asm<'tcx>( inputs: Vec<(Size, Value)>, outputs: Vec<(Size, CPlace<'tcx>)>, ) { - let stack_slot = fx.bcx.func.create_stack_slot(StackSlotData { + let stack_slot = fx.bcx.func.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, size: u32::try_from(slot_size.bytes()).unwrap(), }); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs index d02dfd93c..5120b89c4 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs @@ -62,7 +62,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>( fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]); fx.bcx.switch_to_block(unsupported_leaf); - crate::trap::trap_unreachable( + crate::trap::trap_unimplemented( fx, "__cpuid_count arch intrinsic doesn't yet support specified leaf", ); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 869670c8c..a799dca93 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -139,6 +139,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( .sess .warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); crate::trap::trap_unimplemented(fx, intrinsic); + return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index b2a83e1d4..2e4ca594f 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -44,7 +44,7 @@ fn report_atomic_type_validation_error<'tcx>( ), ); // Prevent verifier error - crate::trap::trap_unreachable(fx, "compilation should not have succeeded"); + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option { @@ -53,7 +53,7 @@ pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx _ => unreachable!(), }; - match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) { + match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) { // Cranelift currently only implements icmp for 128bit vectors. Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty), _ => None, @@ -203,7 +203,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( sym::transmute => { crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); } - _ => unimplemented!("unsupported instrinsic {}", intrinsic), + _ => unimplemented!("unsupported intrinsic {}", intrinsic), } return; }; @@ -301,7 +301,44 @@ fn codegen_float_intrinsic_call<'tcx>( _ => unreachable!(), }; - let res = fx.easy_call(name, &args, ty); + let layout = fx.layout_of(ty); + let res = match intrinsic { + sym::fmaf32 | sym::fmaf64 => { + let a = args[0].load_scalar(fx); + let b = args[1].load_scalar(fx); + let c = args[2].load_scalar(fx); + CValue::by_val(fx.bcx.ins().fma(a, b, c), layout) + } + sym::copysignf32 | sym::copysignf64 => { + let a = args[0].load_scalar(fx); + let b = args[1].load_scalar(fx); + CValue::by_val(fx.bcx.ins().fcopysign(a, b), layout) + } + sym::fabsf32 + | sym::fabsf64 + | sym::floorf32 + | sym::floorf64 + | sym::ceilf32 + | sym::ceilf64 + | sym::truncf32 + | sym::truncf64 => { + let a = args[0].load_scalar(fx); + + let val = match intrinsic { + sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(a), + sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(a), + sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(a), + sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(a), + _ => unreachable!(), + }; + + CValue::by_val(val, layout) + } + // These intrinsics aren't supported natively by Cranelift. + // Lower them to a libcall. + _ => fx.easy_call(name, &args, ty), + }; + ret.write_cvalue(fx, res); true @@ -320,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>( let usize_layout = fx.layout_of(fx.tcx.types.usize); match intrinsic { - sym::assume => { - intrinsic_args!(fx, args => (_a); intrinsic); - } sym::likely | sym::unlikely => { intrinsic_args!(fx, args => (a); intrinsic); @@ -540,6 +574,13 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(res, base.layout())); } + sym::ptr_mask => { + intrinsic_args!(fx, args => (ptr, mask); intrinsic); + let ptr = ptr.load_scalar(fx); + let mask = mask.load_scalar(fx); + fx.bcx.ins().band(ptr, mask); + } + sym::transmute => { intrinsic_args!(fx, args => (from); intrinsic); @@ -775,20 +816,13 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - sym::ptr_guaranteed_eq => { + sym::ptr_guaranteed_cmp => { intrinsic_args!(fx, args => (a, b); intrinsic); let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b); ret.write_cvalue(fx, val); } - sym::ptr_guaranteed_ne => { - intrinsic_args!(fx, args => (a, b); intrinsic); - - let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b); - ret.write_cvalue(fx, val); - } - sym::caller_location => { intrinsic_args!(fx, args => (); intrinsic); @@ -818,8 +852,6 @@ fn codegen_regular_intrinsic_call<'tcx>( if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); - let ret_block = fx.get_block(destination.unwrap()); - fx.bcx.ins().jump(ret_block, &[]); return; } else { fx.tcx @@ -851,8 +883,6 @@ fn codegen_regular_intrinsic_call<'tcx>( if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); - let ret_block = fx.get_block(destination.unwrap()); - fx.bcx.ins().jump(ret_block, &[]); return; } else { fx.tcx diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 30e3d1125..1f358b1bb 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -14,7 +14,7 @@ fn report_simd_type_validation_error( ) { fx.tcx.sess.span_err(span, &format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty)); // Prevent verifier error - crate::trap::trap_unreachable(fx, "compilation should not have succeeded"); + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } pub(super) fn codegen_simd_intrinsic_call<'tcx>( @@ -157,7 +157,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ), ); // Prevent verifier error - crate::trap::trap_unreachable(fx, "compilation should not have succeeded"); + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); return; } } @@ -186,7 +186,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let size = Size::from_bytes( 4 * ret_lane_count, /* size_of([u32; ret_lane_count]) */ ); - alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap() + alloc + .inner() + .get_bytes_strip_provenance(fx, alloc_range(offset, size)) + .unwrap() } _ => unreachable!("{:?}", idx_const), }; @@ -274,12 +277,17 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( idx_const } else { fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant"); - let res = crate::trap::trap_unimplemented_ret_value( + let trap_block = fx.bcx.create_block(); + let dummy_block = fx.bcx.create_block(); + let true_ = fx.bcx.ins().iconst(types::I8, 1); + fx.bcx.ins().brnz(true_, trap_block, &[]); + fx.bcx.ins().jump(dummy_block, &[]); + fx.bcx.switch_to_block(trap_block); + crate::trap::trap_unimplemented( fx, - ret.layout(), "Index argument for `simd_extract` is not a constant", ); - ret.write_cvalue(fx, res); + fx.bcx.switch_to_block(dummy_block); return; }; @@ -392,21 +400,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let layout = a.layout(); let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let res_lane_layout = fx.layout_of(lane_ty); for lane in 0..lane_count { - let a_lane = a.value_lane(fx, lane); - let b_lane = b.value_lane(fx, lane); - let c_lane = c.value_lane(fx, lane); + let a_lane = a.value_lane(fx, lane).load_scalar(fx); + let b_lane = b.value_lane(fx, lane).load_scalar(fx); + let c_lane = c.value_lane(fx, lane).load_scalar(fx); - let res_lane = match lane_ty.kind() { - ty::Float(FloatTy::F32) => { - fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty) - } - ty::Float(FloatTy::F64) => { - fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty) - } - _ => unreachable!(), - }; + let res_lane = fx.bcx.ins().fma(a_lane, b_lane, c_lane); + let res_lane = CValue::by_val(res_lane, res_lane_layout); ret.place_lane(fx, lane).write_cvalue(fx, res_lane); } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index bb0793b1d..913414e76 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -4,6 +4,7 @@ #![warn(unused_lifetimes)] #![warn(unreachable_pub)] +extern crate jobserver; #[macro_use] extern crate rustc_middle; extern crate rustc_ast; @@ -25,10 +26,12 @@ extern crate rustc_target; extern crate rustc_driver; use std::any::Any; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; +use std::sync::Arc; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; +use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -51,11 +54,13 @@ mod cast; mod codegen_i128; mod common; mod compiler_builtins; +mod concurrency_limiter; mod config; mod constant; mod debuginfo; mod discriminant; mod driver; +mod global_asm; mod inline_asm; mod intrinsics; mod linkage; @@ -119,19 +124,20 @@ impl String> Drop for PrintOnPanic { /// The codegen context holds any information shared between the codegen of individual functions /// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). -struct CodegenCx<'tcx> { - tcx: TyCtxt<'tcx>, +struct CodegenCx { + profiler: SelfProfilerRef, + output_filenames: Arc, + should_write_ir: bool, global_asm: String, inline_asm_index: Cell, - cached_context: Context, - debug_context: Option>, + debug_context: Option, unwind_context: UnwindContext, cgu_name: Symbol, } -impl<'tcx> CodegenCx<'tcx> { +impl CodegenCx { fn new( - tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'_>, backend_config: BackendConfig, isa: &dyn TargetIsa, debug_info: bool, @@ -147,10 +153,11 @@ impl<'tcx> CodegenCx<'tcx> { None }; CodegenCx { - tcx, + profiler: tcx.prof.clone(), + output_filenames: tcx.output_filenames(()).clone(), + should_write_ir: crate::pretty_clif::should_write_ir(tcx), global_asm: String::new(), inline_asm_index: Cell::new(0), - cached_context: Context::new(), debug_context, unwind_context, cgu_name, @@ -159,7 +166,7 @@ impl<'tcx> CodegenCx<'tcx> { } pub struct CraneliftCodegenBackend { - pub config: Option, + pub config: RefCell>, } impl CodegenBackend for CraneliftCodegenBackend { @@ -169,6 +176,13 @@ impl CodegenBackend for CraneliftCodegenBackend { Lto::No | Lto::ThinLocal => {} Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."), } + + let mut config = self.config.borrow_mut(); + if config.is_none() { + let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args) + .unwrap_or_else(|err| sess.fatal(&err)); + *config = Some(new_config); + } } fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { @@ -186,15 +200,7 @@ impl CodegenBackend for CraneliftCodegenBackend { need_metadata_module: bool, ) -> Box { tcx.sess.abort_if_errors(); - let config = if let Some(config) = self.config.clone() { - config - } else { - if !tcx.sess.unstable_options() && !tcx.sess.opts.cg.llvm_args.is_empty() { - tcx.sess.fatal("`-Z unstable-options` must be passed to allow configuring cg_clif"); - } - BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) - .unwrap_or_else(|err| tcx.sess.fatal(&err)) - }; + let config = self.config.borrow().clone().unwrap(); match config.codegen_mode { CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module), CodegenMode::Jit | CodegenMode::JitLazy => { @@ -210,12 +216,13 @@ impl CodegenBackend for CraneliftCodegenBackend { fn join_codegen( &self, ongoing_codegen: Box, - _sess: &Session, + sess: &Session, _outputs: &OutputFilenames, ) -> Result<(CodegenResults, FxHashMap), ErrorGuaranteed> { - Ok(*ongoing_codegen - .downcast::<(CodegenResults, FxHashMap)>() - .unwrap()) + Ok(ongoing_codegen + .downcast::() + .unwrap() + .join(sess, self.config.borrow().as_ref().unwrap())) } fn link( @@ -312,5 +319,5 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box Box { - Box::new(CraneliftCodegenBackend { config: None }) + Box::new(CraneliftCodegenBackend { config: RefCell::new(None) }) } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index c67b6e98b..3c024a84d 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,7 +1,7 @@ use rustc_hir::LangItem; use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::AssocKind; -use rustc_session::config::EntryFnType; +use rustc_session::config::{sigpipe, EntryFnType}; use rustc_span::symbol::Ident; use crate::prelude::*; @@ -15,12 +15,12 @@ pub(crate) fn maybe_create_entry_wrapper( is_jit: bool, is_primary_cgu: bool, ) { - let (main_def_id, is_main_fn) = match tcx.entry_fn(()) { + let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) { Some((def_id, entry_ty)) => ( def_id, match entry_ty { - EntryFnType::Main => true, - EntryFnType::Start => false, + EntryFnType::Main { sigpipe } => (true, sigpipe), + EntryFnType::Start => (false, sigpipe::DEFAULT), }, ), None => return, @@ -35,7 +35,7 @@ pub(crate) fn maybe_create_entry_wrapper( return; } - create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn); + create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe); fn create_entry_fn( tcx: TyCtxt<'_>, @@ -44,6 +44,7 @@ pub(crate) fn maybe_create_entry_wrapper( rust_main_def_id: DefId, ignore_lang_start_wrapper: bool, is_main_fn: bool, + sigpipe: u8, ) { let main_ret_ty = tcx.fn_sig(rust_main_def_id).output(); // Given that `main()` has no arguments, @@ -83,6 +84,7 @@ pub(crate) fn maybe_create_entry_wrapper( bcx.switch_to_block(block); let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type()); let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type()); + let arg_sigpipe = bcx.ins().iconst(types::I8, sigpipe as i64); let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); @@ -143,7 +145,8 @@ pub(crate) fn maybe_create_entry_wrapper( let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref); let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func); - let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]); + let call_inst = + bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]); bcx.inst_results(call_inst)[0] } else { // using user-defined start fn diff --git a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs index d1f89adb3..0df7e8229 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs @@ -1,20 +1,3 @@ //! Various optimizations specific to cg_clif -use cranelift_codegen::isa::TargetIsa; - -use crate::prelude::*; - pub(crate) mod peephole; - -pub(crate) fn optimize_function<'tcx>( - tcx: TyCtxt<'tcx>, - isa: &dyn TargetIsa, - instance: Instance<'tcx>, - ctx: &mut Context, - clif_comments: &mut crate::pretty_clif::CommentWriter, -) { - // FIXME classify optimizations over opt levels once we have more - - crate::pretty_clif::write_clif_file(tcx, "preopt", isa, instance, &ctx.func, &*clif_comments); - crate::base::verify_func(tcx, &*clif_comments, &ctx.func); -} diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 1d1ec2168..a7af16268 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -62,7 +62,7 @@ use cranelift_codegen::{ }; use rustc_middle::ty::layout::FnAbiOf; -use rustc_session::config::OutputType; +use rustc_session::config::{OutputFilenames, OutputType}; use crate::prelude::*; @@ -205,15 +205,11 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { } pub(crate) fn write_ir_file( - tcx: TyCtxt<'_>, - name: impl FnOnce() -> String, + output_filenames: &OutputFilenames, + name: &str, write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>, ) { - if !should_write_ir(tcx) { - return; - } - - let clif_output_dir = tcx.output_filenames(()).with_extension("clif"); + let clif_output_dir = output_filenames.with_extension("clif"); match std::fs::create_dir(&clif_output_dir) { Ok(()) => {} @@ -221,44 +217,43 @@ pub(crate) fn write_ir_file( res @ Err(_) => res.unwrap(), } - let clif_file_name = clif_output_dir.join(name()); + let clif_file_name = clif_output_dir.join(name); let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file)); if let Err(err) = res { - tcx.sess.warn(&format!("error writing ir file: {}", err)); + // Using early_warn as no Session is available here + rustc_session::early_warn( + rustc_session::config::ErrorOutputType::default(), + &format!("error writing ir file: {}", err), + ); } } -pub(crate) fn write_clif_file<'tcx>( - tcx: TyCtxt<'tcx>, +pub(crate) fn write_clif_file( + output_filenames: &OutputFilenames, + symbol_name: &str, postfix: &str, isa: &dyn cranelift_codegen::isa::TargetIsa, - instance: Instance<'tcx>, func: &cranelift_codegen::ir::Function, mut clif_comments: &CommentWriter, ) { // FIXME work around filename too long errors - write_ir_file( - tcx, - || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), - |file| { - let mut clif = String::new(); - cranelift_codegen::write::decorate_function(&mut clif_comments, &mut clif, func) - .unwrap(); + write_ir_file(output_filenames, &format!("{}.{}.clif", symbol_name, postfix), |file| { + let mut clif = String::new(); + cranelift_codegen::write::decorate_function(&mut clif_comments, &mut clif, func).unwrap(); - for flag in isa.flags().iter() { - writeln!(file, "set {}", flag)?; - } - write!(file, "target {}", isa.triple().architecture.to_string())?; - for isa_flag in isa.isa_flags().iter() { - write!(file, " {}", isa_flag)?; - } - writeln!(file, "\n")?; - writeln!(file)?; - file.write_all(clif.as_bytes())?; - Ok(()) - }, - ); + for flag in isa.flags().iter() { + writeln!(file, "set {}", flag)?; + } + write!(file, "target {}", isa.triple().architecture.to_string())?; + for isa_flag in isa.isa_flags().iter() { + write!(file, " {}", isa_flag)?; + } + writeln!(file, "\n")?; + writeln!(file)?; + file.write_all(clif.as_bytes())?; + Ok(()) + }); } impl fmt::Debug for FunctionCx<'_, '_, '_> { diff --git a/compiler/rustc_codegen_cranelift/src/toolchain.rs b/compiler/rustc_codegen_cranelift/src/toolchain.rs index f86236ef3..b6b465e1f 100644 --- a/compiler/rustc_codegen_cranelift/src/toolchain.rs +++ b/compiler/rustc_codegen_cranelift/src/toolchain.rs @@ -8,10 +8,8 @@ use rustc_session::Session; /// Tries to infer the path of a binary for the target toolchain from the linker name. pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf { let (mut linker, _linker_flavor) = linker_and_flavor(sess); - let linker_file_name = linker - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or_else(|| sess.fatal("couldn't extract file name from specified linker")); + let linker_file_name = + linker.file_name().unwrap().to_str().expect("linker filename should be valid UTF-8"); if linker_file_name == "ld.lld" { if tool != "ld" { diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 923269c4d..82a2ec579 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -25,33 +25,10 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { fx.bcx.ins().call(puts, &[msg_ptr]); } -/// Use this for example when a function call should never return. This will fill the current block, -/// so you can **not** add instructions to it afterwards. -/// -/// Trap code: user65535 -pub(crate) fn trap_unreachable(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef) { - codegen_print(fx, msg.as_ref()); - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); -} /// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen. -/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions -/// to it afterwards. /// /// Trap code: user65535 pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef) { codegen_print(fx, msg.as_ref()); - let true_ = fx.bcx.ins().iconst(types::I32, 1); - fx.bcx.ins().trapnz(true_, TrapCode::User(!0)); -} - -/// Like `trap_unimplemented` but returns a fake value of the specified type. -/// -/// Trap code: user65535 -pub(crate) fn trap_unimplemented_ret_value<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - dest_layout: TyAndLayout<'tcx>, - msg: impl AsRef, -) -> CValue<'tcx> { - trap_unimplemented(fx, msg); - CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout) + fx.bcx.ins().trap(TrapCode::User(!0)); } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 052ca0a08..dd9d891dd 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -29,6 +29,7 @@ pub(crate) fn unsized_info<'tcx>( 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; } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 45ae2bd8f..cfaadca94 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -122,7 +122,7 @@ impl<'tcx> CValue<'tcx> { let clif_ty = match layout.abi { Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) - .by(u16::try_from(count).unwrap()) + .by(u32::try_from(count).unwrap()) .unwrap(), _ => unreachable!("{:?}", layout.ty), }; @@ -330,7 +330,7 @@ impl<'tcx> CPlace<'tcx> { .fatal(&format!("values of type {} are too big to store on the stack", layout.ty)); } - let stack_slot = fx.bcx.create_stack_slot(StackSlotData { + let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to // specify stack slot alignment. @@ -472,7 +472,7 @@ impl<'tcx> CPlace<'tcx> { } _ if src_ty.is_vector() || dst_ty.is_vector() => { // FIXME do something more efficient for transmutes between vectors and integers. - let stack_slot = fx.bcx.create_stack_slot(StackSlotData { + let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to // specify stack slot alignment. @@ -519,7 +519,7 @@ impl<'tcx> CPlace<'tcx> { if let ty::Array(element, len) = dst_layout.ty.kind() { // Can only happen for vector types let len = - u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap(); + u32::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap(); let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap(); let data = match from.0 { @@ -614,7 +614,7 @@ impl<'tcx> CPlace<'tcx> { dst_align, src_align, true, - MemFlags::trusted(), + flags, ); } CValueInner::ByRef(_, Some(_)) => todo!(), @@ -815,7 +815,8 @@ pub(crate) fn assert_assignable<'tcx>( ); // fn(&T) -> for<'l> fn(&'l T) is allowed } - (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { + // FIXME(dyn-star): Do the right thing with DynKinds for (from, to) in from_traits.iter().zip(to_traits) { let from = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh index a10924628..3d929a1d5 100755 --- a/compiler/rustc_codegen_cranelift/test.sh +++ b/compiler/rustc_codegen_cranelift/test.sh @@ -1,13 +1,2 @@ #!/usr/bin/env bash -set -e - -./y.rs build --sysroot none "$@" - -rm -r target/out || true - -scripts/tests.sh no_sysroot - -./y.rs build "$@" - -scripts/tests.sh base_sysroot -scripts/tests.sh extended_sysroot +exec ./y.rs test diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 5f66ca67f..89661918d 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -156,7 +156,7 @@ mod platform { 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).offset(-1) + &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))); diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch index d5fa1cec0..c59a40df0 100644 --- a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch @@ -14,7 +14,6 @@ index 06c7be0..359e2e7 100644 @@ -75,7 +75,6 @@ #![feature(never_type)] #![feature(unwrap_infallible)] - #![feature(result_into_ok_or_err)] -#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 0ed3e1fbe..848c34211 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -107,45 +107,24 @@ pub trait FnAbiGccExt<'gcc, 'tcx> { impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool, FxHashSet) { let mut on_stack_param_indices = FxHashSet::default(); - let args_capacity: usize = self.args.iter().map(|arg| - if arg.pad.is_some() { - 1 - } - else { - 0 - } + - if let PassMode::Pair(_, _) = arg.mode { - 2 - } else { - 1 - } - ).sum(); + + // This capacity calculation is approximate. let mut argument_tys = Vec::with_capacity( - if let PassMode::Indirect { .. } = self.ret.mode { - 1 - } - else { - 0 - } + args_capacity, + self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } ); let return_ty = match self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), - PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast, _) => cast.gcc_type(cx), PassMode::Indirect { .. } => { argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() } }; - for arg in &self.args { - // add padding - if let Some(ty) = arg.pad { - argument_tys.push(ty.gcc_type(cx)); - } - + for arg in self.args.iter() { let arg_ty = match arg.mode { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), @@ -157,7 +136,13 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { extra_attrs: Some(_), .. } => { unimplemented!(); } - PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast, pad_i32) => { + // add padding + if pad_i32 { + argument_tys.push(Reg::i32().gcc_type(cx)); + } + cast.gcc_type(cx) + } PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index f863abdcc..96c773101 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -45,6 +45,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &Path, + _is_direct_dependency: bool, ) -> PathBuf { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 4d40dd099..6994eeb00 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -15,8 +15,11 @@ use gccjit::{ Type, UnaryOp, }; +use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_codegen_ssa::MemFlags; -use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope}; +use rustc_codegen_ssa::common::{ + AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, +}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ @@ -31,6 +34,7 @@ use rustc_codegen_ssa::traits::{ StaticBuilderMethods, }; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::bug; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -1271,12 +1275,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { val } - fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { - None + fn fptoui_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.fptoint_sat(false, val, dest_ty) } - fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { - None + fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.fptoint_sat(true, val, dest_ty) } fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) { @@ -1285,6 +1289,166 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn fptoint_sat(&mut self, signed: bool, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let src_ty = self.cx.val_ty(val); + let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector { + assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); + (self.cx.element_type(src_ty), self.cx.element_type(dest_ty)) + } else { + (src_ty, dest_ty) + }; + + // FIXME(jistone): the following was originally the fallback SSA implementation, before LLVM 13 + // added native `fptosi.sat` and `fptoui.sat` conversions, but it was used by GCC as well. + // Now that LLVM always relies on its own, the code has been moved to GCC, but the comments are + // still LLVM-specific. This should be updated, and use better GCC specifics if possible. + + let int_width = self.cx.int_width(int_ty); + let float_width = self.cx.float_width(float_ty); + // LLVM's fpto[su]i returns undef when the input val is infinite, NaN, or does not fit into the + // destination integer type after rounding towards zero. This `undef` value can cause UB in + // safe code (see issue #10184), so we implement a saturating conversion on top of it: + // Semantically, the mathematical value of the input is rounded towards zero to the next + // mathematical integer, and then the result is clamped into the range of the destination + // integer type. Positive and negative infinity are mapped to the maximum and minimum value of + // the destination integer type. NaN is mapped to 0. + // + // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to + // a value representable in int_ty. + // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. + // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. + // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly + // representable. Note that this only works if float_ty's exponent range is sufficiently large. + // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 + // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. + // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because + // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). + // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. + let int_max = |signed: bool, int_width: u64| -> u128 { + let shift_amount = 128 - int_width; + if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } + }; + let int_min = |signed: bool, int_width: u64| -> i128 { + if signed { i128::MIN >> (128 - int_width) } else { 0 } + }; + + let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { + let rounded_min = + ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = + ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + }; + let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) { + let rounded_min = + ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = + ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + }; + // To implement saturation, we perform the following steps: + // + // 1. Cast val to an integer with fpto[su]i. This may result in undef. + // 2. Compare val to f_min and f_max, and use the comparison results to select: + // a) int_ty::MIN if val < f_min or val is NaN + // b) int_ty::MAX if val > f_max + // c) the result of fpto[su]i otherwise + // 3. If val is NaN, return 0.0, otherwise return the result of step 2. + // + // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the + // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of + // undef does not introduce any non-determinism either. + // More importantly, the above procedure correctly implements saturating conversion. + // Proof (sketch): + // If val is NaN, 0 is returned by definition. + // Otherwise, val is finite or infinite and thus can be compared with f_min and f_max. + // This yields three cases to consider: + // (1) if val in [f_min, f_max], the result of fpto[su]i is returned, which agrees with + // saturating conversion for inputs in that range. + // (2) if val > f_max, then val is larger than int_ty::MAX. This holds even if f_max is rounded + // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger + // than int_ty::MAX. Because val is larger than int_ty::MAX, the return value of int_ty::MAX + // is correct. + // (3) if val < f_min, then val is smaller than int_ty::MIN. As shown earlier, f_min exactly equals + // int_ty::MIN and therefore the return value of int_ty::MIN is correct. + // QED. + + let float_bits_to_llval = |bx: &mut Self, bits| { + let bits_llval = match float_width { + 32 => bx.cx().const_u32(bits as u32), + 64 => bx.cx().const_u64(bits as u64), + n => bug!("unsupported float width {}", n), + }; + bx.bitcast(bits_llval, float_ty) + }; + let (f_min, f_max) = match float_width { + 32 => compute_clamp_bounds_single(signed, int_width), + 64 => compute_clamp_bounds_double(signed, int_width), + n => bug!("unsupported float width {}", n), + }; + let f_min = float_bits_to_llval(self, f_min); + let f_max = float_bits_to_llval(self, f_max); + let int_max = self.cx.const_uint_big(int_ty, int_max(signed, int_width)); + let int_min = self.cx.const_uint_big(int_ty, int_min(signed, int_width) as u128); + let zero = self.cx.const_uint(int_ty, 0); + + // If we're working with vectors, constants must be "splatted": the constant is duplicated + // into each lane of the vector. The algorithm stays the same, we are just using the + // same constant across all lanes. + let maybe_splat = |bx: &mut Self, val| { + if bx.cx().type_kind(dest_ty) == TypeKind::Vector { + bx.vector_splat(bx.vector_length(dest_ty), val) + } else { + val + } + }; + let f_min = maybe_splat(self, f_min); + let f_max = maybe_splat(self, f_max); + let int_max = maybe_splat(self, int_max); + let int_min = maybe_splat(self, int_min); + let zero = maybe_splat(self, zero); + + // Step 1 ... + let fptosui_result = if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) }; + let less_or_nan = self.fcmp(RealPredicate::RealULT, val, f_min); + let greater = self.fcmp(RealPredicate::RealOGT, val, f_max); + + // Step 2: We use two comparisons and two selects, with %s1 being the + // result: + // %less_or_nan = fcmp ult %val, %f_min + // %greater = fcmp olt %val, %f_max + // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result + // %s1 = select %greater, int_ty::MAX, %s0 + // Note that %less_or_nan uses an *unordered* comparison. This + // comparison is true if the operands are not comparable (i.e., if val is + // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if + // val is NaN. + // + // Performance note: Unordered comparison can be lowered to a "flipped" + // comparison and a negation, and the negation can be merged into the + // select. Therefore, it not necessarily any more expensive than an + // ordered ("normal") comparison. Whether these optimizations will be + // performed is ultimately up to the backend, but at least x86 does + // perform them. + let s0 = self.select(less_or_nan, int_min, fptosui_result); + let s1 = self.select(greater, int_max, s0); + + // Step 3: NaN replacement. + // For unsigned types, the above step already yielded int_ty::MIN == 0 if val is NaN. + // Therefore we only need to execute this step for signed integer types. + if signed { + // LLVM has no isNaN predicate, so we use (val == val) instead + let cmp = self.fcmp(RealPredicate::RealOEQ, val, val); + self.select(cmp, s1, zero) + } else { + s1 + } + } + #[cfg(feature="master")] pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { let struct_type = mask.get_type().is_struct().expect("mask of struct type"); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ccb6cbbc2..aa1c271c3 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -158,10 +158,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { None } - fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> { - self.const_undef(self.type_ix(0)) - } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index c0b8d2181..356c03ee3 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -127,7 +127,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // // We could remove this hack whenever we decide to drop macOS 10.10 support. if self.tcx.sess.target.options.is_like_osx { - // The `inspect` method is okay here because we checked relocations, and + // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state // (not as part of the interpreter execution). // @@ -296,17 +296,17 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> { let alloc = alloc.inner(); - let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); + let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, alloc_id) in alloc.relocations().iter() { + for &(offset, alloc_id) in alloc.provenance().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - // This `inspect` is okay since we have checked that it is not within a relocation, it + // This `inspect` is okay since we have checked that it is not within a pointer with provenance, it // is within the bounds of the allocation, and it doesn't affect interpreter execution // (we inspect the result after interpreter execution). Any undef byte is replaced with // some arbitrary byte value. @@ -319,7 +319,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl read_target_uint( dl.endian, // This `inspect` is okay since it is within the bounds of the allocation, it doesn't // affect interpreter execution (we inspect the result after interpreter execution), - // and we properly interpret the relocation as a relocation pointer offset. + // and we properly interpret the provenance as a relocation pointer offset. alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ) .expect("const_alloc_to_llvm: could not read relocation pointer") @@ -336,7 +336,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl } if alloc.len() >= next_offset { let range = next_offset..alloc.len(); - // This `inspect` is okay since we have check that it is after all relocations, it is + // This `inspect` is okay since we have check that it is after all provenance, it is // within the bounds of the allocation, and it doesn't affect interpreter execution (we // inspect the result after interpreter execution). Any undef byte is replaced with some // arbitrary byte value. diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 5fbdedac0..02cedd464 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); - if let PassMode::Cast(ty) = fn_abi.ret.mode { + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); } let load = self.volatile_load(ptr.get_type(), ptr); @@ -309,6 +309,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { return; } + sym::ptr_mask => { + let usize_type = self.context.new_type::(); + let void_ptr_type = self.context.new_type::<*const ()>(); + + let ptr = args[0].immediate(); + let mask = args[1].immediate(); + + let addr = self.bitcast(ptr, usize_type); + let masked = self.and(addr, mask); + self.bitcast(masked, void_ptr_type) + }, + _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, @@ -320,7 +332,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty) = fn_abi.ret.mode { + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); @@ -416,7 +428,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } - else if let PassMode::Cast(cast) = self.mode { + else if let PassMode::Cast(ref cast, _) = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -481,7 +493,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { extra_attrs: Some(_), .. } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); }, - PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => { + PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => { let next_arg = next(); self.store(bx, next_arg, dst); }, diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 8a206c036..223466fb9 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -19,6 +19,7 @@ #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] +extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index f9a5463ef..74115353a 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -13,6 +13,7 @@ cstr = "0.2" libc = "0.2" libloading = "0.7.1" measureme = "10.0.0" +object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] } tracing = "0.1" rustc_middle = { path = "../rustc_middle" } rustc-demangle = "0.1.21" diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 9eb3574e7..26f5225f6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -19,6 +19,7 @@ use rustc_target::abi::call::ArgAbi; pub use rustc_target::abi::call::*; use rustc_target::abi::{self, HasDataLayout, Int}; pub use rustc_target::spec::abi::Abi; +use rustc_target::spec::SanitizerSet; use libc::c_uint; use smallvec::SmallVec; @@ -90,6 +91,13 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&' if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) { attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx)); } + } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { + // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects + // memory sanitizer's behavior. + + if regular.contains(ArgAttribute::NoUndef) { + attrs.push(llvm::AttributeKind::NoUndef.create_attr(cx.llcx)); + } } attrs @@ -213,7 +221,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) } else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); - } else if let PassMode::Cast(cast) = self.mode { + } else if let PassMode::Cast(cast, _) = &self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -283,7 +291,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } PassMode::Direct(_) | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } - | PassMode::Cast(_) => { + | PassMode::Cast(..) => { let next_arg = next(); self.store(bx, next_arg, dst); } @@ -325,20 +333,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { // Ignore "extra" args from the call site for C variadic functions. // Only the "fixed" args are part of the LLVM function signature. - let args = if self.c_variadic { &self.args[..self.fixed_count] } else { &self.args }; + let args = + if self.c_variadic { &self.args[..self.fixed_count as usize] } else { &self.args }; - let args_capacity: usize = args.iter().map(|arg| - if arg.pad.is_some() { 1 } else { 0 } + - if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } - ).sum(); + // This capacity calculation is approximate. let mut llargument_tys = Vec::with_capacity( - if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity, + self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }, ); - let llreturn_ty = match self.ret.mode { + let llreturn_ty = match &self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), - PassMode::Cast(cast) => cast.llvm_type(cx), + PassMode::Cast(cast, _) => cast.llvm_type(cx), PassMode::Indirect { .. } => { llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() @@ -346,12 +352,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { }; for arg in args { - // add padding - if let Some(ty) = arg.pad { - llargument_tys.push(ty.llvm_type(cx)); - } - - let llarg_ty = match arg.mode { + let llarg_ty = match &arg.mode { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { @@ -366,7 +367,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Cast(cast) => cast.llvm_type(cx), + PassMode::Cast(cast, pad_i32) => { + // add padding + if *pad_i32 { + llargument_tys.push(Reg::i32().llvm_type(cx)); + } + cast.llvm_type(cx) + } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { cx.type_ptr_to(arg.memory_ty(cx)) } @@ -426,46 +433,46 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { i += 1; i - 1 }; - match self.ret.mode { - PassMode::Direct(ref attrs) => { + match &self.ret.mode { + PassMode::Direct(attrs) => { attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } - PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { + PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(attrs); let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx)); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); } - PassMode::Cast(cast) => { + PassMode::Cast(cast, _) => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } _ => {} } - for arg in &self.args { - if arg.pad.is_some() { - apply(&ArgAttributes::new()); - } - match arg.mode { + for arg in self.args.iter() { + match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => { + PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { let i = apply(attrs); let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx)); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]); } - PassMode::Direct(ref attrs) - | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => { + PassMode::Direct(attrs) + | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { apply(attrs); } - PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => { + PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => { assert!(!on_stack); apply(attrs); apply(extra_attrs); } - PassMode::Pair(ref a, ref b) => { + PassMode::Pair(a, b) => { apply(a); apply(b); } - PassMode::Cast(cast) => { + PassMode::Cast(cast, pad_i32) => { + if *pad_i32 { + apply(&ArgAttributes::new()); + } apply(&cast.attrs); } } @@ -488,17 +495,17 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { i += 1; i - 1 }; - match self.ret.mode { - PassMode::Direct(ref attrs) => { + match &self.ret.mode { + PassMode::Direct(attrs) => { attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); } - PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { + PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(bx.cx, attrs); let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx)); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); } - PassMode::Cast(cast) => { + PassMode::Cast(cast, _) => { cast.attrs.apply_attrs_to_callsite( llvm::AttributePlace::ReturnValue, &bx.cx, @@ -517,13 +524,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } } - for arg in &self.args { - if arg.pad.is_some() { - apply(bx.cx, &ArgAttributes::new()); - } - match arg.mode { + for arg in self.args.iter() { + match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => { + PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { let i = apply(bx.cx, attrs); let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx)); attributes::apply_to_callsite( @@ -532,23 +536,22 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { &[byval], ); } - PassMode::Direct(ref attrs) - | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => { + PassMode::Direct(attrs) + | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { apply(bx.cx, attrs); } - PassMode::Indirect { - ref attrs, - extra_attrs: Some(ref extra_attrs), - on_stack: _, - } => { + PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => { apply(bx.cx, attrs); apply(bx.cx, extra_attrs); } - PassMode::Pair(ref a, ref b) => { + PassMode::Pair(a, b) => { apply(bx.cx, a); apply(bx.cx, b); } - PassMode::Cast(cast) => { + PassMode::Cast(cast, pad_i32) => { + if *pad_i32 { + apply(bx.cx, &ArgAttributes::new()); + } apply(bx.cx, &cast.attrs); } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a53946995..5202ac697 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -3,7 +3,6 @@ use crate::builder::Builder; use crate::common::Funclet; use crate::context::CodegenCx; use crate::llvm; -use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -20,7 +19,6 @@ use rustc_target::asm::*; use libc::{c_char, c_uint}; use smallvec::SmallVec; -use tracing::debug; impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_inline_asm( @@ -419,13 +417,6 @@ pub(crate) fn inline_asm_call<'ll>( let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len()); debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { - if unwind && llvm_util::get_version() < (13, 0, 0) { - bx.cx.sess().span_fatal( - line_spans[0], - "unwinding from inline assembly is only supported on llvm >= 13.", - ); - } - let v = llvm::LLVMRustInlineAsm( fty, asm.as_ptr().cast(), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index aabbe8ac2..eff2436d4 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -35,6 +35,10 @@ pub fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[&Attrib /// Get LLVM attribute for the provided inline heuristic. #[inline] fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> { + if !cx.tcx.sess.opts.unstable_opts.inline_llvm { + // disable LLVM inlining + return Some(AttributeKind::NoInline.create_attr(cx.llcx)); + } match inline { InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)), InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)), @@ -386,7 +390,8 @@ pub fn from_fn_attrs<'ll, 'tcx>( ) { let span = cx .tcx - .get_attr(instance.def_id(), sym::target_feature) + .get_attrs(instance.def_id(), sym::target_feature) + .next() .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); let msg = format!( "the target features {} must all be either enabled or disabled together", diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 27039cda2..ed96355a0 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -8,10 +8,11 @@ use std::path::{Path, PathBuf}; use std::ptr; use std::str; +use crate::common; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; -use rustc_session::cstore::{DllCallingConvention, DllImport}; +use rustc_session::cstore::DllImport; use rustc_session::Session; /// Helper for adding many files to an archive. @@ -103,29 +104,28 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { lib_name: &str, dll_imports: &[DllImport], tmpdir: &Path, + is_direct_dependency: bool, ) -> PathBuf { + let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; let output_path = { let mut output_path: PathBuf = tmpdir.to_path_buf(); - output_path.push(format!("{}_imports", lib_name)); + output_path.push(format!("{}{}", lib_name, name_suffix)); output_path.with_extension("lib") }; let target = &sess.target; - let mingw_gnu_toolchain = target.vendor == "pc" - && target.os == "windows" - && target.env == "gnu" - && target.abi.is_empty(); + let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); let import_name_and_ordinal_vector: Vec<(String, Option)> = dll_imports .iter() .map(|import: &DllImport| { if sess.target.arch == "x86" { ( - LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain), - import.ordinal, + common::i686_decorated_name(import, mingw_gnu_toolchain, false), + import.ordinal(), ) } else { - (import.name.to_string(), import.ordinal) + (import.name.to_string(), import.ordinal()) } }) .collect(); @@ -136,7 +136,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def"); + let def_file_path = + tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", @@ -159,6 +160,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { } }; + // --no-leading-underscore: For the `import_name_type` feature to work, we need to be + // able to control the *exact* spelling of each of the symbols that are being imported: + // hence we don't want `dlltool` adding leading underscores automatically. let dlltool = find_binutils_dlltool(sess); let result = std::process::Command::new(dlltool) .args([ @@ -168,6 +172,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { lib_name, "-l", output_path.to_str().unwrap(), + "--no-leading-underscore", ]) .output(); @@ -188,10 +193,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { let output_path_z = rustc_fs_util::path_to_c_string(&output_path); - tracing::trace!("invoking LLVMRustWriteImportLibrary"); - tracing::trace!(" dll_name {:#?}", dll_name_z); - tracing::trace!(" output_path {}", output_path.display()); - tracing::trace!( + trace!("invoking LLVMRustWriteImportLibrary"); + trace!(" dll_name {:#?}", dll_name_z); + trace!(" output_path {}", output_path.display()); + trace!( " import names: {}", dll_imports .iter() @@ -322,22 +327,6 @@ impl<'a> LlvmArchiveBuilder<'a> { ret } } - - fn i686_decorated_name(import: &DllImport, mingw: bool) -> String { - let name = import.name; - let prefix = if mingw { "" } else { "_" }; - - match import.calling_convention { - DllCallingConvention::C => format!("{}{}", prefix, name), - DllCallingConvention::Stdcall(arg_list_size) => { - format!("{}{}@{}", prefix, name, arg_list_size) - } - DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size), - DllCallingConvention::Vectorcall(arg_list_size) => { - format!("{}@@{}", name, arg_list_size) - } - } - } } fn string_to_io_error(s: String) -> io::Error { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 3731c6bcf..a89df00e2 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -1,15 +1,16 @@ use crate::back::write::{ self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers, }; -use crate::llvm::archive_ro::ArchiveRO; use crate::llvm::{self, build_string, False, True}; use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm}; +use object::read::archive::ArchiveFile; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::memmap::Mmap; use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; @@ -17,7 +18,6 @@ use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, Lto}; -use tracing::{debug, info}; use std::ffi::{CStr, CString}; use std::fs::File; @@ -107,14 +107,24 @@ fn prepare_lto( .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); } - let archive = ArchiveRO::open(path).expect("wanted an rlib"); + let archive_data = unsafe { + Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib")) + .expect("couldn't map rlib") + }; + let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); let obj_files = archive - .iter() - .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c)))) + .members() + .filter_map(|child| { + child.ok().and_then(|c| { + std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)) + }) + }) .filter(|&(name, _)| looks_like_rust_object_file(name)); for (name, child) in obj_files { info!("adding bitcode from {}", name); - match get_bitcode_slice_from_object_data(child.data()) { + match get_bitcode_slice_from_object_data( + child.data(&*archive_data).expect("corrupt rlib"), + ) { Ok(data) => { let module = SerializedModule::FromRlib(data.to_vec()); upstream_modules.push((module, CString::new(name).unwrap())); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 534d32e8a..a695df840 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -5,7 +5,7 @@ use crate::back::profiling::{ use crate::base; use crate::common; use crate::consts; -use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; +use crate::llvm::{self, DiagnosticInfo, PassManager}; use crate::llvm_util; use crate::type_::Type; use crate::LlvmCodegenBackend; @@ -28,7 +28,6 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo}; -use tracing::debug; use libc::{c_char, c_int, c_uint, c_void, size_t}; use std::ffi::CString; @@ -304,7 +303,6 @@ impl<'a> DiagnosticHandlers<'a> { remark_passes.as_ptr(), remark_passes.len(), ); - llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast()); DiagnosticHandlers { data, llcx, old_handler } } } @@ -312,9 +310,7 @@ impl<'a> DiagnosticHandlers<'a> { impl<'a> Drop for DiagnosticHandlers<'a> { fn drop(&mut self) { - use std::ptr::null_mut; unsafe { - llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut()); llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler); drop(Box::from_raw(self.data)); } @@ -342,16 +338,6 @@ fn report_inline_asm( cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); } -unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) { - if user.is_null() { - return; - } - let (cgcx, _) = *(user as *const (&CodegenContext, &Handler)); - - let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag); - report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source); -} - unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { if user.is_null() { return; @@ -423,6 +409,14 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option { .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) } +fn get_instr_profile_output_path(config: &ModuleConfig) -> Option { + if config.instrument_coverage { + Some(CString::new("default_%m_%p.profraw").unwrap()) + } else { + None + } +} + pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( cgcx: &CodegenContext, diag_handler: &Handler, @@ -438,6 +432,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( let pgo_use_path = get_pgo_use_path(config); let pgo_sample_use_path = get_pgo_sample_use_path(config); let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO; + let instr_profile_output_path = get_instr_profile_output_path(config); // Sanitizer instrumentation is only inserted during the pre-link optimization stage. let sanitizer_options = if !is_lto { Some(llvm::SanitizerOptions { @@ -488,6 +483,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), config.instrument_coverage, + instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), config.instrument_gcov, pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), config.debug_info_for_profiling, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d3096c73a..63b63c6a1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -3,7 +3,6 @@ use crate::common::Funclet; use crate::context::CodegenCx; use crate::llvm::{self, BasicBlock, False}; use crate::llvm::{AtomicOrdering, AtomicRmwBinOp, SynchronizationScope}; -use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -28,7 +27,6 @@ use std::ffi::CStr; use std::iter; use std::ops::Deref; use std::ptr; -use tracing::{debug, instrument}; // All Builders must have an llfn associated with them #[must_use] @@ -726,11 +724,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, UNNAMED) } } - fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { + fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { self.fptoint_sat(false, val, dest_ty) } - fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> { + fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { self.fptoint_sat(true, val, dest_ty) } @@ -1038,25 +1036,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { dst: &'ll Value, cmp: &'ll Value, src: &'ll Value, - mut order: rustc_codegen_ssa::common::AtomicOrdering, + order: rustc_codegen_ssa::common::AtomicOrdering, failure_order: rustc_codegen_ssa::common::AtomicOrdering, weak: bool, ) -> &'ll Value { let weak = if weak { llvm::True } else { llvm::False }; - if llvm_util::get_version() < (13, 0, 0) { - use rustc_codegen_ssa::common::AtomicOrdering::*; - // Older llvm has the pre-C++17 restriction on - // success and failure memory ordering, - // requiring the former to be at least as strong as the latter. - // So, for llvm 12, we upgrade the success ordering to a stronger - // one if necessary. - match (order, failure_order) { - (Relaxed, Acquire) => order = Acquire, - (Release, Acquire) => order = AcquireRelease, - (_, SequentiallyConsistent) => order = SequentiallyConsistent, - _ => {} - } - } unsafe { llvm::LLVMRustBuildAtomicCmpXchg( self.llbuilder, @@ -1444,51 +1428,32 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } } - fn fptoint_sat_broken_in_llvm(&self) -> bool { - match self.tcx.sess.target.arch.as_ref() { - // FIXME - https://bugs.llvm.org/show_bug.cgi?id=50083 - "riscv64" => llvm_util::get_version() < (13, 0, 0), - _ => false, - } - } - - fn fptoint_sat( - &mut self, - signed: bool, - val: &'ll Value, - dest_ty: &'ll Type, - ) -> Option<&'ll Value> { - if !self.fptoint_sat_broken_in_llvm() { - let src_ty = self.cx.val_ty(val); - let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector - { - assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); - ( - self.cx.element_type(src_ty), - self.cx.element_type(dest_ty), - Some(self.cx.vector_length(src_ty)), - ) - } else { - (src_ty, dest_ty, None) - }; - let float_width = self.cx.float_width(float_ty); - let int_width = self.cx.int_width(int_ty); - - let instr = if signed { "fptosi" } else { "fptoui" }; - let name = if let Some(vector_length) = vector_length { - format!( - "llvm.{}.sat.v{}i{}.v{}f{}", - instr, vector_length, int_width, vector_length, float_width - ) - } else { - format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width) - }; - let f = - self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty)); - Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None)) + fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { + let src_ty = self.cx.val_ty(val); + let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector { + assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); + ( + self.cx.element_type(src_ty), + self.cx.element_type(dest_ty), + Some(self.cx.vector_length(src_ty)), + ) } else { - None - } + (src_ty, dest_ty, None) + }; + let float_width = self.cx.float_width(float_ty); + let int_width = self.cx.int_width(int_ty); + + let instr = if signed { "fptosi" } else { "fptoui" }; + let name = if let Some(vector_length) = vector_length { + format!( + "llvm.{}.sat.v{}i{}.v{}f{}", + instr, vector_length, int_width, vector_length, float_width + ) + } else { + format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width) + }; + let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty)); + self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None) } pub(crate) fn landing_pad( diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 72155d874..b83c1e8f0 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -6,11 +6,11 @@ use crate::abi::FnAbiLlvmExt; use crate::attributes; +use crate::common; use crate::context::CodegenCx; use crate::llvm; use crate::value::Value; use rustc_codegen_ssa::traits::*; -use tracing::debug; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::{self, Instance, TypeVisitable}; @@ -79,13 +79,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> llfn } } else { - let llfn = cx.declare_fn(sym, fn_abi); + let instance_def_id = instance.def_id(); + let llfn = if tcx.sess.target.arch == "x86" && + let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym) + { + cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi) + } else { + cx.declare_fn(sym, fn_abi) + }; debug!("get_fn: not casting pointer!"); attributes::from_fn_attrs(cx, llfn, instance); - let instance_def_id = instance.def_id(); - // Apply an appropriate linkage/visibility value to our item that we // just declared. // diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index fb4da9a5f..acee9134f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -10,13 +10,17 @@ use crate::value::Value; use rustc_ast::Mutability; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; +use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::TyCtxt; +use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType}; use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size}; +use rustc_target::spec::Target; use libc::{c_char, c_uint}; -use tracing::debug; +use std::fmt::Write; /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". @@ -211,7 +215,11 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn const_to_opt_uint(&self, v: &'ll Value) -> Option { - try_as_const_integral(v).map(|v| unsafe { llvm::LLVMConstIntGetZExtValue(v) }) + try_as_const_integral(v).and_then(|v| unsafe { + let mut i = 0u64; + let success = llvm::LLVMRustConstIntGetZExtValue(v, &mut i); + success.then_some(i) + }) } fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option { @@ -222,10 +230,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { }) } - fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value { - self.const_undef(self.type_ix(0)) - } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { @@ -357,3 +361,74 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> { unsafe { llvm::LLVMIsAConstantInt(v) } } + +pub(crate) fn get_dllimport<'tcx>( + tcx: TyCtxt<'tcx>, + id: DefId, + name: &str, +) -> Option<&'tcx DllImport> { + tcx.native_library(id) + .map(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name)) + .flatten() +} + +pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool { + target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() +} + +pub(crate) fn i686_decorated_name( + dll_import: &DllImport, + mingw: bool, + disable_name_mangling: bool, +) -> String { + let name = dll_import.name.as_str(); + + let (add_prefix, add_suffix) = match dll_import.import_name_type { + Some(PeImportNameType::NoPrefix) => (false, true), + Some(PeImportNameType::Undecorated) => (false, false), + _ => (true, true), + }; + + // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__). + let mut decorated_name = String::with_capacity(name.len() + 6); + + if disable_name_mangling { + // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled. + decorated_name.push('\x01'); + } + + let prefix = if add_prefix && dll_import.is_fn { + match dll_import.calling_convention { + DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None, + DllCallingConvention::Stdcall(_) => (!mingw + || dll_import.import_name_type == Some(PeImportNameType::Decorated)) + .then_some('_'), + DllCallingConvention::Fastcall(_) => Some('@'), + } + } else if !dll_import.is_fn && !mingw { + // For static variables, prefix with '_' on MSVC. + Some('_') + } else { + None + }; + if let Some(prefix) = prefix { + decorated_name.push(prefix); + } + + decorated_name.push_str(name); + + if add_suffix && dll_import.is_fn { + match dll_import.calling_convention { + DllCallingConvention::C => {} + DllCallingConvention::Stdcall(arg_list_size) + | DllCallingConvention::Fastcall(arg_list_size) => { + write!(&mut decorated_name, "@{}", arg_list_size).unwrap(); + } + DllCallingConvention::Vectorcall(arg_list_size) => { + write!(&mut decorated_name, "@@{}", arg_list_size).unwrap(); + } + } + } + + decorated_name +} diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 18467e370..a559f7f3d 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -1,5 +1,5 @@ use crate::base; -use crate::common::CodegenCx; +use crate::common::{self, CodegenCx}; use crate::debuginfo; use crate::llvm::{self, True}; use crate::llvm_util; @@ -23,16 +23,15 @@ use rustc_target::abi::{ AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange, }; use std::ops::Range; -use tracing::debug; pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value { let alloc = alloc.inner(); - let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); + let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; - // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`, - // so `range` must be within the bounds of `alloc` and not contain or overlap a relocation. + // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`, so `range` + // must be within the bounds of `alloc` and not contain or overlap a pointer provenance. fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>( llvals: &mut Vec<&'ll Value>, cx: &'a CodegenCx<'ll, 'b>, @@ -79,12 +78,12 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< } let mut next_offset = 0; - for &(offset, alloc_id) in alloc.relocations().iter() { + for &(offset, alloc_id) in alloc.provenance().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - // This `inspect` is okay since we have checked that it is not within a relocation, it + // This `inspect` is okay since we have checked that there is no provenance, it // is within the bounds of the allocation, and it doesn't affect interpreter execution // (we inspect the result after interpreter execution). append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, next_offset..offset); @@ -93,7 +92,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< dl.endian, // This `inspect` is okay since it is within the bounds of the allocation, it doesn't // affect interpreter execution (we inspect the result after interpreter execution), - // and we properly interpret the relocation as a relocation pointer offset. + // and we properly interpret the provenance as a relocation pointer offset. alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ) .expect("const_alloc_to_llvm: could not read relocation pointer") @@ -121,7 +120,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< } if alloc.len() >= next_offset { let range = next_offset..alloc.len(); - // This `inspect` is okay since we have check that it is after all relocations, it is + // This `inspect` is okay since we have check that it is after all provenance, it is // within the bounds of the allocation, and it doesn't affect interpreter execution (we // inspect the result after interpreter execution). append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range); @@ -160,7 +159,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, - span_def_id: DefId, + def_id: DefId, ) -> &'ll Value { let llty = cx.layout_of(ty).llvm_type(cx); if let Some(linkage) = attrs.linkage { @@ -175,7 +174,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( cx.layout_of(mt.ty).llvm_type(cx) } else { cx.sess().span_fatal( - cx.tcx.def_span(span_def_id), + cx.tcx.def_span(def_id), "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", ) }; @@ -194,7 +193,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( real_name.push_str(sym); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { cx.sess().span_fatal( - cx.tcx.def_span(span_def_id), + cx.tcx.def_span(def_id), &format!("symbol `{}` is already defined", &sym), ) }); @@ -202,6 +201,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( llvm::LLVMSetInitializer(g2, g1); g2 } + } else if cx.tcx.sess.target.arch == "x86" && + let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym) + { + cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty) } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global @@ -475,7 +478,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // // We could remove this hack whenever we decide to drop macOS 10.10 support. if self.tcx.sess.target.is_like_osx { - // The `inspect` method is okay here because we checked relocations, and + // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state // (not as part of the interpreter execution). // @@ -483,7 +486,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // happens to be zero. Instead, we should only check the value of defined bytes // and set all undefined bytes to zero if this allocation is headed for the // BSS. - let all_bytes_are_zero = alloc.relocations().is_empty() + let all_bytes_are_zero = alloc.provenance().is_empty() && alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()) .iter() @@ -507,9 +510,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { section.as_str().as_ptr().cast(), section.as_str().len() as c_uint, ); - assert!(alloc.relocations().is_empty()); + assert!(alloc.provenance().is_empty()); - // The `inspect` method is okay here because we checked relocations, and + // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state (not // as part of the interpreter execution). let bytes = diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5857b83f6..67ffc7cb9 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -142,17 +142,6 @@ pub unsafe fn create_module<'ll>( let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); - if llvm_version < (13, 0, 0) { - if sess.target.arch == "powerpc64" { - target_data_layout = target_data_layout.replace("-S128", ""); - } - if sess.target.arch == "wasm32" { - target_data_layout = "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(); - } - if sess.target.arch == "wasm64" { - target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string(); - } - } if llvm_version < (14, 0, 0) { if sess.target.llvm_target == "i686-pc-windows-msvc" || sess.target.llvm_target == "i586-pc-windows-msvc" @@ -897,6 +886,9 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void); ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void); } + + ifn!("llvm.ptrmask", fn(i8p, t_isize) -> i8p); + None } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 58f391692..0d1df6fb1 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -16,8 +16,6 @@ use rustc_middle::ty::TyCtxt; use std::ffi::CString; -use tracing::debug; - /// Generates and exports the Coverage Map. /// /// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 98ba38356..964a632b6 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -28,7 +28,6 @@ use std::cell::RefCell; use std::ffi::CString; use std::iter; -use tracing::debug; pub mod mapgen; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bd84100e0..163ccd946 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -42,7 +42,6 @@ use rustc_span::{self, FileNameDisplayPreference, SourceFile}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::{Align, Size}; use smallvec::smallvec; -use tracing::debug; use libc::{c_char, c_longlong, c_uint}; use std::borrow::Cow; @@ -51,7 +50,6 @@ use std::hash::{Hash, Hasher}; use std::iter; use std::path::{Path, PathBuf}; use std::ptr; -use tracing::instrument; impl PartialEq for llvm::Metadata { fn eq(&self, other: &Self) -> bool { @@ -114,6 +112,7 @@ macro_rules! return_if_di_node_created_in_meantime { } /// Extract size and alignment from a TyAndLayout. +#[inline] fn size_and_align_of<'tcx>(ty_and_layout: TyAndLayout<'tcx>) -> (Size, Align) { (ty_and_layout.size, ty_and_layout.align.abi) } @@ -1499,24 +1498,18 @@ fn vcall_visibility_metadata<'ll, 'tcx>( // If there is not LTO and the visibility in public, we have to assume that the vtable can // be seen from anywhere. With multiple CGUs, the vtable is quasi-public. (Lto::No | Lto::ThinLocal, Visibility::Public, _) - | (Lto::No, Visibility::Restricted(_) | Visibility::Invisible, false) => { - VCallVisibility::Public - } + | (Lto::No, Visibility::Restricted(_), false) => VCallVisibility::Public, // With LTO and a quasi-public visibility, the usages of the functions of the vtable are // all known by the `LinkageUnit`. // FIXME: LLVM only supports this optimization for `Lto::Fat` currently. Once it also // supports `Lto::Thin` the `VCallVisibility` may have to be adjusted for those. (Lto::Fat | Lto::Thin, Visibility::Public, _) - | ( - Lto::ThinLocal | Lto::Thin | Lto::Fat, - Visibility::Restricted(_) | Visibility::Invisible, - false, - ) => VCallVisibility::LinkageUnit, + | (Lto::ThinLocal | Lto::Thin | Lto::Fat, Visibility::Restricted(_), false) => { + VCallVisibility::LinkageUnit + } // If there is only one CGU, private vtables can only be seen by that CGU/translation unit // and therefore we know of all usages of functions in the vtable. - (_, Visibility::Restricted(_) | Visibility::Invisible, true) => { - VCallVisibility::TranslationUnit - } + (_, Visibility::Restricted(_), true) => VCallVisibility::TranslationUnit, }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index d6e2c8ccd..129e336c7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -1,19 +1,21 @@ use std::borrow::Cow; use libc::c_uint; -use rustc_codegen_ssa::debuginfo::{ - type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo, +use rustc_codegen_ssa::{ + debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo}, + traits::ConstMethods, }; + +use rustc_index::vec::IndexVec; use rustc_middle::{ bug, ty::{ self, layout::{LayoutOf, TyAndLayout}, - util::Discr, - AdtDef, GeneratorSubsts, + AdtDef, GeneratorSubsts, Ty, }, }; -use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants}; +use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; use crate::{ @@ -21,9 +23,9 @@ use crate::{ debuginfo::{ metadata::{ build_field_di_node, closure_saved_names_of_captured_variables, - enums::tag_base_type, - file_metadata, generator_layout_and_saved_local_names, size_and_align_of, - type_map::{self, UniqueTypeId}, + enums::{tag_base_type, DiscrResult}, + file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node, + type_map::{self, Stub, UniqueTypeId}, unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER, }, @@ -35,59 +37,161 @@ use crate::{ }, }; -/// In CPP-like mode, we generate a union of structs for each variant and an -/// explicit discriminant field roughly equivalent to the following C/C++ code: +// The names of the associated constants in each variant wrapper struct. +// These have to match up with the names being used in `intrinsic.natvis`. +const ASSOC_CONST_DISCR_NAME: &str = "NAME"; +const ASSOC_CONST_DISCR_EXACT: &str = "DISCR_EXACT"; +const ASSOC_CONST_DISCR_BEGIN: &str = "DISCR_BEGIN"; +const ASSOC_CONST_DISCR_END: &str = "DISCR_END"; + +const ASSOC_CONST_DISCR128_EXACT_LO: &str = "DISCR128_EXACT_LO"; +const ASSOC_CONST_DISCR128_EXACT_HI: &str = "DISCR128_EXACT_HI"; +const ASSOC_CONST_DISCR128_BEGIN_LO: &str = "DISCR128_BEGIN_LO"; +const ASSOC_CONST_DISCR128_BEGIN_HI: &str = "DISCR128_BEGIN_HI"; +const ASSOC_CONST_DISCR128_END_LO: &str = "DISCR128_END_LO"; +const ASSOC_CONST_DISCR128_END_HI: &str = "DISCR128_END_HI"; + +// The name of the tag field in the top-level union +const TAG_FIELD_NAME: &str = "tag"; +const TAG_FIELD_NAME_128_LO: &str = "tag128_lo"; +const TAG_FIELD_NAME_128_HI: &str = "tag128_hi"; + +// We assign a "virtual" discriminant value to the sole variant of +// a single-variant enum. +const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; + +/// In CPP-like mode, we generate a union with a field for each variant and an +/// explicit tag field. The field of each variant has a struct type +/// that encodes the discrimiant of the variant and it's data layout. +/// The union also has a nested enumeration type that is only used for encoding +/// variant names in an efficient way. Its enumerator values do _not_ correspond +/// to the enum's discriminant values. +/// It's roughly equivalent to the following C/C++ code: /// /// ```c -/// union enum$<{fully-qualified-name}> { -/// struct {variant 0 name} { -/// +/// union enum2$<{fully-qualified-name}> { +/// struct Variant0 { +/// struct {name-of-variant-0} { +/// +/// } value; +/// +/// static VariantNames NAME = {name-of-variant-0}; +/// static int_type DISCR_EXACT = {discriminant-of-variant-0}; /// } variant0; +/// /// -/// {name} discriminant; +/// +/// int_type tag; +/// +/// enum VariantNames { +/// = 0, // The numeric values are variant index, +/// = 1, // not discriminant values. +/// = 2, +/// ... +/// } /// } /// ``` /// -/// As you can see, the type name is wrapped `enum$`. This way we can have a -/// single NatVis rule for handling all enums. +/// As you can see, the type name is wrapped in `enum2$<_>`. This way we can +/// have a single NatVis rule for handling all enums. The `2` in `enum2$<_>` +/// is an encoding version tag, so that debuggers can decide to decode this +/// differently than the previous `enum$<_>` encoding emitted by earlier +/// compiler versions. /// -/// At the LLVM IR level this looks like +/// Niche-tag enums have one special variant, usually called the +/// "untagged variant". This variant has a field that +/// doubles as the tag of the enum. The variant is active when the value of +/// that field is within a pre-defined range. Therefore the variant struct +/// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in +/// that case. Both `DISCR_BEGIN` and `DISCR_END` are inclusive bounds. +/// Note that these ranges can wrap around, so that `DISCR_END < DISCR_BEGIN`. /// -/// ```txt -/// DW_TAG_union_type (top-level type for enum) -/// DW_TAG_member (member for variant 1) -/// DW_TAG_member (member for variant 2) -/// DW_TAG_member (member for variant 3) -/// DW_TAG_structure_type (type of variant 1) -/// DW_TAG_structure_type (type of variant 2) -/// DW_TAG_structure_type (type of variant 3) -/// DW_TAG_enumeration_type (type of tag) -/// ``` +/// Single-variant enums don't actually have a tag field. In this case we +/// emit a static tag field (that always has the value 0) so we can use the +/// same representation (and NatVis). /// -/// The above encoding applies for enums with a direct tag. For niche-tag we have to do things -/// differently in order to allow a NatVis visualizer to extract all the information needed: -/// We generate a union of two fields, one for the dataful variant -/// and one that just points to the discriminant (which is some field within the dataful variant). -/// We also create a DW_TAG_enumeration_type DIE that contains tag values for the non-dataful -/// variants and make the discriminant field that type. We then use NatVis to render the enum type -/// correctly in Windbg/VS. This will generate debuginfo roughly equivalent to the following C: +/// For niche-layout enums it's possible to have a 128-bit tag. NatVis, VS, and +/// WinDbg (the main targets for CPP-like debuginfo at the moment) don't support +/// 128-bit integers, so all values involved get split into two 64-bit fields. +/// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`, +/// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`, +/// and so on. /// -/// ```c -/// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> { -/// struct { -/// -/// } dataful_variant; -/// enum Discriminant$ { -/// -/// } discriminant; +/// +/// The following pseudocode shows how to decode an enum value in a debugger: +/// +/// ```text +/// +/// fn find_active_variant(enum_value) -> (VariantName, VariantValue) { +/// let is_128_bit = enum_value.has_field("tag128_lo"); +/// +/// if !is_128_bit { +/// // Note: `tag` can be a static field for enums with only one +/// // inhabited variant. +/// let tag = enum_value.field("tag").value; +/// +/// // For each variant, check if it is a match. Only one of them will match, +/// // so if we find it we can return it immediately. +/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) { +/// if variant_field.has_field("DISCR_EXACT") { +/// // This variant corresponds to a single tag value +/// if variant_field.field("DISCR_EXACT").value == tag { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } else { +/// // This is a range variant +/// let begin = variant_field.field("DISCR_BEGIN"); +/// let end = variant_field.field("DISCR_END"); +/// +/// if is_in_range(tag, begin, end) { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } +/// } +/// } else { +/// // Basically the same as with smaller tags, we just have to +/// // stitch the values together. +/// let tag: u128 = (enum_value.field("tag128_lo").value as u128) | +/// (enum_value.field("tag128_hi").value as u128 << 64); +/// +/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) { +/// if variant_field.has_field("DISCR128_EXACT_LO") { +/// let discr_exact = (variant_field.field("DISCR128_EXACT_LO" as u128) | +/// (variant_field.field("DISCR128_EXACT_HI") as u128 << 64); +/// +/// // This variant corresponds to a single tag value +/// if discr_exact.value == tag { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } else { +/// // This is a range variant +/// let begin = (variant_field.field("DISCR128_BEGIN_LO").value as u128) | +/// (variant_field.field("DISCR128_BEGIN_HI").value as u128 << 64); +/// let end = (variant_field.field("DISCR128_END_LO").value as u128) | +/// (variant_field.field("DISCR128_END_HI").value as u128 << 64); +/// +/// if is_in_range(tag, begin, end) { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } +/// } +/// } +/// +/// // We should have found an active variant at this point. +/// unreachable!(); /// } -/// ``` /// -/// The NatVis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>` -/// and evaluates `this.discriminant`. If the value is between the min niche and max -/// niche, then the enum is in the dataful variant and `this.dataful_variant` is -/// rendered. Otherwise, the enum is in one of the non-dataful variants. In that -/// case, we just need to render the name of the `this.discriminant` enum. +/// // Check if a value is within the given range +/// // (where the range might wrap around the value space) +/// fn is_in_range(value, start, end) -> bool { +/// if start < end { +/// value >= start && value <= end +/// } else { +/// value >= start || value <= end +/// } +/// } +/// +/// ``` pub(super) fn build_enum_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, @@ -135,27 +239,28 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( ref variants, tag_field, .. - } => build_union_fields_for_direct_tag_enum( + } => build_union_fields_for_enum( cx, enum_adt_def, enum_type_and_layout, enum_type_di_node, - &mut variants.indices(), + variants.indices(), tag_field, + None, ), Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, ref variants, tag_field, .. - } => build_union_fields_for_niche_tag_enum( + } => build_union_fields_for_enum( cx, enum_adt_def, enum_type_and_layout, enum_type_di_node, - dataful_variant, - &mut variants.indices(), + variants.indices(), tag_field, + Some(untagged_variant), ), } }, @@ -217,137 +322,344 @@ fn build_single_variant_union_fields<'ll, 'tcx>( let variant_layout = enum_type_and_layout.for_variant(cx, variant_index); let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( cx, - enum_type_and_layout.ty, + enum_type_and_layout, enum_type_di_node, variant_index, enum_adt_def.variant(variant_index), variant_layout, ); - // NOTE: The field name of the union is the same as the variant name, not "variant0". - let variant_name = enum_adt_def.variant(variant_index).name.as_str(); + let tag_base_type = cx.tcx.types.u32; + let tag_base_type_di_node = type_di_node(cx, tag_base_type); + let tag_base_type_align = cx.align_of(tag_base_type); + + let variant_names_type_di_node = build_variant_names_type_di_node( + cx, + enum_type_di_node, + std::iter::once(( + variant_index, + Cow::from(enum_adt_def.variant(variant_index).name.as_str()), + )), + ); - smallvec![build_field_di_node( + let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node( cx, + enum_type_and_layout, enum_type_di_node, - variant_name, - // NOTE: We use the size and align of the entire type, not from variant_layout - // since the later is sometimes smaller (if it has fewer fields). - size_and_align_of(enum_type_and_layout), - Size::ZERO, - DIFlags::FlagZero, + variant_index, + None, variant_struct_type_di_node, - )] + variant_names_type_di_node, + tag_base_type_di_node, + tag_base_type, + DiscrResult::NoDiscriminant, + ); + + smallvec![ + build_field_di_node( + cx, + enum_type_di_node, + &variant_union_field_name(variant_index), + // NOTE: We use the size and align of the entire type, not from variant_layout + // since the later is sometimes smaller (if it has fewer fields). + size_and_align_of(enum_type_and_layout), + Size::ZERO, + DIFlags::FlagZero, + variant_struct_type_wrapper_di_node, + ), + unsafe { + llvm::LLVMRustDIBuilderCreateStaticMemberType( + DIB(cx), + enum_type_di_node, + TAG_FIELD_NAME.as_ptr().cast(), + TAG_FIELD_NAME.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + variant_names_type_di_node, + DIFlags::FlagZero, + Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)), + tag_base_type_align.bits() as u32, + ) + } + ] } -fn build_union_fields_for_direct_tag_enum<'ll, 'tcx>( +fn build_union_fields_for_enum<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, enum_adt_def: AdtDef<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>, enum_type_di_node: &'ll DIType, - variant_indices: &mut dyn Iterator, + variant_indices: impl Iterator + Clone, tag_field: usize, + untagged_variant_index: Option, ) -> SmallVec<&'ll DIType> { + let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); + + let variant_names_type_di_node = build_variant_names_type_di_node( + cx, + enum_type_di_node, + variant_indices.clone().map(|variant_index| { + let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); + (variant_index, variant_name) + }), + ); + let variant_field_infos: SmallVec> = variant_indices .map(|variant_index| { let variant_layout = enum_type_and_layout.for_variant(cx, variant_index); + let variant_def = enum_adt_def.variant(variant_index); + + let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( + cx, + enum_type_and_layout, + enum_type_di_node, + variant_index, + variant_def, + variant_layout, + ); + VariantFieldInfo { variant_index, - variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node( - cx, - enum_type_and_layout.ty, - enum_type_di_node, - variant_index, - enum_adt_def.variant(variant_index), - variant_layout, - ), + variant_struct_type_di_node, source_info: None, + discr: super::compute_discriminant_value(cx, enum_type_and_layout, variant_index), } }) .collect(); - let discr_type_name = cx.tcx.item_name(enum_adt_def.did()); - let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); - let discr_type_di_node = super::build_enumeration_type_di_node( - cx, - discr_type_name.as_str(), - tag_base_type, - &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { - (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str())) - }), - enum_type_di_node, - ); - build_union_fields_for_direct_tag_enum_or_generator( cx, enum_type_and_layout, enum_type_di_node, &variant_field_infos, - discr_type_di_node, + variant_names_type_di_node, + tag_base_type, tag_field, + untagged_variant_index, ) } -fn build_union_fields_for_niche_tag_enum<'ll, 'tcx>( +// The base type of the VariantNames DW_AT_enumeration_type is always the same. +// It has nothing to do with the tag of the enum and just has to be big enough +// to hold all variant names. +fn variant_names_enum_base_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> Ty<'tcx> { + cx.tcx.types.u32 +} + +/// This function builds a DW_AT_enumeration_type that contains an entry for +/// each variant. Note that this has nothing to do with the discriminant. The +/// numeric value of each enumerator corresponds to the variant index. The +/// type is only used for efficiently encoding the name of each variant in +/// debuginfo. +fn build_variant_names_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - enum_adt_def: AdtDef<'tcx>, - enum_type_and_layout: TyAndLayout<'tcx>, - enum_type_di_node: &'ll DIType, - dataful_variant_index: VariantIdx, - variant_indices: &mut dyn Iterator, - tag_field: usize, -) -> SmallVec<&'ll DIType> { - let dataful_variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( + containing_scope: &'ll DIType, + variants: impl Iterator)>, +) -> &'ll DIType { + // Create an enumerator for each variant. + super::build_enumeration_type_di_node( cx, - enum_type_and_layout.ty, - enum_type_di_node, - dataful_variant_index, - &enum_adt_def.variant(dataful_variant_index), - enum_type_and_layout.for_variant(cx, dataful_variant_index), - ); + "VariantNames", + variant_names_enum_base_type(cx), + variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32() as u64)), + containing_scope, + ) +} - let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); - // Create an DW_TAG_enumerator for each variant except the dataful one. - let discr_type_di_node = super::build_enumeration_type_di_node( +fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + enum_or_generator_type_and_layout: TyAndLayout<'tcx>, + enum_or_generator_type_di_node: &'ll DIType, + variant_index: VariantIdx, + untagged_variant_index: Option, + variant_struct_type_di_node: &'ll DIType, + variant_names_type_di_node: &'ll DIType, + tag_base_type_di_node: &'ll DIType, + tag_base_type: Ty<'tcx>, + discr: DiscrResult, +) -> &'ll DIType { + type_map::build_type_with_children( cx, - "Discriminant$", - tag_base_type, - &mut variant_indices.filter_map(|variant_index| { - if let Some(discr_val) = - super::compute_discriminant_value(cx, enum_type_and_layout, variant_index) - { - let discr = Discr { val: discr_val as u128, ty: tag_base_type }; - let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); - Some((discr, variant_name)) - } else { - debug_assert_eq!(variant_index, dataful_variant_index); - None - } - }), - enum_type_di_node, - ); - - smallvec![ - build_field_di_node( - cx, - enum_type_di_node, - "dataful_variant", - size_and_align_of(enum_type_and_layout), - Size::ZERO, - DIFlags::FlagZero, - dataful_variant_struct_type_di_node, - ), - build_field_di_node( + type_map::stub( cx, - enum_type_di_node, - "discriminant", - cx.size_and_align_of(tag_base_type), - enum_type_and_layout.fields.offset(tag_field), + Stub::Struct, + UniqueTypeId::for_enum_variant_struct_type_wrapper( + cx.tcx, + enum_or_generator_type_and_layout.ty, + variant_index, + ), + &variant_struct_wrapper_type_name(variant_index), + // NOTE: We use size and align of enum_type, not from variant_layout: + size_and_align_of(enum_or_generator_type_and_layout), + Some(enum_or_generator_type_di_node), DIFlags::FlagZero, - discr_type_di_node, ), - ] + |cx, wrapper_struct_type_di_node| { + enum DiscrKind { + Exact(u64), + Exact128(u128), + Range(u64, u64), + Range128(u128, u128), + } + + let (tag_base_type_size, tag_base_type_align) = cx.size_and_align_of(tag_base_type); + let is_128_bits = tag_base_type_size.bits() > 64; + + let discr = match discr { + DiscrResult::NoDiscriminant => DiscrKind::Exact(SINGLE_VARIANT_VIRTUAL_DISR), + DiscrResult::Value(discr_val) => { + if is_128_bits { + DiscrKind::Exact128(discr_val) + } else { + debug_assert_eq!(discr_val, discr_val as u64 as u128); + DiscrKind::Exact(discr_val as u64) + } + } + DiscrResult::Range(min, max) => { + assert_eq!(Some(variant_index), untagged_variant_index); + if is_128_bits { + DiscrKind::Range128(min, max) + } else { + debug_assert_eq!(min, min as u64 as u128); + debug_assert_eq!(max, max as u64 as u128); + DiscrKind::Range(min as u64, max as u64) + } + } + }; + + let mut fields = SmallVec::new(); + + // We always have a field for the value + fields.push(build_field_di_node( + cx, + wrapper_struct_type_di_node, + "value", + size_and_align_of(enum_or_generator_type_and_layout), + Size::ZERO, + DIFlags::FlagZero, + variant_struct_type_di_node, + )); + + let build_assoc_const = + |name: &str, type_di_node: &'ll DIType, value: u64, align: Align| unsafe { + llvm::LLVMRustDIBuilderCreateStaticMemberType( + DIB(cx), + wrapper_struct_type_di_node, + name.as_ptr().cast(), + name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + type_di_node, + DIFlags::FlagZero, + Some(cx.const_u64(value)), + align.bits() as u32, + ) + }; + + // We also always have an associated constant for the discriminant value + // of the variant. + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_NAME, + variant_names_type_di_node, + variant_index.as_u32() as u64, + cx.align_of(variant_names_enum_base_type(cx)), + )); + + // Emit the discriminant value (or range) corresponding to the variant. + match discr { + DiscrKind::Exact(discr_val) => { + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_EXACT, + tag_base_type_di_node, + discr_val, + tag_base_type_align, + )); + } + DiscrKind::Exact128(discr_val) => { + let align = cx.align_of(cx.tcx.types.u64); + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let Split128 { hi, lo } = split_128(discr_val); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_EXACT_LO, + type_di_node, + lo, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_EXACT_HI, + type_di_node, + hi, + align, + )); + } + DiscrKind::Range(begin, end) => { + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_BEGIN, + tag_base_type_di_node, + begin, + tag_base_type_align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_END, + tag_base_type_di_node, + end, + tag_base_type_align, + )); + } + DiscrKind::Range128(begin, end) => { + let align = cx.align_of(cx.tcx.types.u64); + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let Split128 { hi: begin_hi, lo: begin_lo } = split_128(begin); + let Split128 { hi: end_hi, lo: end_lo } = split_128(end); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_BEGIN_HI, + type_di_node, + begin_hi, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_BEGIN_LO, + type_di_node, + begin_lo, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_END_HI, + type_di_node, + end_hi, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_END_LO, + type_di_node, + end_lo, + align, + )); + } + } + + fields + }, + NO_GENERICS, + ) + .di_node +} + +struct Split128 { + hi: u64, + lo: u64, +} + +fn split_128(value: u128) -> Split128 { + Split128 { hi: (value >> 64) as u64, lo: value as u64 } } fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( @@ -369,6 +681,29 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id); let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx); + let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len(); + + let tag_base_type = tag_base_type(cx, generator_type_and_layout); + + let variant_names_type_di_node = build_variant_names_type_di_node( + cx, + generator_type_di_node, + variant_range + .clone() + .map(|variant_index| (variant_index, GeneratorSubsts::variant_name(variant_index))), + ); + + let discriminants: IndexVec = { + let discriminants_iter = generator_substs.discriminants(generator_def_id, cx.tcx); + let mut discriminants: IndexVec = + IndexVec::with_capacity(variant_count); + for (variant_index, discr) in discriminants_iter { + // Assert that the index in the IndexMap matches up with the given VariantIdx. + assert_eq!(variant_index, discriminants.next_index()); + discriminants.push(DiscrResult::Value(discr.val)); + } + discriminants + }; // Build the type node for each field. let variant_field_infos: SmallVec> = variant_range @@ -391,29 +726,24 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( None }; - VariantFieldInfo { variant_index, variant_struct_type_di_node, source_info } + VariantFieldInfo { + variant_index, + variant_struct_type_di_node, + source_info, + discr: discriminants[variant_index], + } }) .collect(); - let tag_base_type = tag_base_type(cx, generator_type_and_layout); - let discr_type_name = "Discriminant$"; - let discr_type_di_node = super::build_enumeration_type_di_node( - cx, - discr_type_name, - tag_base_type, - &mut generator_substs - .discriminants(generator_def_id, cx.tcx) - .map(|(variant_index, discr)| (discr, GeneratorSubsts::variant_name(variant_index))), - generator_type_di_node, - ); - build_union_fields_for_direct_tag_enum_or_generator( cx, generator_type_and_layout, generator_type_di_node, &variant_field_infos[..], - discr_type_di_node, + variant_names_type_di_node, + tag_base_type, tag_field, + None, ) } @@ -425,8 +755,11 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( enum_type_di_node: &'ll DIType, variant_field_infos: &[VariantFieldInfo<'ll>], discr_type_di_node: &'ll DIType, + tag_base_type: Ty<'tcx>, tag_field: usize, + untagged_variant_index: Option, ) -> SmallVec<&'ll DIType> { + let tag_base_type_di_node = type_di_node(cx, tag_base_type); let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1); // We create a field in the union for each variant ... @@ -438,6 +771,19 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( let field_name = variant_union_field_name(variant_member_info.variant_index); let (size, align) = size_and_align_of(enum_type_and_layout); + let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node( + cx, + enum_type_and_layout, + enum_type_di_node, + variant_member_info.variant_index, + untagged_variant_index, + variant_member_info.variant_struct_type_di_node, + discr_type_di_node, + tag_base_type_di_node, + tag_base_type, + variant_member_info.discr, + ); + // We use LLVMRustDIBuilderCreateMemberType() member type directly because // the build_field_di_node() function does not support specifying a source location, // which is something that we don't do anywhere else. @@ -456,7 +802,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( // Union fields are always at offset zero Size::ZERO.bits(), DIFlags::FlagZero, - variant_member_info.variant_struct_type_di_node, + variant_struct_type_wrapper, ) } })); @@ -466,16 +812,53 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout)) ); - // ... and a field for the discriminant. - unions_fields.push(build_field_di_node( - cx, - enum_type_di_node, - "discriminant", - cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), - enum_type_and_layout.fields.offset(tag_field), - DIFlags::FlagZero, - discr_type_di_node, - )); + // ... and a field for the tag. If the tag is 128 bits wide, this will actually + // be two 64-bit fields. + let is_128_bits = cx.size_of(tag_base_type).bits() > 64; + + if is_128_bits { + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let size_and_align = cx.size_and_align_of(cx.tcx.types.u64); + + let (lo_offset, hi_offset) = match cx.tcx.data_layout.endian { + Endian::Little => (0, 8), + Endian::Big => (8, 0), + }; + + let tag_field_offset = enum_type_and_layout.fields.offset(tag_field).bytes(); + let lo_offset = Size::from_bytes(tag_field_offset + lo_offset); + let hi_offset = Size::from_bytes(tag_field_offset + hi_offset); + + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME_128_LO, + size_and_align, + lo_offset, + DIFlags::FlagZero, + type_di_node, + )); + + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME_128_HI, + size_and_align, + hi_offset, + DIFlags::FlagZero, + type_di_node, + )); + } else { + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME, + cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), + enum_type_and_layout.fields.offset(tag_field), + DIFlags::FlagZero, + tag_base_type_di_node, + )); + } unions_fields } @@ -485,6 +868,7 @@ struct VariantFieldInfo<'ll> { variant_index: VariantIdx, variant_struct_type_di_node: &'ll DIType, source_info: Option<(&'ll DIFile, c_uint)>, + discr: DiscrResult, } fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { @@ -512,3 +896,29 @@ fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { .map(|&s| Cow::from(s)) .unwrap_or_else(|| format!("variant{}", variant_index.as_usize()).into()) } + +fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, str> { + const PRE_ALLOCATED: [&str; 16] = [ + "Variant0", + "Variant1", + "Variant2", + "Variant3", + "Variant4", + "Variant5", + "Variant6", + "Variant7", + "Variant8", + "Variant9", + "Variant10", + "Variant11", + "Variant12", + "Variant13", + "Variant14", + "Variant15", + ]; + + PRE_ALLOCATED + .get(variant_index.as_usize()) + .map(|&s| Cow::from(s)) + .unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into()) +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 73e01d045..14044d0f9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -10,7 +10,6 @@ use rustc_middle::{ ty::{ self, layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}, - util::Discr, AdtDef, GeneratorSubsts, Ty, VariantDef, }, }; @@ -90,8 +89,11 @@ fn build_c_style_enum_di_node<'ll, 'tcx>( cx, &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false), tag_base_type(cx, enum_type_and_layout), - &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { - (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str())) + enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { + let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); + // Is there anything we can do to support 128-bit C-Style enums? + let value = discr.val as u64; + (name, value) }), containing_scope, ), @@ -152,7 +154,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, type_name: &str, base_type: Ty<'tcx>, - variants: &mut dyn Iterator, Cow<'tcx, str>)>, + enumerators: impl Iterator, u64)>, containing_scope: &'ll DIType, ) -> &'ll DIType { let is_unsigned = match base_type.kind() { @@ -161,18 +163,15 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( _ => bug!("build_enumeration_type_di_node() called with non-integer tag type."), }; - let enumerator_di_nodes: SmallVec> = variants - .map(|(discr, variant_name)| { - unsafe { - Some(llvm::LLVMRustDIBuilderCreateEnumerator( - DIB(cx), - variant_name.as_ptr().cast(), - variant_name.len(), - // FIXME: what if enumeration has i128 discriminant? - discr.val as i64, - is_unsigned, - )) - } + let enumerator_di_nodes: SmallVec> = enumerators + .map(|(name, value)| unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + value as i64, + is_unsigned, + )) }) .collect(); @@ -247,23 +246,27 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( /// and a DW_TAG_member for each field (but not the discriminant). fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - enum_type: Ty<'tcx>, + enum_type_and_layout: TyAndLayout<'tcx>, enum_type_di_node: &'ll DIType, variant_index: VariantIdx, variant_def: &VariantDef, variant_layout: TyAndLayout<'tcx>, ) -> &'ll DIType { - debug_assert_eq!(variant_layout.ty, enum_type); + debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty); type_map::build_type_with_children( cx, type_map::stub( cx, Stub::Struct, - UniqueTypeId::for_enum_variant_struct_type(cx.tcx, enum_type, variant_index), + UniqueTypeId::for_enum_variant_struct_type( + cx.tcx, + enum_type_and_layout.ty, + variant_index, + ), variant_def.name.as_str(), // NOTE: We use size and align of enum_type, not from variant_layout: - cx.size_and_align_of(enum_type), + size_and_align_of(enum_type_and_layout), Some(enum_type_di_node), DIFlags::FlagZero, ), @@ -290,9 +293,9 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( type_di_node(cx, field_layout.ty), ) }) - .collect() + .collect::>() }, - |cx| build_generic_type_param_di_nodes(cx, enum_type), + |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty), ) .di_node } @@ -398,39 +401,60 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( .di_node } +#[derive(Copy, Clone)] +enum DiscrResult { + NoDiscriminant, + Value(u128), + Range(u128, u128), +} + +impl DiscrResult { + fn opt_single_val(&self) -> Option { + if let Self::Value(d) = *self { Some(d) } else { None } + } +} + /// Returns the discriminant value corresponding to the variant index. /// /// Will return `None` if there is less than two variants (because then the enum won't have) -/// a tag, and if this is the dataful variant of a niche-layout enum (because then there is no +/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no /// single discriminant value). fn compute_discriminant_value<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, enum_type_and_layout: TyAndLayout<'tcx>, variant_index: VariantIdx, -) -> Option { +) -> DiscrResult { match enum_type_and_layout.layout.variants() { - &Variants::Single { .. } => None, - &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => Some( - enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val - as u64, + &Variants::Single { .. } => DiscrResult::NoDiscriminant, + &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value( + enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val, ), &Variants::Multiple { - tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, + tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant }, tag, .. } => { - if variant_index == dataful_variant { - None + if variant_index == untagged_variant { + let valid_range = enum_type_and_layout + .for_variant(cx, variant_index) + .largest_niche + .as_ref() + .unwrap() + .valid_range; + + let min = valid_range.start.min(valid_range.end); + let min = tag.size(cx).truncate(min); + + let max = valid_range.start.max(valid_range.end); + let max = tag.size(cx).truncate(max); + + DiscrResult::Range(min, max) } else { let value = (variant_index.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); let value = tag.size(cx).truncate(value); - // NOTE(eddyb) do *NOT* remove this assert, until - // we pass the full 128-bit value to LLVM, otherwise - // truncation will be silent and remain undetected. - assert_eq!(value as u64 as u128, value); - Some(value as u64) + DiscrResult::Value(value) } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index f1935e0ec..becbccc43 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -88,7 +88,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()), variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node( cx, - enum_type, + enum_type_and_layout, enum_type_di_node, variant_index, enum_adt_def.variant(variant_index), @@ -378,7 +378,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( /// /// The DW_AT_discr_value is optional, and is omitted if /// - This is the only variant of a univariant enum (i.e. their is no discriminant) -/// - This is the "dataful" variant of a niche-layout enum +/// - This is the "untagged" variant of a niche-layout enum /// (where only the other variants are identified by a single value) /// /// There is only ever a single member, the type of which is a struct that describes the @@ -413,7 +413,13 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( enum_type_and_layout.size.bits(), enum_type_and_layout.align.abi.bits() as u32, Size::ZERO.bits(), - discr_value.map(|v| cx.const_u64(v)), + discr_value.opt_single_val().map(|value| { + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); + cx.const_u64(value as u64) + }), DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index ce2f419c4..e30622cbd 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -47,6 +47,8 @@ pub(super) enum UniqueTypeId<'tcx> { VariantPart(Ty<'tcx>, private::HiddenZst), /// The ID for the artificial struct type describing a single enum variant. VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst), + /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode. + VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst), /// The ID of the artificial type we create for VTables. VTableTy(Ty<'tcx>, Option>, private::HiddenZst), } @@ -71,6 +73,15 @@ impl<'tcx> UniqueTypeId<'tcx> { UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst) } + pub fn for_enum_variant_struct_type_wrapper( + tcx: TyCtxt<'tcx>, + enum_ty: Ty<'tcx>, + variant_idx: VariantIdx, + ) -> Self { + debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); + UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst) + } + pub fn for_vtable_ty( tcx: TyCtxt<'tcx>, self_type: Ty<'tcx>, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index cf591295b..b23fe3fc9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -39,7 +39,6 @@ use smallvec::SmallVec; use std::cell::OnceCell; use std::cell::RefCell; use std::iter; -use tracing::debug; mod create_scope_map; pub mod gdb; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 8f2436739..a40cfc8b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -6,7 +6,7 @@ use super::CodegenUnitDebugContext; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, DefIdTree, Ty}; -use tracing::trace; +use trace; use crate::common::CodegenCx; use crate::llvm; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index fa0ecd18f..0f663a267 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,7 +22,6 @@ use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_middle::ty::Ty; use rustc_symbol_mangling::typeid::typeid_for_fnabi; use smallvec::SmallVec; -use tracing::debug; /// Declare a function. /// diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9f3647492..a640de42a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -71,6 +71,7 @@ fn get_simple_intrinsic<'ll>( sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", + sym::ptr_mask => "llvm.ptrmask", _ => return None, }; Some(cx.get_intrinsic(llvm_name)) @@ -161,7 +162,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let ptr = args[0].immediate(); - let load = if let PassMode::Cast(ty) = fn_abi.ret.mode { + let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { let llty = ty.llvm_type(self); let ptr = self.pointercast(ptr, self.type_ptr_to(llty)); self.volatile_load(llty, ptr) @@ -374,7 +375,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty) = fn_abi.ret.mode { + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.llvm_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); @@ -1704,6 +1705,97 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, bitwise_red!(simd_reduce_all: vector_reduce_and, true); bitwise_red!(simd_reduce_any: vector_reduce_or, true); + if name == sym::simd_cast_ptr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(p) => { + let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + }); + assert!(!check_sized); // we are in codegen, so we shouldn't see these types + require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem) + } + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(p) => { + let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + }); + assert!(!check_sized); // we are in codegen, so we shouldn't see these types + require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem) + } + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + if in_elem == out_elem { + return Ok(args[0].immediate()); + } else { + return Ok(bx.pointercast(args[0].immediate(), llret_ty)); + } + } + + if name == sym::simd_expose_addr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", out_elem), + } + + return Ok(bx.ptrtoint(args[0].immediate(), llret_ty)); + } + + if name == sym::simd_from_exposed_addr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + return Ok(bx.inttoptr(args[0].immediate(), llret_ty)); + } + if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, "return"); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 636d689a3..42c65e04e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -7,7 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(hash_raw_entry)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(extern_types)] #![feature(once_cell)] #![feature(iter_intersperse)] @@ -16,6 +16,8 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs index 64db4f746..7d9489702 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs @@ -83,17 +83,6 @@ impl<'a> Child<'a> { } } } - - pub fn data(&self) -> &'a [u8] { - unsafe { - let mut data_len = 0; - let data_ptr = super::LLVMRustArchiveChildData(self.raw, &mut data_len); - if data_ptr.is_null() { - panic!("failed to read data from archive child"); - } - slice::from_raw_parts(data_ptr as *const u8, data_len as usize) - } - } } impl<'a> Drop for Child<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3139f93bf..ce27dc5a5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1096,7 +1096,7 @@ extern "C" { pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value; pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value; pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value; - pub fn LLVMConstIntGetZExtValue(ConstantVal: &ConstantInt) -> c_ulonglong; + pub fn LLVMRustConstIntGetZExtValue(ConstantVal: &ConstantInt, Value: &mut u64) -> bool; pub fn LLVMRustConstInt128Get( ConstantVal: &ConstantInt, SExt: bool, @@ -2079,6 +2079,19 @@ extern "C" { Ty: &'a DIType, ) -> &'a DIType; + pub fn LLVMRustDIBuilderCreateStaticMemberType<'a>( + Builder: &DIBuilder<'a>, + Scope: &'a DIDescriptor, + Name: *const c_char, + NameLen: size_t, + File: &'a DIFile, + LineNo: c_uint, + Ty: &'a DIType, + Flags: DIFlags, + val: Option<&'a Value>, + AlignInBits: u32, + ) -> &'a DIDerivedType; + pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>( Builder: &DIBuilder<'a>, Scope: &'a DIScope, @@ -2347,6 +2360,7 @@ extern "C" { PGOGenPath: *const c_char, PGOUsePath: *const c_char, InstrumentCoverage: bool, + InstrProfileOutput: *const c_char, InstrumentGCOV: bool, PGOSampleUsePath: *const c_char, DebugInfoForProfiling: bool, @@ -2375,7 +2389,6 @@ extern "C" { AIR: &ArchiveIterator<'a>, ) -> Option<&'a mut ArchiveChild<'a>>; pub fn LLVMRustArchiveChildName(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildData(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char; pub fn LLVMRustArchiveChildFree<'a>(ACR: &'a mut ArchiveChild<'a>); pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>); pub fn LLVMRustDestroyArchive(AR: &'static mut Archive); @@ -2410,12 +2423,6 @@ extern "C" { cookie_out: &mut c_uint, ) -> &'a SMDiagnostic; - pub fn LLVMRustSetInlineAsmDiagnosticHandler( - C: &Context, - H: InlineAsmDiagHandlerTy, - CX: *mut c_void, - ); - #[allow(improper_ctypes)] pub fn LLVMRustUnpackSMDiagnostic( d: &SMDiagnostic, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a0a640473..60707a1c3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -15,7 +15,6 @@ use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use smallvec::{smallvec, SmallVec}; use std::ffi::{CStr, CString}; -use tracing::debug; use std::mem; use std::path::Path; @@ -92,16 +91,6 @@ unsafe fn configure_llvm(sess: &Session) { add("-generate-arange-section", false); } - // Disable the machine outliner by default in LLVM versions 11 and LLVM - // version 12, where it leads to miscompilation. - // - // Ref: - // - https://github.com/rust-lang/rust/issues/85351 - // - https://reviews.llvm.org/D103167 - if llvm_util::get_version() < (13, 0, 0) { - add("-enable-machine-outliner=never", false); - } - match sess.opts.unstable_opts.merge_functions.unwrap_or(sess.target.merge_functions) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { @@ -165,6 +154,10 @@ pub fn time_trace_profiler_finish(file_name: &Path) { // // To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def // where the * matches the architecture's name +// +// For targets not present in the above location, see llvm-project/llvm/lib/Target/{ARCH}/*.td +// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. +// // Beware to not use the llvm github project for this, but check the git submodule // found in src/llvm-project // Though note that Rust can also be build with an external precompiled version of LLVM @@ -440,6 +433,8 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec= (15, 0, 0)) .map(String::from), ); diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 6e9428485..1eceb7f5c 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_session::config::CrateType; use rustc_target::spec::RelocModel; -use tracing::debug; impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { fn predefine_static( diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 9f0e6c80b..dc1165835 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -11,7 +11,6 @@ use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; use smallvec::{smallvec, SmallVec}; -use tracing::debug; use std::fmt::Write; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 46d6344db..d868e3d56 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -26,7 +26,6 @@ rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } -rustc_apfloat = { path = "../rustc_apfloat" } rustc_attr = { path = "../rustc_attr" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 0d2aa483d..bb76ca5d2 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,44 +1,16 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::memmap::Mmap; use rustc_session::cstore::DllImport; use rustc_session::Session; +use rustc_span::symbol::Symbol; +use object::read::archive::ArchiveFile; + +use std::fmt::Display; +use std::fs::File; use std::io; use std::path::{Path, PathBuf}; -pub(super) fn find_library( - name: &str, - verbatim: bool, - search_paths: &[PathBuf], - sess: &Session, -) -> PathBuf { - // On Windows, static libraries sometimes show up as libfoo.a and other - // times show up as foo.lib - let oslibname = if verbatim { - name.to_string() - } else { - format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix) - }; - let unixlibname = format!("lib{}.a", name); - - for path in search_paths { - debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname); - if test.exists() { - return test; - } - if oslibname != unixlibname { - let test = path.join(&unixlibname); - if test.exists() { - return test; - } - } - } - sess.fatal(&format!( - "could not find native static library `{}`, \ - perhaps an -L flag is missing?", - name - )); -} - pub trait ArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a>; @@ -53,7 +25,38 @@ pub trait ArchiveBuilderBuilder { lib_name: &str, dll_imports: &[DllImport], tmpdir: &Path, + is_direct_dependency: bool, ) -> PathBuf; + + fn extract_bundled_libs( + &self, + rlib: &Path, + outdir: &Path, + bundled_lib_file_names: &FxHashSet, + ) -> Result<(), String> { + let message = |msg: &str, e: &dyn Display| format!("{} '{}': {}", msg, &rlib.display(), e); + let archive_map = unsafe { + Mmap::map(File::open(rlib).map_err(|e| message("failed to open file", &e))?) + .map_err(|e| message("failed to mmap file", &e))? + }; + let archive = ArchiveFile::parse(&*archive_map) + .map_err(|e| message("failed to parse archive", &e))?; + + for entry in archive.members() { + let entry = entry.map_err(|e| message("failed to read entry", &e))?; + let data = entry + .data(&*archive_map) + .map_err(|e| message("failed to get data from archive member", &e))?; + let name = std::str::from_utf8(entry.name()) + .map_err(|e| message("failed to convert name", &e))?; + if !bundled_lib_file_names.contains(&Symbol::intern(name)) { + continue; // We need to extract only native libraries. + } + std::fs::write(&outdir.join(&name), data) + .map_err(|e| message("failed to write file", &e))?; + } + Ok(()) + } } pub trait ArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 63207803e..6cce95427 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,11 +1,13 @@ use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; +use rustc_metadata::find_native_static_library; use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; @@ -20,11 +22,11 @@ use rustc_session::utils::NativeLibKind; use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_span::DebuggerVisualizerFile; -use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; +use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo}; use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target}; -use super::archive::{find_library, ArchiveBuilder, ArchiveBuilderBuilder}; +use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{create_rmeta_file, MetadataPosition}; @@ -44,7 +46,7 @@ use std::io::{BufWriter, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; -use std::{ascii, char, env, fmt, fs, io, mem, str}; +use std::{env, fmt, fs, io, mem, str}; pub fn ensure_removed(diag_handler: &Handler, path: &Path) { if let Err(e) = fs::remove_file(path) { @@ -307,6 +309,9 @@ fn link_rlib<'a>( } } + // Used if packed_bundled_libs flag enabled. + let mut packed_bundled_libs = Vec::new(); + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, // we may not be configured to actually include a static library if we're // adding it here. That's because later when we consume this rlib we'll @@ -325,6 +330,8 @@ fn link_rlib<'a>( // metadata of the rlib we're generating somehow. for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { + NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) } + if flavor == RlibFlavor::Normal && sess.opts.unstable_opts.packed_bundled_libs => {} NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) } if flavor == RlibFlavor::Normal => { @@ -348,7 +355,16 @@ fn link_rlib<'a>( } if let Some(name) = lib.name { let location = - find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess); + find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess); + if sess.opts.unstable_opts.packed_bundled_libs && flavor == RlibFlavor::Normal { + packed_bundled_libs.push(find_native_static_library( + lib.filename.unwrap().as_str(), + Some(true), + &lib_search_paths, + sess, + )); + continue; + } ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| { sess.fatal(&format!( "failed to add native library {}: {}", @@ -360,13 +376,14 @@ fn link_rlib<'a>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? + collate_raw_dylibs(sess, codegen_results.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(|e| { @@ -403,6 +420,12 @@ fn link_rlib<'a>( ab.add_file(&trailing_metadata); } + // Add all bundled static native library dependencies. + // Archives added to the end of .rlib archive, see comment above for the reason. + for lib in packed_bundled_libs { + ab.add_file(&lib) + } + return Ok(ab); } @@ -412,9 +435,9 @@ fn link_rlib<'a>( /// then the CodegenResults value contains one NativeLib instance for each block. However, the /// linker appears to expect only a single import library for each library used, so we need to /// collate the symbols together by library name before generating the import libraries. -fn collate_raw_dylibs( - sess: &Session, - used_libraries: &[NativeLib], +fn collate_raw_dylibs<'a, 'b>( + sess: &'a Session, + used_libraries: impl IntoIterator, ) -> Result)>, ErrorGuaranteed> { // Use index maps to preserve original order of imports and libraries. let mut dylib_table = FxIndexMap::>::default(); @@ -552,14 +575,6 @@ fn link_staticlib<'a>( Ok(()) } -fn escape_stdout_stderr_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); - x - }) -} - /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a /// DWARF package. fn link_dwarf_object<'a>( @@ -764,15 +779,15 @@ fn link_natively<'a>( "Linker does not support -static-pie command line option. Retrying with -static instead." ); // Mirror `add_(pre,post)_link_objects` to replace CRT objects. - let self_contained = crt_objects_fallback(sess, crate_type); + let self_contained = self_contained(sess, crate_type); let opts = &sess.target; let pre_objects = if self_contained { - &opts.pre_link_objects_fallback + &opts.pre_link_objects_self_contained } else { &opts.pre_link_objects }; let post_objects = if self_contained { - &opts.post_link_objects_fallback + &opts.post_link_objects_self_contained } else { &opts.post_link_objects }; @@ -866,7 +881,7 @@ fn link_natively<'a>( if !prog.status.success() { let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); - let escaped_output = escape_stdout_stderr_string(&output); + let escaped_output = escape_string(&output); let mut err = sess.struct_err(&format!( "linking with `{}` failed: {}", linker_path.display(), @@ -934,8 +949,8 @@ fn link_natively<'a>( sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; @@ -1065,11 +1080,10 @@ fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Opti } fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); - x - }) + match str::from_utf8(s) { + Ok(s) => s.to_owned(), + Err(_) => format!("Non-UTF-8 output: {}", s.escape_ascii()), + } } fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { @@ -1173,13 +1187,6 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { // only the linker flavor is known; use the default linker for the selected flavor (None, Some(flavor)) => Some(( PathBuf::from(match flavor { - LinkerFlavor::Em => { - if cfg!(windows) { - "emcc.bat" - } else { - "emcc" - } - } LinkerFlavor::Gcc => { if cfg!(any(target_os = "solaris", target_os = "illumos")) { // On historical Solaris systems, "cc" may have @@ -1194,11 +1201,17 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { } } LinkerFlavor::Ld => "ld", - LinkerFlavor::Msvc => "link.exe", LinkerFlavor::Lld(_) => "lld", - LinkerFlavor::PtxLinker => "rust-ptx-linker", - LinkerFlavor::BpfLinker => "bpf-linker", - LinkerFlavor::L4Bender => "l4-bender", + LinkerFlavor::Msvc => "link.exe", + LinkerFlavor::EmCc => { + if cfg!(windows) { + "emcc.bat" + } else { + "emcc" + } + } + LinkerFlavor::Bpf => "bpf-linker", + LinkerFlavor::Ptx => "rust-ptx-linker", }), flavor, )), @@ -1208,7 +1221,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { }); let flavor = if stem == "emcc" { - LinkerFlavor::Em + LinkerFlavor::EmCc } else if stem == "gcc" || stem.ends_with("-gcc") || stem == "clang" @@ -1236,7 +1249,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { // linker and linker flavor specified via command line have precedence over what the target // specification specifies - if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) { + let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli); + if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) { return ret; } @@ -1556,26 +1570,26 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { true } -/// Whether we link to our own CRT objects instead of relying on gcc to pull them. +/// Various toolchain components used during linking are used from rustc distribution +/// instead of being found somewhere on the host system. /// We only provide such support for a very limited number of targets. -fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { +fn self_contained(sess: &Session, crate_type: CrateType) -> bool { if let Some(self_contained) = sess.opts.cg.link_self_contained { return self_contained; } - match sess.target.crt_objects_fallback { + match sess.target.link_self_contained { + LinkSelfContainedDefault::False => false, + LinkSelfContainedDefault::True => true, // FIXME: Find a better heuristic for "native musl toolchain is available", // based on host and linker path, for example. // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). - Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), - Some(CrtObjectsFallback::Mingw) => { + LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)), + LinkSelfContainedDefault::Mingw => { sess.host == sess.target && sess.target.vendor != "uwp" && detect_self_contained_mingw(&sess) } - // FIXME: Figure out cases in which WASM needs to link with a native toolchain. - Some(CrtObjectsFallback::Wasm) => true, - None => false, } } @@ -1583,12 +1597,21 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { fn add_pre_link_objects( cmd: &mut dyn Linker, sess: &Session, + flavor: LinkerFlavor, link_output_kind: LinkOutputKind, self_contained: bool, ) { + // FIXME: we are currently missing some infra here (per-linker-flavor CRT objects), + // so Fuchsia has to be special-cased. let opts = &sess.target; - let objects = - if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; + let empty = Default::default(); + let objects = if self_contained { + &opts.pre_link_objects_self_contained + } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) { + &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)); } @@ -1601,9 +1624,11 @@ fn add_post_link_objects( link_output_kind: LinkOutputKind, self_contained: bool, ) { - let opts = &sess.target; - let objects = - if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects }; + 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() { cmd.add_object(&get_object_file_path(sess, obj, self_contained)); } @@ -1703,6 +1728,13 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// that are necessary for the linking. They are only present in symbol table but not actually /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. +/// +/// There's a few internal crates in the standard library (aka libcore and +/// libstd) which actually have a circular dependence upon one another. This +/// currently arises through "weak lang items" where libcore requires things +/// like `rust_begin_unwind` but libstd ends up defining it. To get this +/// circular dependence to work correctly we declare some of these things +/// in this synthetic object. fn add_linked_symbol_object( cmd: &mut dyn Linker, sess: &Session, @@ -1882,12 +1914,12 @@ fn linker_with_args<'a>( out_filename: &Path, codegen_results: &CodegenResults, ) -> Result { - let crt_objects_fallback = crt_objects_fallback(sess, crate_type); + let self_contained = self_contained(sess, crate_type); let cmd = &mut *super::linker::get_linker( sess, path, flavor, - crt_objects_fallback, + self_contained, &codegen_results.crate_info.target_cpu, ); let link_output_kind = link_output_kind(sess, crate_type); @@ -1914,7 +1946,7 @@ fn linker_with_args<'a>( // ------------ Object code and libraries, order-dependent ------------ // Pre-link CRT objects. - add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); + add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained); add_linked_symbol_object( cmd, @@ -1947,7 +1979,6 @@ fn linker_with_args<'a>( // Upstream rust libraries are not supposed to depend on our local native // libraries as that would violate the structure of the DAG, in that // scenario they are required to link to them as well in a shared fashion. - // (The current implementation still doesn't prevent it though, see the FIXME below.) // // Note that upstream rust libraries may contain native dependencies as // well, but they also can't depend on what we just started to add to the @@ -1968,15 +1999,16 @@ fn linker_with_args<'a>( // and move this option back to the top. cmd.add_as_needed(); - // FIXME: Move this below to other native libraries - // (or alternatively link all native libraries after their respective crates). - // This change is somewhat breaking in practice due to local static libraries being linked - // as whole-archive (#85144), so removing whole-archive may be a pre-requisite. + // Local native libraries of all kinds. + // + // If `-Zlink-native-libraries=false` is set, then the assumption is that an + // external build system already has the native dependencies defined, and it + // will provide them to the linker itself. if sess.opts.unstable_opts.link_native_libraries { add_local_native_libraries(cmd, sess, codegen_results); } - // Upstream rust libraries and their non-bundled static libraries + // Upstream rust libraries and their (possibly bundled) static native libraries. add_upstream_rust_crates( cmd, sess, @@ -1986,24 +2018,54 @@ fn linker_with_args<'a>( tmpdir, ); - // Upstream dynamic native libraries linked with `#[link]` attributes at and `-l` - // command line options. - // If -Zlink-native-libraries=false is set, then the assumption is that an - // external build system already has the native dependencies defined, and it - // will provide them to the linker itself. + // Dynamic native libraries from upstream crates. + // + // FIXME: Merge this to `add_upstream_rust_crates` so that all native libraries are linked + // together with their respective upstream crates, and in their originally specified order. + // This may be slightly breaking due to our use of `--as-needed` and needs a crater run. if sess.opts.unstable_opts.link_native_libraries { add_upstream_native_libraries(cmd, sess, codegen_results); } // Link with the import library generated for any raw-dylib functions. for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? + 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, + )); + } + // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case + // they are used within inlined functions or instantiated generic functions. We do this *after* + // handling the raw-dylib symbols in the current crate to make sure that those are chosen first + // by the linker. + 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"); + let native_libraries_from_nonstatics = codegen_results + .crate_info + .native_libraries + .iter() + .filter_map(|(cnum, libraries)| { + (dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries) + }) + .flatten(); + for (raw_dylib_name, raw_dylib_imports) in + collate_raw_dylibs(sess, native_libraries_from_nonstatics)? + { + cmd.add_object(&archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + &raw_dylib_imports, + tmpdir, + false, )); } @@ -2024,7 +2086,7 @@ fn linker_with_args<'a>( cmd, sess, link_output_kind, - crt_objects_fallback, + self_contained, flavor, crate_type, codegen_results, @@ -2040,7 +2102,7 @@ fn linker_with_args<'a>( // ------------ Object code and libraries, order-dependent ------------ // Post-link CRT objects. - add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); + add_post_link_objects(cmd, sess, link_output_kind, self_contained); // ------------ Late order-dependent options ------------ @@ -2057,7 +2119,7 @@ fn add_order_independent_options( cmd: &mut dyn Linker, sess: &Session, link_output_kind: LinkOutputKind, - crt_objects_fallback: bool, + self_contained: bool, flavor: LinkerFlavor, crate_type: CrateType, codegen_results: &CodegenResults, @@ -2070,7 +2132,10 @@ fn add_order_independent_options( add_link_script(cmd, sess, tmpdir, crate_type); - if sess.target.os == "fuchsia" && crate_type == CrateType::Executable { + if sess.target.os == "fuchsia" + && crate_type == CrateType::Executable + && flavor != LinkerFlavor::Gcc + { let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" } else { @@ -2086,7 +2151,7 @@ fn add_order_independent_options( // Make the binary compatible with data execution prevention schemes. cmd.add_no_exec(); - if crt_objects_fallback { + if self_contained { cmd.no_crt_objects(); } @@ -2099,11 +2164,11 @@ fn add_order_independent_options( }); } - if flavor == LinkerFlavor::PtxLinker { + if flavor == LinkerFlavor::Ptx { // Provide the linker with fallback to internal `target-cpu`. cmd.arg("--fallback-arch"); cmd.arg(&codegen_results.crate_info.target_cpu); - } else if flavor == LinkerFlavor::BpfLinker { + } else if flavor == LinkerFlavor::Bpf { cmd.arg("--cpu"); cmd.arg(&codegen_results.crate_info.target_cpu); cmd.arg("--cpu-features"); @@ -2115,7 +2180,7 @@ fn add_order_independent_options( cmd.linker_plugin_lto(); - add_library_search_dirs(cmd, sess, crt_objects_fallback); + add_library_search_dirs(cmd, sess, self_contained); cmd.output_filename(out_filename); @@ -2319,72 +2384,25 @@ fn add_upstream_rust_crates<'a>( // crates. let deps = &codegen_results.crate_info.used_crates; - // There's a few internal crates in the standard library (aka libcore and - // libstd) which actually have a circular dependence upon one another. This - // currently arises through "weak lang items" where libcore requires things - // like `rust_begin_unwind` but libstd ends up defining it. To get this - // circular dependence to work correctly in all situations we'll need to be - // sure to correctly apply the `--start-group` and `--end-group` options to - // GNU linkers, otherwise if we don't use any other symbol from the standard - // library it'll get discarded and the whole application won't link. - // - // In this loop we're calculating the `group_end`, after which crate to - // pass `--end-group` and `group_start`, before which crate to pass - // `--start-group`. We currently do this by passing `--end-group` after - // the first crate (when iterating backwards) that requires a lang item - // defined somewhere else. Once that's set then when we've defined all the - // necessary lang items we'll pass `--start-group`. - // - // Note that this isn't amazing logic for now but it should do the trick - // for the current implementation of the standard library. - let mut group_end = None; - let mut group_start = None; - // Crates available for linking thus far. - let mut available = FxHashSet::default(); - // Crates required to satisfy dependencies discovered so far. - let mut required = FxHashSet::default(); - - let info = &codegen_results.crate_info; - for &cnum in deps.iter().rev() { - if let Some(missing) = info.missing_lang_items.get(&cnum) { - let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied()); - required.extend(missing_crates); - } - - required.insert(Some(cnum)); - available.insert(Some(cnum)); - - if required.len() > available.len() && group_end.is_none() { - group_end = Some(cnum); - } - if required.len() == available.len() && group_end.is_some() { - group_start = Some(cnum); - break; - } - } - - // If we didn't end up filling in all lang items from upstream crates then - // we'll be filling it in with our crate. This probably means we're the - // standard library itself, so skip this for now. - if group_end.is_some() && group_start.is_none() { - group_end = None; - } - let mut compiler_builtins = None; let search_path = OnceCell::new(); for &cnum in deps.iter() { - if group_start == Some(cnum) { - cmd.group_start(); - } - // We may not pass all crates through to the linker. Some crates may // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. let src = &codegen_results.crate_info.used_crate_source[&cnum]; match data[cnum.as_usize() - 1] { _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { - add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); + add_static_crate( + cmd, + sess, + archive_builder_builder, + codegen_results, + tmpdir, + cnum, + &Default::default(), + ); } // compiler-builtins are always placed last to ensure that they're // linked correctly. @@ -2394,17 +2412,41 @@ fn add_upstream_rust_crates<'a>( } Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); + let bundled_libs = if sess.opts.unstable_opts.packed_bundled_libs { + codegen_results.crate_info.native_libraries[&cnum] + .iter() + .filter_map(|lib| lib.filename) + .collect::>() + } else { + Default::default() + }; + add_static_crate( + cmd, + sess, + archive_builder_builder, + codegen_results, + tmpdir, + cnum, + &bundled_libs, + ); // Link static native libs with "-bundle" modifier only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically // or is an rlib already included via some other dylib crate, the symbols from // native libs will have already been included in that dylib. // - // If -Zlink-native-libraries=false is set, then the assumption is that an + // If `-Zlink-native-libraries=false` is set, then the assumption is that an // external build system already has the native dependencies defined, and it // will provide them to the linker itself. if sess.opts.unstable_opts.link_native_libraries { + if sess.opts.unstable_opts.packed_bundled_libs { + // If rlib contains native libs as archives, unpack them to tmpdir. + let rlib = &src.rlib.as_ref().unwrap().0; + archive_builder_builder + .extract_bundled_libs(rlib, tmpdir, &bundled_libs) + .unwrap_or_else(|e| sess.fatal(e)); + } + let mut last = (None, NativeLibKind::Unspecified, None); for lib in &codegen_results.crate_info.native_libraries[&cnum] { let Some(name) = lib.name else { @@ -2437,6 +2479,14 @@ fn add_upstream_rust_crates<'a>( bundle: Some(false), whole_archive: Some(false) | None, } => { + // HACK/FIXME: Fixup a circular dependency between libgcc and libc + // with glibc. This logic should be moved to the libc crate. + if sess.target.os == "linux" + && sess.target.env == "gnu" + && name == "c" + { + cmd.link_staticlib("gcc", false); + } cmd.link_staticlib(name, lib.verbatim.unwrap_or(false)); } NativeLibKind::LinkArg => { @@ -2446,20 +2496,23 @@ fn add_upstream_rust_crates<'a>( | NativeLibKind::Framework { .. } | NativeLibKind::Unspecified | NativeLibKind::RawDylib => {} - NativeLibKind::Static { - bundle: Some(true) | None, - whole_archive: _, - } => {} + NativeLibKind::Static { bundle: Some(true) | None, whole_archive } => { + if sess.opts.unstable_opts.packed_bundled_libs { + // If rlib contains native libs as archives, they are unpacked to tmpdir. + let path = tmpdir.join(lib.filename.unwrap().as_str()); + if whole_archive == Some(true) { + cmd.link_whole_rlib(&path); + } else { + cmd.link_rlib(&path); + } + } + } } } } } Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0), } - - if group_end == Some(cnum) { - cmd.group_end(); - } } // compiler-builtins are always placed last to ensure that they're @@ -2468,7 +2521,15 @@ fn add_upstream_rust_crates<'a>( // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic` // is used) if let Some(cnum) = compiler_builtins { - add_static_crate(cmd, sess, archive_builder_builder, codegen_results, tmpdir, cnum); + add_static_crate( + cmd, + sess, + archive_builder_builder, + codegen_results, + tmpdir, + cnum, + &Default::default(), + ); } // Converts a library file-stem into a cc -l argument @@ -2501,6 +2562,7 @@ fn add_upstream_rust_crates<'a>( codegen_results: &CodegenResults, tmpdir: &Path, cnum: CrateNum, + bundled_lib_file_names: &FxHashSet, ) { let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; @@ -2529,6 +2591,7 @@ fn add_upstream_rust_crates<'a>( let dst = tmpdir.join(cratepath.file_name().unwrap()); let name = cratepath.file_name().unwrap().to_str().unwrap(); let name = &name[3..name.len() - 5]; // chop off lib/.rlib + let bundled_lib_file_names = bundled_lib_file_names.clone(); sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| { let canonical_name = name.replace('-', "_"); @@ -2562,6 +2625,15 @@ fn add_upstream_rust_crates<'a>( let skip_because_lto = upstream_rust_objects_already_included && is_rust_object && is_builtins; + // We skip native libraries because: + // 1. This native libraries won't be used from the generated rlib, + // so we can throw them away to avoid the copying work. + // 2. We can't allow it to be a single remaining entry in archive + // as some linkers may complain on that. + if bundled_lib_file_names.contains(&Symbol::intern(f)) { + return true; + } + if skip_because_cfg_say_so || skip_because_lto { return true; } @@ -2657,7 +2729,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { } } -fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { +pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { match sess.lto() { config::Lto::Fat => true, config::Lto::Thin => { @@ -2674,11 +2746,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { let os = &sess.target.os; let llvm_target = &sess.target.llvm_target; if sess.target.vendor != "apple" - || !matches!(os.as_ref(), "ios" | "tvos" | "watchos") + || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos") || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64)) { return; } + + if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) { + return; + } + let sdk_name = match (arch.as_ref(), os.as_ref()) { ("aarch64", "tvos") => "appletvos", ("x86_64", "tvos") => "appletvsimulator", @@ -2694,6 +2771,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator", ("aarch64", "watchos") => "watchos", ("arm", "watchos") => "watchos", + (_, "macos") => "macosx", _ => { sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os)); return; @@ -2777,20 +2855,24 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { - let tools_path = sess.get_tools_search_paths(false); - let gcc_ld_dir = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .find(|p| { - p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() - }) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); - cmd.arg({ - let mut arg = OsString::from("-B"); - arg.push(gcc_ld_dir); - arg - }); - cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str())); + // Implement the "self-contained" part of -Zgcc-ld + // by adding rustc distribution directories to the tool search path. + for path in sess.get_tools_search_paths(false) { + cmd.arg({ + let mut arg = OsString::from("-B"); + arg.push(path.join("gcc-ld")); + arg + }); + } + // Implement the "linker flavor" part of -Zgcc-ld + // by asking cc to use some kind of lld. + cmd.arg("-fuse-ld=lld"); + if sess.target.lld_flavor != LldFlavor::Ld { + // 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). + cmd.arg(format!("--target={}", sess.target.llvm_target)); + } } } } else { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index ce51b2e95..e505543b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,4 +1,3 @@ -use super::archive; use super::command::Command; use super::symbol_export; use rustc_span::symbol::sym; @@ -11,6 +10,7 @@ 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::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; use rustc_middle::ty::TyCtxt; @@ -126,29 +126,26 @@ pub fn get_linker<'a>( // to the linker args construction. assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); match flavor { - LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { - Box::new(MsvcLinker { cmd, sess }) as Box - } - LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box, LinkerFlavor::Gcc => { Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false }) as Box } - + LinkerFlavor::Ld if sess.target.os == "l4re" => { + Box::new(L4Bender::new(cmd, sess)) as Box + } LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Ld => { Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true }) as Box } - + LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { + Box::new(MsvcLinker { cmd, sess }) as Box + } LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box, - - LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box, - - LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box, - - LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box, + LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box, + LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box, + LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box, } } @@ -186,8 +183,6 @@ pub trait Linker { 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 group_start(&mut self); - fn group_end(&mut self); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} fn add_no_exec(&mut self) {} @@ -519,7 +514,7 @@ impl<'a> Linker for GccLinker<'a> { // -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 lib = archive::find_library(lib, verbatim, search_path, &self.sess); + let lib = find_native_static_library(lib, Some(verbatim), search_path, &self.sess); self.linker_arg(&lib); } } @@ -733,18 +728,6 @@ impl<'a> Linker for GccLinker<'a> { self.hint_dynamic(); // Reset to default before returning the composed command line. } - fn group_start(&mut self) { - if self.takes_hints() { - self.linker_arg("--start-group"); - } - } - - fn group_end(&mut self) { - if self.takes_hints() { - self.linker_arg("--end-group"); - } - } - fn linker_plugin_lto(&mut self) { match self.sess.opts.cg.linker_plugin_lto { LinkerPluginLto::Disabled => { @@ -1022,10 +1005,6 @@ impl<'a> Linker for MsvcLinker<'a> { } } - // MSVC doesn't need group indicators - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing } @@ -1168,10 +1147,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - // Appears not necessary on Emscripten - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing } @@ -1347,10 +1322,6 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} - // Not needed for now with LLD - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing for now } @@ -1479,14 +1450,6 @@ impl<'a> Linker for L4Bender<'a> { self.hint_static(); // Reset to default before returning the composed command line. } - fn group_start(&mut self) { - self.cmd.arg("--start-group"); - } - - fn group_end(&mut self) { - self.cmd.arg("--end-group"); - } - fn linker_plugin_lto(&mut self) {} fn control_flow_guard(&mut self) {} @@ -1667,10 +1630,6 @@ impl<'a> Linker for PtxLinker<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn group_start(&mut self) {} - - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) {} } @@ -1780,9 +1739,5 @@ impl<'a> Linker for BpfLinker<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn group_start(&mut self) {} - - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) {} } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 0302c2881..99ddd1764 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -117,6 +117,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Architecture::Riscv32, "riscv64" => Architecture::Riscv64, "sparc64" => Architecture::Sparc64, + "avr" => Architecture::Avr, + "msp430" => Architecture::Msp430, + "hexagon" => Architecture::Hexagon, + "bpf" => Architecture::Bpf, // Unsupported architecture. _ => return None, }; @@ -187,12 +191,12 @@ pub enum MetadataPosition { Last, } -// For rlibs we "pack" rustc metadata into a dummy object file. When rustc -// creates a dylib crate type it will pass `--whole-archive` (or the -// platform equivalent) to include all object files from an rlib into the -// final dylib itself. This causes linkers to iterate and 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 will be able to process. +// 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 diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index e6b605575..8d7e2c5cf 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -103,18 +103,14 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< } }) .map(|def_id| { - let (export_level, used) = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; - // We won't link right if these symbols are stripped during LTO. - let used = match name { - "rust_eh_personality" - | "rust_eh_register_frames" - | "rust_eh_unregister_frames" => true, - _ => false, - }; - (SymbolExportLevel::Rust, used) + // 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()), false) + symbol_export_level(tcx, def_id.to_def_id()) }; let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); debug!( @@ -544,7 +540,7 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( .map(|fnabi| (fnabi.conv, &fnabi.args[..])) .unwrap_or((Conv::Rust, &[])); - // Decorate symbols with prefices, suffices and total number of bytes of arguments. + // 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 => ("@", "@"), diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 1b5ad8710..68f3b19b7 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -15,7 +15,7 @@ use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::profiling::VerboseTimingGuard; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; -use rustc_errors::{DiagnosticId, FatalError, Handler, Level}; +use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level}; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ @@ -256,8 +256,11 @@ impl ModuleConfig { { MergeFunctions::Disabled => false, MergeFunctions::Trampolines | MergeFunctions::Aliases => { - sess.opts.optimize == config::OptLevel::Default - || sess.opts.optimize == config::OptLevel::Aggressive + use config::OptLevel::*; + match sess.opts.optimize { + Aggressive | Default | SizeMin | Size => true, + Less | No => false, + } } }, @@ -1737,6 +1740,16 @@ impl SharedEmitter { } } +impl Translate for SharedEmitter { + fn fluent_bundle(&self) -> Option<&Lrc> { + None + } + + fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { + panic!("shared emitter attempted to translate a diagnostic"); + } +} + impl Emitter for SharedEmitter { fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) { let fluent_args = self.to_fluent_args(diag.args()); @@ -1758,14 +1771,6 @@ impl Emitter for SharedEmitter { fn source_map(&self) -> Option<&Lrc> { None } - - fn fluent_bundle(&self) -> Option<&Lrc> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - panic!("shared emitter attempted to translate a diagnostic"); - } } impl SharedEmitterMain { @@ -1887,7 +1892,7 @@ impl OngoingCodegen { } }); - sess.cgu_reuse_tracker.check_expected_reuse(sess.diagnostic()); + sess.cgu_reuse_tracker.check_expected_reuse(sess); sess.abort_if_errors(); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a840b2709..b98ff4957 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,3 +1,4 @@ +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, @@ -12,7 +13,7 @@ use crate::traits::*; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; use rustc_attr as attr; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_iter; @@ -21,10 +22,12 @@ use rustc_data_structures::sync::ParallelIterator; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; +use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS; use rustc_index::vec::Idx; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; 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::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; @@ -34,6 +37,7 @@ use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; +use rustc_span::Symbol; use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_target::abi::{Align, VariantIdx}; @@ -151,6 +155,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( 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; } @@ -162,6 +167,11 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if let Some(entry_idx) = vptr_entry_idx { let ptr_ty = cx.type_i8p(); let ptr_align = cx.tcx().data_layout.pointer_align.abi; + let vtable_ptr_ty = cx.scalar_pair_element_backend_type( + cx.layout_of(cx.tcx().mk_mut_ptr(target)), + 1, + true, + ); let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty)); let gep = bx.inbounds_gep( ptr_ty, @@ -172,7 +182,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.nonnull_metadata(new_vptr); // VTable loads are invariant. bx.set_invariant_load(new_vptr); - new_vptr + bx.pointercast(new_vptr, vtable_ptr_ty) } else { old_info } @@ -388,15 +398,14 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let main_llfn = cx.get_fn_addr(instance); - let use_start_lang_item = EntryFnType::Start != entry_type; - let entry_fn = create_entry_fn::(cx, main_llfn, main_def_id, use_start_lang_item); + 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, - use_start_lang_item: bool, + entry_type: EntryFnType, ) -> Bx::Function { // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, // depending on whether the target needs `argc` and `argv` to be passed in. @@ -441,7 +450,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let i8pp_ty = cx.type_ptr_to(cx.type_i8p()); let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); - let (start_fn, start_ty, args) = if use_start_lang_item { + let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type { let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); let start_fn = cx.get_fn_addr( ty::Instance::resolve( @@ -453,8 +462,13 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .unwrap() .unwrap(), ); - let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty); - (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv]) + + 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, i8pp_ty, i8_ty], isize_ty); + (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe]) } else { debug!("using user-defined start fn"); let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty); @@ -810,21 +824,16 @@ impl CrateInfo { crate_name: Default::default(), used_crates, used_crate_source: Default::default(), - lang_item_to_crate: Default::default(), - missing_lang_items: Default::default(), dependency_formats: tcx.dependency_formats(()).clone(), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; - let lang_items = tcx.lang_items(); - let crates = tcx.crates(()); let n_crates = crates.len(); info.native_libraries.reserve(n_crates); info.crate_name.reserve(n_crates); info.used_crate_source.reserve(n_crates); - info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { info.native_libraries @@ -842,17 +851,41 @@ impl CrateInfo { if tcx.is_no_builtins(cnum) { info.is_no_builtins.insert(cnum); } - let missing = tcx.missing_lang_items(cnum); - for &item in missing.iter() { - if let Ok(id) = lang_items.require(item) { - info.lang_item_to_crate.insert(item, id.krate); - } - } + } - // No need to look for lang items that don't actually need to exist. - let missing = - missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect(); - info.missing_lang_items.insert(cnum, missing); + // 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: FxHashSet<&Symbol> = info + .used_crates + .iter() + .flat_map(|cnum| { + tcx.missing_lang_items(*cnum) + .iter() + .filter(|l| lang_items::required(tcx, **l)) + .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item)) + }) + .collect(); + let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" }; + info.linked_symbols + .iter_mut() + .filter(|(crate_type, _)| { + !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) + }) + .for_each(|(_, linked_symbols)| { + linked_symbols.extend( + missing_weak_lang_items + .iter() + .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)), + ) + }); } let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type { @@ -873,7 +906,7 @@ impl CrateInfo { } }); - if tcx.sess.target.is_like_msvc && embed_visualizers { + if target.is_like_msvc && embed_visualizers { info.natvis_debugger_visualizers = collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis); } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 8cd5a0fc2..135ed680d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -18,11 +18,10 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability}; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; -use rustc_target::abi::{Integer, TagEncoding, Variants}; +use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; +use rustc_target::abi::Integer; use smallvec::SmallVec; -use std::borrow::Cow; use std::fmt::Write; use crate::debuginfo::wants_c_like_enum_debuginfo; @@ -98,7 +97,6 @@ fn push_debuginfo_type_name<'tcx>( if let Some(ty_and_layout) = layout_for_cpp_like_fallback { msvc_enum_fallback( - tcx, ty_and_layout, &|output, visited| { push_item_name(tcx, def.did(), true, output); @@ -391,11 +389,10 @@ fn push_debuginfo_type_name<'tcx>( // Name will be "{closure_env#0}", "{generator_env#0}", or // "{async_fn_env#0}", etc. // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of - // an artificial `enum$<>` type, as defined in msvc_enum_fallback(). + // an artificial `enum2$<>` type, as defined in msvc_enum_fallback(). if cpp_like_debuginfo && t.is_generator() { let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap(); msvc_enum_fallback( - tcx, ty_and_layout, &|output, visited| { push_closure_or_generator_name(tcx, def_id, substs, true, output, visited); @@ -428,58 +425,17 @@ fn push_debuginfo_type_name<'tcx>( /// 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 `src/etc/natvis/intrinsic.natvis` and - // `EnumMemberDescriptionFactor::create_member_descriptions`. + // debugger. For more information, look in + // rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs. fn msvc_enum_fallback<'tcx>( - tcx: TyCtxt<'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)); - let ty = ty_and_layout.ty; - - output.push_str("enum$<"); + output.push_str("enum2$<"); push_inner(output, visited); - - let variant_name = |variant_index| match ty.kind() { - ty::Adt(adt_def, _) => { - debug_assert!(adt_def.is_enum()); - Cow::from(adt_def.variant(variant_index).name.as_str()) - } - ty::Generator(..) => GeneratorSubsts::variant_name(variant_index), - _ => unreachable!(), - }; - - if let Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, - tag, - variants, - .. - } = &ty_and_layout.variants - { - let dataful_variant_layout = &variants[*dataful_variant]; - - // calculate the range of values for the dataful variant - let dataful_discriminant_range = - dataful_variant_layout.largest_niche().unwrap().valid_range; - - let min = dataful_discriminant_range.start; - let min = tag.size(&tcx).truncate(min); - - let max = dataful_discriminant_range.end; - let max = tag.size(&tcx).truncate(max); - - let dataful_variant_name = variant_name(*dataful_variant); - write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap(); - } else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants { - // Uninhabited enums can't be constructed and should never need to be visualized so - // skip this step for them. - if !ty_and_layout.abi.is_uninhabited() { - write!(output, ", {}", variant_name(*variant_idx)).unwrap(); - } - } push_close_angle_bracket(true, output); } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1802eedf1..e736b2aba 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,7 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] #![feature(try_blocks)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(associated_type_bounds)] #![feature(strict_provenance)] @@ -25,7 +25,6 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; -use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; @@ -113,6 +112,7 @@ bitflags::bitflags! { pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, + pub filename: Option, pub cfg: Option, pub verbatim: Option, pub dll_imports: Vec, @@ -122,6 +122,7 @@ 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, @@ -152,8 +153,6 @@ pub struct CrateInfo { pub used_libraries: Vec, pub used_crate_source: FxHashMap>, pub used_crates: Vec, - pub lang_item_to_crate: FxHashMap, - pub missing_lang_items: FxHashMap>, pub dependency_formats: Lrc, pub windows_subsystem: Option, pub natvis_debugger_visualizers: BTreeSet, @@ -168,6 +167,13 @@ pub struct CodegenResults { pub crate_info: CrateInfo, } +pub enum CodegenErrors<'a> { + WrongFileType, + EmptyVersionNumber, + EncodingVersionMismatch { version_array: String, rlink_version: u32 }, + RustcVersionMismatch { rustc_version: String, current_version: &'a str }, +} + pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); crate::base::provide(providers); @@ -212,30 +218,34 @@ impl CodegenResults { encoder.finish() } - pub fn deserialize_rlink(data: Vec) -> Result { + pub fn deserialize_rlink<'a>(data: Vec) -> Result> { // 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("The input does not look like a .rlink file".to_string()); + return Err(CodegenErrors::WrongFileType); } let data = &data[RLINK_MAGIC.len()..]; if data.len() < 4 { - return Err("The input does not contain version number".to_string()); + 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(".rlink file was produced with encoding version {version_array}, but the current version is {RLINK_VERSION}".to_string()); + 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(); let current_version = RUSTC_VERSION.unwrap(); if rustc_version != current_version { - return Err(format!( - ".rlink file was produced by rustc version {rustc_version}, but the current version is {current_version}." - )); + return Err(CodegenErrors::RustcVersionMismatch { + rustc_version: rustc_version.to_string(), + current_version, + }); } let codegen_results = CodegenResults::decode(&mut decoder); diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 27d791d90..cae46ebd2 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -1,6 +1,6 @@ use crate::traits::*; -use rustc_middle::ty::{self, subst::GenericArgKind, ExistentialPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; use rustc_session::config::Lto; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::call::FnAbi; @@ -29,7 +29,7 @@ impl<'a, 'tcx> VirtualIndex { && bx.cx().sess().lto() == Lto::Fat { let typeid = - bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), get_trait_ref(bx.tcx(), ty))); + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty))); let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes(); let type_checked_load = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); let func = bx.extract_value(type_checked_load, 0); @@ -64,17 +64,13 @@ impl<'a, 'tcx> VirtualIndex { } } -fn get_trait_ref<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> { +/// This takes a valid `self` receiver type and extracts the principal trait +/// ref of the type. +fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Dynamic(trait_refs, _) = ty.kind() { - return trait_refs[0].map_bound(|trait_ref| match trait_ref { - ExistentialPredicate::Trait(tr) => tr, - ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), - ExistentialPredicate::AutoTrait(_) => { - bug!("auto traits don't have functions") - } - }); + if let ty::Dynamic(data, _, _) = ty.kind() { + return data.principal().expect("expected principal trait object"); } } } @@ -90,6 +86,7 @@ fn get_trait_ref<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::PolyExistentialTr /// 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>, @@ -97,8 +94,6 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let tcx = cx.tcx(); - debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); - // Check the cache. if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { return val; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 24da48ead..c7617d2e4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -266,7 +266,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec, mir: &mir::Body<'tcx>, ) { - for (bb, data) in mir.basic_blocks().iter_enumerated() { + for (bb, data) in mir.basic_blocks.iter_enumerated() { match data.terminator().kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume @@ -296,7 +296,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec(result: &mut IndexVec, mir: &mir::Body<'tcx>) { - let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks()); + 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 => { @@ -359,7 +359,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec> FunctionCx<'a, 'tcx, Bx> { bx.unreachable(); return; } - let llval = match self.fn_abi.ret.mode { + let llval = match &self.fn_abi.ret.mode { PassMode::Ignore | PassMode::Indirect { .. } => { bx.ret_void(); return; @@ -339,7 +338,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - PassMode::Cast(cast_ty) => { + PassMode::Cast(cast_ty, _) => { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(Some(op)) => op, LocalRef::Operand(None) => bug!("use of return before def"), @@ -360,7 +359,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llval } }; - let ty = bx.cast_backend_type(&cast_ty); + let ty = bx.cast_backend_type(cast_ty); let addr = bx.pointercast(llslot, bx.type_ptr_to(ty)); bx.load(ty, addr, self.fn_abi.ret.layout.align.abi) } @@ -368,6 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.ret(llval); } + #[tracing::instrument(level = "trace", skip(self, helper, bx))] fn codegen_drop_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -398,13 +398,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? - ty::Dynamic(..) => { + 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), substs: drop_fn.substs, }; + 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) @@ -412,6 +428,51 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, ) } + 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), + substs: drop_fn.substs, + }; + 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 data = args[0]; + let data_ty = bx.cx().backend_type(place.layout); + let vtable_ptr = + bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]); + let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE); + // Truncate vtable off of args list + args = &args[..1]; + debug!("args' = {:?}", args); + ( + meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) + .get_fn(&mut bx, vtable, ty, &fn_abi), + fn_abi, + ) + } _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())), }; helper.do_call( @@ -798,58 +859,78 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let mut op = self.codegen_operand(&mut bx, arg); if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { - if let Pair(..) = op.val { - // 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 - 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() - { - for i in 0..op.layout.fields.count() { - let field = op.extract_field(&mut bx, i); - if !field.layout.is_zst() { - // we found the one non-zero-sized field that is allowed - // now find *its* non-zero-sized field, or stop if it's a - // pointer - op = field; - continue 'descend_newtypes; + 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 + 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() + && !op.layout.ty.is_region_ptr() + { + for i in 0..op.layout.fields.count() { + let field = op.extract_field(&mut bx, i); + if !field.layout.is_zst() { + // we found the one non-zero-sized field that is allowed + // now find *its* non-zero-sized field, or stop if it's a + // pointer + op = field; + continue 'descend_newtypes; + } } + + span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); } - span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); + // 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( + &mut bx, + meta, + op.layout.ty, + &fn_abi, + )); + llargs.push(data_ptr); + continue 'make_args; } - - // 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 - match op.val { - Pair(data_ptr, meta) => { - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - &mut 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( + &mut bx, + meta, + op.layout.ty, + &fn_abi, + )); + llargs.push(data_ptr); + continue; + } + Immediate(_) => { + let ty::Ref(_, ty, _) = op.layout.ty.kind() else { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + }; + if !ty.is_dyn_star() { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); } - other => bug!("expected a Pair, got {:?}", other), + // FIXME(dyn-star): Make sure this is done on a &dyn* receiver + let place = op.deref(bx.cx()); + let data_ptr = place.project_field(&mut bx, 0); + let meta_ptr = place.project_field(&mut bx, 1); + let meta = bx.load_operand(meta_ptr); + llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( + &mut 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); } - } else if let Ref(data_ptr, Some(meta), _) = op.val { - // by-value dynamic dispatch - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - &mut bx, - meta, - op.layout.ty, - &fn_abi, - )); - llargs.push(data_ptr); - continue; - } else { - span_bug!(span, "can't codegen a virtual call on {:?}", op); } } @@ -1161,39 +1242,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs: &mut Vec, arg: &ArgAbi<'tcx, Ty<'tcx>>, ) { - // Fill padding with undef value, where applicable. - if let Some(ty) = arg.pad { - llargs.push(bx.const_undef(bx.reg_backend_type(&ty))) - } - - if arg.is_ignore() { - return; - } - - if let PassMode::Pair(..) = arg.mode { - match op.val { + match arg.mode { + PassMode::Ignore => return, + PassMode::Cast(_, 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), - } - } else if arg.is_unsized_indirect() { - match op.val { + }, + PassMode::Indirect { attrs: _, extra_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 { .. } | PassMode::Cast(_) => { + PassMode::Indirect { .. } | PassMode::Cast(..) => { let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) @@ -1225,8 +1302,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if let PassMode::Cast(ty) = arg.mode { - let llty = bx.cast_backend_type(&ty); + if let PassMode::Cast(ty, _) = &arg.mode { + let llty = bx.cast_backend_type(ty); let addr = bx.pointercast(llval, bx.type_ptr_to(llty)); llval = bx.load(llty, addr, align.min(arg.layout.align.abi)); } else { @@ -1625,7 +1702,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } DirectOperand(index) => { // If there is a cast, we have to store and reload. - let op = if let PassMode::Cast(_) = ret_abi.mode { + 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); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 9a995fbf6..4c6ab457c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -25,26 +25,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { let ct = self.monomorphize(constant.literal); - let ct = match ct { - mir::ConstantKind::Ty(ct) => ct, + let uv = match ct { + mir::ConstantKind::Ty(ct) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv.expand(), + ty::ConstKind::Value(val) => { + return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val))); + } + err => span_bug!( + constant.span, + "encountered bad ConstKind after monomorphizing: {:?}", + err + ), + }, + mir::ConstantKind::Unevaluated(uv, _) => uv, mir::ConstantKind::Val(val, _) => return Ok(val), }; - match ct.kind() { - ty::ConstKind::Unevaluated(ct) => self - .cx - .tcx() - .const_eval_resolve(ty::ParamEnv::reveal_all(), ct, None) - .map_err(|err| { - self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); - err - }), - ty::ConstKind::Value(val) => Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val))), - err => span_bug!( - constant.span, - "encountered bad ConstKind after monomorphizing: {:?}", - err - ), - } + + self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| { + self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); + err + }) } /// process constant containing SIMD shuffle indices diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 8c3186efc..157c1c823 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -3,7 +3,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; @@ -93,15 +93,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } /// 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 - /// (unless the crate is being compiled with `-Z debug-macros`). + /// 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, mut span: Span) -> Span { // Bail out if debug info emission is not enabled. if self.debug_context.is_none() { return span; } - if span.from_expansion() && !self.cx.sess().opts.unstable_opts.debug_macros { + if self.cx.tcx().should_collapse_debuginfo(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. diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 94ac71a4d..215edbe02 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -77,10 +77,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let llval = match name { - sym::assume => { - bx.assume(args[0].immediate()); - return; - } sym::abort => { bx.abort(); return; @@ -555,14 +551,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + sym::ptr_guaranteed_cmp => { let a = args[0].immediate(); let b = args[1].immediate(); - if name == sym::ptr_guaranteed_eq { - bx.icmp(IntPredicate::IntEQ, a, b) - } else { - bx.icmp(IntPredicate::IntNE, a, b) - } + bx.icmp(IntPredicate::IntEQ, a, b) } sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { @@ -597,8 +589,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty) = fn_abi.ret.mode { - let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty)); + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { + let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(ty)); let ptr = bx.pointercast(result.llval, ptr_llty); bx.store(llval, ptr, result.align); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 8ee375fa9..2b931bfc9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -150,13 +150,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let start_llbb = Bx::append_block(cx, llfn, "start"); let mut bx = Bx::build(cx, start_llbb); - if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) { + if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) { bx.set_personality_fn(cx.eh_personality()); } let cleanup_kinds = analyze::cleanup_kinds(&mir); let cached_llbbs: IndexVec> = mir - .basic_blocks() + .basic_blocks .indices() .map(|bb| if bb == mir::START_BLOCK { Some(start_llbb) } else { None }) .collect(); @@ -172,8 +172,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( unreachable_block: None, double_unwind_guard: None, cleanup_kinds, - landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), - funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks().len()), + landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), + funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), locals: IndexVec::new(), debug_context, per_local_var_debug_info: None, @@ -191,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // errored or at least linted ErrorHandled::Reported(_) | ErrorHandled::Linted => {} ErrorHandled::TooGeneric => { - span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err) + span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) } } } @@ -283,7 +283,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_abi.args[idx]; idx += 1; - if arg.pad.is_some() { + if let PassMode::Cast(_, true) = arg.mode { llarg_idx += 1; } let pr_field = place.project_field(bx, i); @@ -309,7 +309,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let arg = &fx.fn_abi.args[idx]; idx += 1; - if arg.pad.is_some() { + if let PassMode::Cast(_, true) = arg.mode { llarg_idx += 1; } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c612634fc..37b1e0362 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -72,10 +72,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ) -> Self { let layout = bx.layout_of(ty); - if layout.is_zst() { - return OperandRef::new_zst(bx, layout); - } - let val = match val { ConstValue::Scalar(x) => { let Abi::Scalar(scalar) = layout.abi else { @@ -84,10 +80,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } - ConstValue::ZeroSized => { - let llval = bx.zst_to_backend(bx.immediate_backend_type(layout)); - OperandValue::Immediate(llval) - } + ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout), ConstValue::Slice { data, start, end } => { let Abi::ScalarPair(a_scalar, _) = layout.abi else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 268c4d765..13d8f6edd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::glue; use crate::traits::*; -use crate::MemFlags; use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; @@ -245,7 +244,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { }; bx.intcast(tag.immediate(), cast_to, signed) } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. let niche_llty = bx.cx().immediate_backend_type(tag.layout); @@ -303,7 +302,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx.select( is_niche, niche_discr, - bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64), + bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), ) } } @@ -338,21 +337,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } Variants::Multiple { tag_encoding: - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, tag_field, .. } => { - if variant_index != dataful_variant { - if bx.cx().sess().target.arch == "arm" - || bx.cx().sess().target.arch == "aarch64" - { - // FIXME(#34427): as workaround for LLVM bug on ARM, - // use memset of 0 before assigning niche value. - let fill_byte = bx.cx().const_u8(0); - let size = bx.cx().const_usize(self.layout.size.bytes()); - bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); - } - + 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(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 26b9fbf44..56852b0fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,6 +4,7 @@ use super::{FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; +use crate::meth::get_vtable; use crate::traits::*; use crate::MemFlags; @@ -87,7 +88,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let size = bx.const_usize(dest.layout.size.bytes()); // Use llvm.memset.p0i8.* to initialize all zero arrays - if bx.cx().const_to_opt_uint(v) == Some(0) { + 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 bx; @@ -271,6 +272,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } + mir::CastKind::DynStar => { + let data = match operand.val { + OperandValue::Ref(_, _, _) => todo!(), + OperandValue::Immediate(v) => v, + OperandValue::Pair(_, _) => todo!(), + }; + let trait_ref = + if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() { + data.principal() + } else { + bug!("Only valid to do a DynStar cast into a DynStar type") + }; + let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); + OperandValue::Pair(data, vtable) + } mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, ) diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f452f2988..1db0fb3a6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_middle::mir::NonDivergingIntrinsic; use super::FunctionCx; use super::LocalRef; @@ -73,11 +74,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope); bx } - mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { + mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { + let op_val = self.codegen_operand(&mut bx, op); + bx.assume(op_val.immediate()); + bx + } + mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + mir::CopyNonOverlapping { ref count, ref src, ref dst }, + )) => { let dst_val = self.codegen_operand(&mut bx, dst); let src_val = self.codegen_operand(&mut bx, src); let count = self.codegen_operand(&mut bx, count).immediate(); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index ecad05185..0e259bcd1 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -210,8 +210,11 @@ const POWERPC_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("vsx", Some(sym::powerpc_target_feature)), ]; -const MIPS_ALLOWED_FEATURES: &[(&str, Option)] = - &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))]; +const MIPS_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("fp64", Some(sym::mips_target_feature)), + ("msa", Some(sym::mips_target_feature)), + ("virt", Some(sym::mips_target_feature)), +]; const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("m", Some(sym::riscv_target_feature)), @@ -227,6 +230,10 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("zhinxmin", Some(sym::riscv_target_feature)), ("zfh", Some(sym::riscv_target_feature)), ("zfhmin", Some(sym::riscv_target_feature)), + ("zba", Some(sym::riscv_target_feature)), + ("zbb", Some(sym::riscv_target_feature)), + ("zbc", Some(sym::riscv_target_feature)), + ("zbs", Some(sym::riscv_target_feature)), ("zbkb", Some(sym::riscv_target_feature)), ("zbkc", Some(sym::riscv_target_feature)), ("zbkx", Some(sym::riscv_target_feature)), diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9f49749bb..10cf8948b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,6 +1,5 @@ use super::abi::AbiBuilderMethods; use super::asm::AsmBuilderMethods; -use super::consts::ConstMethods; use super::coverageinfo::CoverageInfoBuilderMethods; use super::debuginfo::DebugInfoBuilderMethods; use super::intrinsic::IntrinsicCallMethods; @@ -15,7 +14,6 @@ use crate::mir::operand::OperandRef; use crate::mir::place::PlaceRef; use crate::MemFlags; -use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -188,8 +186,8 @@ pub trait BuilderMethods<'a, 'tcx>: 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) -> Option; - fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option; + 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; @@ -223,156 +221,7 @@ pub trait BuilderMethods<'a, 'tcx>: return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) }; } - let try_sat_result = - if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) }; - if let Some(try_sat_result) = try_sat_result { - return try_sat_result; - } - - let int_width = self.cx().int_width(int_ty); - let float_width = self.cx().float_width(float_ty); - // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the - // destination integer type after rounding towards zero. This `undef` value can cause UB in - // safe code (see issue #10184), so we implement a saturating conversion on top of it: - // Semantically, the mathematical value of the input is rounded towards zero to the next - // mathematical integer, and then the result is clamped into the range of the destination - // integer type. Positive and negative infinity are mapped to the maximum and minimum value of - // the destination integer type. NaN is mapped to 0. - // - // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to - // a value representable in int_ty. - // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. - // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. - // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly - // representable. Note that this only works if float_ty's exponent range is sufficiently large. - // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 - // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. - // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because - // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). - // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. - let int_max = |signed: bool, int_width: u64| -> u128 { - let shift_amount = 128 - int_width; - if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } - }; - let int_min = |signed: bool, int_width: u64| -> i128 { - if signed { i128::MIN >> (128 - int_width) } else { 0 } - }; - - let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { - let rounded_min = - ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero); - assert_eq!(rounded_min.status, Status::OK); - let rounded_max = - ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero); - assert!(rounded_max.value.is_finite()); - (rounded_min.value.to_bits(), rounded_max.value.to_bits()) - }; - let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) { - let rounded_min = - ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero); - assert_eq!(rounded_min.status, Status::OK); - let rounded_max = - ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero); - assert!(rounded_max.value.is_finite()); - (rounded_min.value.to_bits(), rounded_max.value.to_bits()) - }; - // To implement saturation, we perform the following steps: - // - // 1. Cast x to an integer with fpto[su]i. This may result in undef. - // 2. Compare x to f_min and f_max, and use the comparison results to select: - // a) int_ty::MIN if x < f_min or x is NaN - // b) int_ty::MAX if x > f_max - // c) the result of fpto[su]i otherwise - // 3. If x is NaN, return 0.0, otherwise return the result of step 2. - // - // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the - // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of - // undef does not introduce any non-determinism either. - // More importantly, the above procedure correctly implements saturating conversion. - // Proof (sketch): - // If x is NaN, 0 is returned by definition. - // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max. - // This yields three cases to consider: - // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with - // saturating conversion for inputs in that range. - // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded - // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger - // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX - // is correct. - // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals - // int_ty::MIN and therefore the return value of int_ty::MIN is correct. - // QED. - - let float_bits_to_llval = |bx: &mut Self, bits| { - let bits_llval = match float_width { - 32 => bx.cx().const_u32(bits as u32), - 64 => bx.cx().const_u64(bits as u64), - n => bug!("unsupported float width {}", n), - }; - bx.bitcast(bits_llval, float_ty) - }; - let (f_min, f_max) = match float_width { - 32 => compute_clamp_bounds_single(signed, int_width), - 64 => compute_clamp_bounds_double(signed, int_width), - n => bug!("unsupported float width {}", n), - }; - let f_min = float_bits_to_llval(self, f_min); - let f_max = float_bits_to_llval(self, f_max); - let int_max = self.cx().const_uint_big(int_ty, int_max(signed, int_width)); - let int_min = self.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128); - let zero = self.cx().const_uint(int_ty, 0); - - // If we're working with vectors, constants must be "splatted": the constant is duplicated - // into each lane of the vector. The algorithm stays the same, we are just using the - // same constant across all lanes. - let maybe_splat = |bx: &mut Self, val| { - if bx.cx().type_kind(dest_ty) == TypeKind::Vector { - bx.vector_splat(bx.vector_length(dest_ty), val) - } else { - val - } - }; - let f_min = maybe_splat(self, f_min); - let f_max = maybe_splat(self, f_max); - let int_max = maybe_splat(self, int_max); - let int_min = maybe_splat(self, int_min); - let zero = maybe_splat(self, zero); - - // Step 1 ... - let fptosui_result = if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) }; - let less_or_nan = self.fcmp(RealPredicate::RealULT, x, f_min); - let greater = self.fcmp(RealPredicate::RealOGT, x, f_max); - - // Step 2: We use two comparisons and two selects, with %s1 being the - // result: - // %less_or_nan = fcmp ult %x, %f_min - // %greater = fcmp olt %x, %f_max - // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result - // %s1 = select %greater, int_ty::MAX, %s0 - // Note that %less_or_nan uses an *unordered* comparison. This - // comparison is true if the operands are not comparable (i.e., if x is - // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if - // x is NaN. - // - // Performance note: Unordered comparison can be lowered to a "flipped" - // comparison and a negation, and the negation can be merged into the - // select. Therefore, it not necessarily any more expensive than an - // ordered ("normal") comparison. Whether these optimizations will be - // performed is ultimately up to the backend, but at least x86 does - // perform them. - let s0 = self.select(less_or_nan, int_min, fptosui_result); - let s1 = self.select(greater, int_max, s0); - - // Step 3: NaN replacement. - // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. - // Therefore we only need to execute this step for signed integer types. - if signed { - // LLVM has no isNaN predicate, so we use (x == x) instead - let cmp = self.fcmp(RealPredicate::RealOEQ, x, x); - self.select(cmp, s1, zero) - } else { - s1 - } + 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; diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 8a91d4735..fdc7a30e8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -29,7 +29,6 @@ pub trait ConstMethods<'tcx>: BackendTypes { 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 zst_to_backend(&self, llty: Self::Type) -> Self::Value; fn from_const_alloc( &self, layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 322bfd5ce..09d53331b 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -9,13 +9,13 @@ use rustc_span::{Span, Symbol}; use super::InterpCx; use crate::interpret::{ - struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, UnsupportedOpInfo, + struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, + UnsupportedOpInfo, }; /// The CTFE machine has some custom error kinds. #[derive(Clone, Debug)] pub enum ConstEvalErrKind { - NeedsRfc(String), ConstAccessesStatic, ModifiedGlobal, AssertFailure(AssertKind), @@ -42,9 +42,6 @@ impl fmt::Display for ConstEvalErrKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::ConstEvalErrKind::*; match *self { - NeedsRfc(ref msg) => { - write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg) - } ConstAccessesStatic => write!(f, "constant accesses static"), ModifiedGlobal => { write!(f, "modifying a static's initial value from another static's initializer") @@ -158,6 +155,7 @@ impl<'tcx> ConstEvalErr<'tcx> { InterpError::Unsupported( UnsupportedOpInfo::ReadPointerAsBytes | UnsupportedOpInfo::PartialPointerOverwrite(_) + | UnsupportedOpInfo::PartialPointerCopy(_), ) => { err.help("this code performed an operation that depends on the underlying bytes representing a pointer"); err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported"); 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 975fb4b22..a2f14e753 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,8 +2,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, - Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, - ScalarMaybeUninit, StackPopCleanup, InterpError, + Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, + RefTracking, StackPopCleanup, }; use rustc_hir::def::DefKind; @@ -74,14 +74,16 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; + ecx.machine.check_alignment = false; // interning doesn't need to respect alignment intern_const_alloc_recursive(ecx, intern_kind, &ret)?; + // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) } /// 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. +/// `simd_shuffle` and const patterns in match arms. It never performs alignment checks. /// /// 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 @@ -98,7 +100,11 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( tcx, root_span, param_env, - CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics), + CompileTimeInterpreter::new( + tcx.const_eval_limit(), + can_access_statics, + /*check_alignment:*/ false, + ), ) } @@ -166,10 +172,7 @@ pub(super) fn op_to_const<'tcx>( // see comment on `let try_as_immediate` above Err(imm) => match *imm { _ if imm.layout.is_zst() => ConstValue::ZeroSized, - Immediate::Scalar(x) => match x { - ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()), - }, + Immediate::Scalar(x) => ConstValue::Scalar(x), Immediate::ScalarPair(a, b) => { debug!("ScalarPair(a: {:?}, b: {:?})", a, b); // We know `offset` is relative to the allocation, so we can use `into_parts`. @@ -194,7 +197,7 @@ pub(super) fn op_to_const<'tcx>( } } -#[instrument(skip(tcx), level = "debug")] +#[instrument(skip(tcx), level = "debug", ret)] pub(crate) fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, @@ -203,7 +206,13 @@ pub(crate) fn turn_into_const_value<'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); - let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); + // This is just accessing an already computed constant, so no need to check alginment here. + let ecx = mk_eval_cx( + tcx, + tcx.def_span(key.value.instance.def_id()), + key.param_env, + /*can_access_statics:*/ is_static, + ); let mplace = ecx.raw_const_to_mplace(constant).expect( "can only fail if layout computation failed, \ @@ -215,10 +224,7 @@ pub(crate) fn turn_into_const_value<'tcx>( ); // Turn this into a proper constant. - let const_val = op_to_const(&ecx, &mplace.into()); - debug!(?const_val); - - const_val + op_to_const(&ecx, &mplace.into()) } #[instrument(skip(tcx), level = "debug")] @@ -300,7 +306,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>( key.param_env, // Statics (and promoteds inside statics) may access other statics, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. - CompileTimeInterpreter::new(tcx.const_eval_limit(), /*can_access_statics:*/ is_static), + CompileTimeInterpreter::new( + tcx.const_eval_limit(), + /*can_access_statics:*/ is_static, + /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks, + ), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a..e5acacd91 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -35,21 +35,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { // All `#[rustc_do_not_const_check]` functions should be hooked here. let def_id = instance.def_id(); - if Some(def_id) == self.tcx.lang_items().const_eval_select() { - // redirect to const_eval_select_ct - if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() { - return Ok(Some( - ty::Instance::resolve( - *self.tcx, - ty::ParamEnv::reveal_all(), - const_eval_select, - instance.substs, - ) - .unwrap() - .unwrap(), - )); - } - } else if Some(def_id) == self.tcx.lang_items().panic_display() + if Some(def_id) == self.tcx.lang_items().panic_display() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { // &str or &&str @@ -89,10 +75,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// exhaustion error. /// /// Setting this to `0` disables the limit and allows the interpreter to run forever. - pub steps_remaining: usize, + pub(super) steps_remaining: usize, /// The virtual call stack. - pub(crate) stack: Vec>, + pub(super) stack: Vec>, /// We need to make sure consts never point to anything mutable, even recursively. That is /// relied on for pattern matching on consts with references. @@ -101,14 +87,22 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// * Pointers to allocations inside of statics can never leak outside, to a non-static global. /// This boolean here controls the second part. pub(super) can_access_statics: bool, + + /// Whether to check alignment during evaluation. + pub(super) check_alignment: bool, } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(crate) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self { + pub(crate) fn new( + const_eval_limit: Limit, + can_access_statics: bool, + check_alignment: bool, + ) -> Self { CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new(), can_access_statics, + check_alignment, } } } @@ -197,34 +191,35 @@ impl interpret::MayLeak for ! { } impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> { + /// 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 { .. }) => a == b, - // Equality with integers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false, - // FIXME: return `true` 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). - (Scalar::Ptr(..), Scalar::Ptr(..)) => false, - }) - } - - fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> { - Ok(match (a, b) { - // Comparisons between integers are always known. - (Scalar::Int(_), Scalar::Int(_)) => a != b, + (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)) => { - int.is_null() && !self.scalar_may_be_null(ptr)? + | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) + if int.is_null() && !self.scalar_may_be_null(ptr)? => + { + 0 } - // FIXME: return `true` for at least some comparisons where we can reliably + // 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(..)) => false, + (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, }) } } @@ -236,6 +231,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + #[inline(always)] + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.check_alignment + } + + #[inline(always)] + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, @@ -251,9 +256,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ); throw_inval!(AlreadyReported(guar)); } else { + // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, + // so this should be unreachable. let path = ecx.tcx.def_path_str(def.did); - Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path)) - .into()) + bug!("trying to call extern function `{path}` at compile-time"); } } _ => Ok(ecx.tcx.instance_mir(instance)), @@ -321,22 +327,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // CTFE-specific intrinsics. let Some(ret) = target else { - return Err(ConstEvalErrKind::NeedsRfc(format!( - "calling intrinsic `{}`", - intrinsic_name - )) - .into()); + throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time"); }; match intrinsic_name { - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = ecx.read_immediate(&args[0])?.to_scalar()?; - let b = ecx.read_immediate(&args[1])?.to_scalar()?; - let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - ecx.guaranteed_eq(a, b)? - } else { - ecx.guaranteed_ne(a, b)? - }; - ecx.write_scalar(Scalar::from_bool(cmp), dest)?; + 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_machine_usize(ecx)?; @@ -382,11 +380,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } _ => { - return Err(ConstEvalErrKind::NeedsRfc(format!( - "calling intrinsic `{}`", - intrinsic_name - )) - .into()); + throw_unsup_format!( + "intrinsic `{intrinsic_name}` is not supported at compile-time" + ); } } @@ -429,7 +425,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _left: &ImmTy<'tcx>, _right: &ImmTy<'tcx>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) + throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { @@ -451,7 +447,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer, ) -> InterpResult<'tcx> { - Err(ConstEvalErrKind::NeedsRfc("exposing pointers".to_string()).into()) + // This is only reachable with -Zunleash-the-miri-inside-of-you. + throw_unsup_format!("exposing pointers is not possible at compile-time") } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 948c33494..d9c4ae4d5 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,16 +1,16 @@ // Not in interpret to make sure we do not use private implementation details +use crate::errors::MaxNumNodesInConstErr; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, + Scalar, +}; use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, - Scalar, -}; - mod error; mod eval_queries; mod fn_queries; @@ -72,12 +72,17 @@ pub(crate) fn eval_to_valtree<'tcx>( Ok(valtree) => Ok(Some(valtree)), Err(err) => { let did = cid.instance.def_id(); - let s = cid.display(tcx); + let global_const_id = cid.display(tcx); match err { ValTreeCreationError::NodesOverflow => { - let msg = format!("maximum number of nodes exceeded in constant {}", &s); + let msg = format!( + "maximum number of nodes exceeded in constant {}", + &global_const_id + ); let mut diag = match tcx.hir().span_if_local(did) { - Some(span) => tcx.sess.struct_span_err(span, &msg), + Some(span) => { + tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id }) + } None => tcx.sess.struct_err(&msg), }; diag.emit(); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 8fff4571d..a964fe846 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -3,7 +3,7 @@ use super::machine::CompileTimeEvalContext; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, - MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit, + MemoryKind, PlaceTy, Scalar, }; use crate::interpret::{MPlaceTy, Value}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; @@ -90,14 +90,14 @@ pub(crate) fn const_to_valtree_inner<'tcx>( let Ok(val) = ecx.read_immediate(&place.into()) else { return Err(ValTreeCreationError::Other); }; - let val = val.to_scalar().unwrap(); + let val = val.to_scalar(); *num_nodes += 1; Ok(ty::ValTree::Leaf(val.assert_int())) } // Raw pointers are not allowed in type level constants, as we cannot properly test them for - // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). + // equality at compile-time (see `ptr_guaranteed_cmp`). // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to // agree with runtime equality tests. ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType), @@ -204,7 +204,7 @@ fn get_info_on_unsized_field<'tcx>( (unsized_inner_ty, num_elems) } -#[instrument(skip(ecx), level = "debug")] +#[instrument(skip(ecx), level = "debug", ret)] fn create_pointee_place<'tcx>( ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, ty: Ty<'tcx>, @@ -237,14 +237,11 @@ fn create_pointee_place<'tcx>( let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap(); debug!(?ptr); - let place = MPlaceTy::from_aligned_ptr_with_meta( + MPlaceTy::from_aligned_ptr_with_meta( ptr.into(), layout, MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)), - ); - debug!(?place); - - place + ) } else { create_mplace_from_layout(ecx, ty) } @@ -253,7 +250,7 @@ fn create_pointee_place<'tcx>( /// 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")] +#[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -294,7 +291,7 @@ pub fn valtree_to_const_value<'tcx>( dump_place(&ecx, place.into()); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); - let const_val = match ty.kind() { + match ty.kind() { ty::Ref(_, _, _) => { let ref_place = place.to_ref(&tcx); let imm = @@ -303,10 +300,7 @@ pub fn valtree_to_const_value<'tcx>( op_to_const(&ecx, &imm.into()) } _ => op_to_const(&ecx, &place.into()), - }; - debug!(?const_val); - - const_val + } } ty::Never | ty::Error(_) @@ -349,11 +343,7 @@ fn valtree_into_mplace<'tcx>( ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { let scalar_int = valtree.unwrap_leaf(); debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); - ecx.write_immediate( - Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())), - &place.into(), - ) - .unwrap(); + ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap(); } ty::Ref(_, inner_ty, _) => { let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree); @@ -366,11 +356,10 @@ fn valtree_into_mplace<'tcx>( let imm = match inner_ty.kind() { ty::Slice(_) | ty::Str => { let len = valtree.unwrap_branch().len(); - let len_scalar = - ScalarMaybeUninit::Scalar(Scalar::from_machine_usize(len as u64, &tcx)); + let len_scalar = Scalar::from_machine_usize(len as u64, &tcx); Immediate::ScalarPair( - ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx), + Scalar::from_maybe_pointer((*pointee_place).ptr, &tcx), len_scalar, ) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index a463fe7b9..c3547cb3a 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -3,7 +3,7 @@ use rustc_macros::SessionDiagnostic; use rustc_span::Span; #[derive(SessionDiagnostic)] -#[error(const_eval::unstable_in_stable)] +#[diag(const_eval::unstable_in_stable)] pub(crate) struct UnstableInStable { pub gate: String, #[primary_span] @@ -22,14 +22,14 @@ pub(crate) struct UnstableInStable { } #[derive(SessionDiagnostic)] -#[error(const_eval::thread_local_access, code = "E0625")] +#[diag(const_eval::thread_local_access, code = "E0625")] pub(crate) struct NonConstOpErr { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(const_eval::static_access, code = "E0013")] +#[diag(const_eval::static_access, code = "E0013")] #[help] pub(crate) struct StaticAccessErr { #[primary_span] @@ -41,7 +41,7 @@ pub(crate) struct StaticAccessErr { } #[derive(SessionDiagnostic)] -#[error(const_eval::raw_ptr_to_int)] +#[diag(const_eval::raw_ptr_to_int)] #[note] #[note(const_eval::note2)] pub(crate) struct RawPtrToIntErr { @@ -50,7 +50,7 @@ pub(crate) struct RawPtrToIntErr { } #[derive(SessionDiagnostic)] -#[error(const_eval::raw_ptr_comparison)] +#[diag(const_eval::raw_ptr_comparison)] #[note] pub(crate) struct RawPtrComparisonErr { #[primary_span] @@ -58,14 +58,14 @@ pub(crate) struct RawPtrComparisonErr { } #[derive(SessionDiagnostic)] -#[error(const_eval::panic_non_str)] +#[diag(const_eval::panic_non_str)] pub(crate) struct PanicNonStrErr { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(const_eval::mut_deref, code = "E0658")] +#[diag(const_eval::mut_deref, code = "E0658")] pub(crate) struct MutDerefErr { #[primary_span] pub span: Span, @@ -73,7 +73,7 @@ pub(crate) struct MutDerefErr { } #[derive(SessionDiagnostic)] -#[error(const_eval::transient_mut_borrow, code = "E0658")] +#[diag(const_eval::transient_mut_borrow, code = "E0658")] pub(crate) struct TransientMutBorrowErr { #[primary_span] pub span: Span, @@ -81,9 +81,116 @@ pub(crate) struct TransientMutBorrowErr { } #[derive(SessionDiagnostic)] -#[error(const_eval::transient_mut_borrow_raw, code = "E0658")] +#[diag(const_eval::transient_mut_borrow_raw, code = "E0658")] pub(crate) struct TransientMutBorrowErrRaw { #[primary_span] pub span: Span, pub kind: ConstContext, } + +#[derive(SessionDiagnostic)] +#[diag(const_eval::max_num_nodes_in_const)] +pub(crate) struct MaxNumNodesInConstErr { + #[primary_span] + pub span: Span, + pub global_const_id: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_fn_pointer_call)] +pub(crate) struct UnallowedFnPointerCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unstable_const_fn)] +pub(crate) struct UnstableConstFn { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")] +pub(crate) struct UnallowedMutableRefsRaw { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")] +pub(crate) struct NonConstFmtMacroCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fn_call, code = "E0015")] +pub(crate) struct NonConstFnCall { + #[primary_span] + pub span: Span, + pub def_path_str: String, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_op_in_const_context)] +pub(crate) struct UnallowedOpInConstContext { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_heap_allocations, code = "E0010")] +pub(crate) struct UnallowedHeapAllocations { + #[primary_span] + #[label] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_inline_asm, code = "E0015")] +pub(crate) struct UnallowedInlineAsm { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::interior_mutable_data_refer, code = "E0492")] +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(SessionDiagnostic)] +#[diag(const_eval::interior_mutability_borrow)] +pub(crate) struct InteriorMutabilityBorrow { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index c97c31eb9..cbe985480 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -108,6 +108,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), } } + + 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_sized = data.to_pointer(self)?; + let val = Immediate::ScalarPair(data, vtable); + self.write_immediate(val, dest)?; + } else { + bug!() + } + } } Ok(()) } @@ -123,10 +137,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match src.layout.ty.kind() { // Floating point Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); + return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into()); } Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); + return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); } // The rest is integer/pointer-"like", including fn ptr casts _ => assert!( @@ -153,7 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(dest_layout.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()), + Immediate::ScalarPair(data, _) => Ok(data.into()), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({:?} -> {:?})", @@ -167,7 +181,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // # The remaining source values are scalar and "int-like". - let scalar = src.to_scalar()?; + let scalar = src.to_scalar(); Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } @@ -179,7 +193,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); assert!(cast_ty.is_integral()); - let scalar = src.to_scalar()?; + let scalar = src.to_scalar(); let ptr = scalar.to_pointer(self)?; match ptr.into_pointer_or_addr() { Ok(ptr) => M::expose_ptr(self, ptr)?, @@ -197,7 +211,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_matches!(cast_ty.kind(), ty::RawPtr(_)); // First cast to usize. - let scalar = src.to_scalar()?; + let scalar = src.to_scalar(); let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?; let addr = addr.to_machine_usize(self)?; @@ -291,14 +305,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { - let ptr = self.read_immediate(src)?.to_scalar()?; + let ptr = self.read_scalar(src)?; // u64 cast is from usize to u64, which is always good let val = Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); self.write_immediate(val, dest) } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; + 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_vptr = old_vptr.to_pointer(self)?; let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; if old_trait != data_a.principal() { @@ -307,10 +326,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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(ref data, _)) => { + (_, &ty::Dynamic(ref 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_immediate(src)?.to_scalar()?; + let ptr = self.read_scalar(src)?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 150d6589b..d37eaeed0 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -21,7 +21,7 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou use super::{ AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, PointerArithmetic, Provenance, - Scalar, ScalarMaybeUninit, StackPopJump, + Scalar, StackPopJump, }; use crate::transform::validate::equal_up_to_regions; @@ -187,9 +187,6 @@ pub enum LocalValue { impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { /// Read the local's value or error if the local is not yet live or not live anymore. - /// - /// Note: This may only be invoked from the `Machine::access_local` hook and not from - /// anywhere else. You may be invalidating machine invariants if you do! #[inline] pub fn access(&self) -> InterpResult<'tcx, &Operand> { match &self.value { @@ -782,7 +779,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!( unwinding, match self.frame().loc { - Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup, + Ok(loc) => self.body().basic_blocks[loc.block].is_cleanup, Err(_) => true, } ); @@ -991,16 +988,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug } LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { write!(fmt, " {:?}", val)?; - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = 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 ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 { + if let Scalar::Ptr(ptr, _size) = val1 { allocs.push(ptr.provenance.get_alloc_id()); } - if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 { + if let Scalar::Ptr(ptr, _size) = val2 { allocs.push(ptr.provenance.get_alloc_id()); } } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 376b8872c..24dbc7695 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -134,7 +134,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: alloc.mutability = Mutability::Not; }; // link the alloc id to the actual allocation - leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id)); + leftover_allocations.extend(alloc.provenance().iter().map(|&(_, alloc_id)| alloc_id)); let alloc = tcx.intern_const_alloc(alloc); tcx.set_alloc_id_memory(alloc_id, alloc); None @@ -191,10 +191,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory return Ok(true); }; - // If there are no relocations in this allocation, it does not contain references + // If there is no provenance in this allocation, it does not contain references // that point to another allocation, and we can avoid the interning walk. if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? { - if !alloc.has_relocations() { + if !alloc.has_provenance() { return Ok(false); } } else { @@ -233,8 +233,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory } fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { - // Handle Reference types, as these are the only relocations supported by const eval. - // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. + // Handle Reference types, as these are the only types with provenance supported by const eval. + // Raw pointers (and boxes) are handled by the `leftover_allocations` logic. let tcx = self.ecx.tcx; let ty = mplace.layout.ty; if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { @@ -334,7 +334,7 @@ pub enum InternKind { /// tracks where in the value we are and thus can show much better error messages. /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. -#[tracing::instrument(level = "debug", skip(ecx))] +#[instrument(level = "debug", skip(ecx))] pub fn intern_const_alloc_recursive< 'mir, 'tcx: 'mir, @@ -410,7 +410,7 @@ pub fn intern_const_alloc_recursive< // references and a `leftover_allocations` set (where we only have a todo-list here). // So we hand-roll the interning logic here again. match intern_kind { - // Statics may contain mutable allocations even behind relocations. + // Statics may point to mutable allocations. // Even for immutable statics it would be ok to have mutable allocations behind // raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`. InternKind::Static(_) => {} @@ -441,7 +441,7 @@ pub fn intern_const_alloc_recursive< } let alloc = tcx.intern_const_alloc(alloc); tcx.set_alloc_id_memory(alloc_id, alloc); - for &(_, alloc_id) in alloc.inner().relocations().iter() { + for &(_, alloc_id) in alloc.inner().provenance().iter() { if leftover_allocations.insert(alloc_id) { todo.push(alloc_id); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 08209eb79..8637d6a77 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar}, - BinOp, + BinOp, NonDivergingIntrinsic, }; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf as _; @@ -79,9 +79,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ty::Projection(_) | ty::Opaque(_, _) | ty::Param(_) - | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => throw_inval!(TooGeneric), + ty::Bound(_, _) => bug!("bound ty during ctfe"), ty::Bool | ty::Char | ty::Int(_) @@ -95,7 +95,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Dynamic(_, _) + | ty::Dynamic(_, _, _) | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) @@ -184,7 +184,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::bitreverse => { let ty = substs.type_at(0); let layout_of = self.layout_of(ty)?; - let val = self.read_scalar(&args[0])?.check_init()?; + let val = self.read_scalar(&args[0])?; let bits = val.to_bits(layout_of.size)?; let kind = match layout_of.abi { Abi::Scalar(scalar) => scalar.primitive(), @@ -256,7 +256,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?; if overflowed { let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar()?.to_bits(layout.size)?; + let r_val = r.to_scalar().to_bits(layout.size)?; if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { throw_ub_format!("overflowing shift by {} in `{}`", r_val, intrinsic_name); } else { @@ -269,9 +269,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) let layout = self.layout_of(substs.type_at(0))?; - let val = self.read_scalar(&args[0])?.check_init()?; + let val = self.read_scalar(&args[0])?; let val_bits = val.to_bits(layout.size)?; - let raw_shift = self.read_scalar(&args[1])?.check_init()?; + 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; @@ -320,7 +320,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 poiner points to an allocation. + // Neither pointer points to an allocation. // If these are inequal or null, this *will* fail the deref check below. (a, b) } @@ -506,12 +506,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // These just return their argument self.copy_op(&args[0], dest, /*allow_transmute*/ false)?; } - sym::assume => { - let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } sym::raw_eq => { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; @@ -536,6 +530,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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_format!("`assume` called with `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 exact_div( &mut self, a: &ImmTy<'tcx, M::Provenance>, @@ -570,7 +590,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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: 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 @@ -687,10 +707,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; assert!(!layout.is_unsized()); - let lhs = self.read_pointer(lhs)?; - let rhs = self.read_pointer(rhs)?; - let lhs_bytes = self.read_bytes_ptr(lhs, layout.size)?; - let rhs_bytes = self.read_bytes_ptr(rhs, layout.size)?; + 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, Align::ONE)? else { + // zero-sized access + return Ok(&[]); + }; + if alloc_ref.has_provenance() { + throw_ub_format!("`raw_eq` on bytes 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)) } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 5864b9215..91f4f0425 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -28,7 +28,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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]; + let block = &frame.body.basic_blocks[loc.block]; if loc.statement_index == block.statements.len() { debug!( "find_closest_untracked_caller_location: got terminator {:?} ({:?})", diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index f9847742f..7e4c5fcb0 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -48,7 +48,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnPtr(_) | ty::Never | ty::Tuple(_) - | ty::Dynamic(_, _) => self.pretty_print_type(ty), + | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799..530e252b7 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -6,6 +6,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt::Debug; use std::hash::Hash; +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; @@ -123,18 +124,15 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether memory accesses should be alignment-checked. fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Whether, when checking alignment, we should `force_int` and thus support + /// Whether, when checking alignment, we should look at the actual address and thus support /// custom alignment logic based on whatever the integer address happens to be. /// - /// Requires Provenance::OFFSET_IS_ADDR to be true. - fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// If this returns true, Provenance::OFFSET_IS_ADDR must be true. + fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Whether to enforce integers and floats being initialized. - fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { true @@ -218,23 +216,12 @@ pub trait Machine<'mir, 'tcx>: Sized { right: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - /// Called to read the specified `local` from the `frame`. - /// Since reading a ZST is not actually accessing memory or locals, this is never invoked - /// for ZST reads. - #[inline] - fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - local: mir::Local, - ) -> InterpResult<'tcx, &'a Operand> - where - 'tcx: 'mir, - { - frame.locals[local].access() - } - /// Called to write the specified `local` from the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. + /// + /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut + /// Frame`. #[inline] fn access_local_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, @@ -329,7 +316,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// 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 relocations. + /// This must only fail if `alloc` contains provenance. fn adjust_allocation<'b>( ecx: &InterpCx<'mir, 'tcx, Self>, id: AllocId, @@ -337,13 +324,22 @@ pub trait Machine<'mir, 'tcx>: Sized { 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, + ) -> InterpResult<'tcx> { + throw_unsup_format!("inline assembly is not supported") + } + /// Hook for performing extra checks on a memory read access. /// /// 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. #[inline(always)] - fn memory_read( + fn before_memory_read( _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_extra: &Self::AllocExtra, @@ -355,7 +351,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Hook for performing extra checks on a memory write access. #[inline(always)] - fn memory_written( + fn before_memory_write( _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, @@ -367,7 +363,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Hook for performing extra operations on a memory deallocation. #[inline(always)] - fn memory_deallocated( + fn before_memory_deallocation( _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, @@ -437,28 +433,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type FrameExtra = (); #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - - #[inline(always)] - fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not support `force_int`. + fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + // We do not support `use_addr`. false } - #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - - #[inline(always)] - fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - true - } - #[inline(always)] fn checked_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true @@ -510,6 +489,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { ) -> 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(addr)) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ed2c4edf9..ed155fbfe 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -21,7 +21,6 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar, - ScalarMaybeUninit, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -215,7 +214,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.allocate_raw_ptr(alloc, kind).unwrap() } - /// This can fail only of `alloc` contains relocations. + /// This can fail only of `alloc` contains provenance. pub fn allocate_raw_ptr( &mut self, alloc: Allocation, @@ -327,7 +326,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Let the machine take some extra action let size = alloc.size(); - M::memory_deallocated( + M::before_memory_deallocation( *self.tcx, &mut self.machine, &mut alloc.extra, @@ -438,15 +437,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg, }) } - // Ensure we never consider the null pointer dereferencable. + // Ensure we never consider the null pointer dereferenceable. if M::Provenance::OFFSET_IS_ADDR { assert_ne!(ptr.addr(), Size::ZERO); } // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { - if M::force_int_for_alignment_check(self) { - // `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. + if M::use_addr_for_alignment_check(self) { + // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. check_offset_align(ptr.addr().bytes(), align)?; } else { // Check allocation alignment and offset alignment. @@ -520,6 +519,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// 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, @@ -573,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?; if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; + 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 { // Even in this branch we have to be sure that we actually access the allocation, in @@ -589,6 +590,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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! /// @@ -634,7 +640,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; + M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) } else { Ok(None) @@ -788,10 +794,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { todo.extend(static_roots); while let Some(id) = todo.pop() { if reachable.insert(id) { - // This is a new allocation, add its relocations to `todo`. + // This is a new allocation, add the allocation it points to to `todo`. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( - alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()), + alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()), ); } } @@ -827,7 +833,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, allocs_to_print: &mut VecDeque, alloc: &Allocation, ) -> std::fmt::Result { - for alloc_id in alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()) { + for alloc_id in alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()) { allocs_to_print.push_back(alloc_id); } write!(fmt, "{}", display_allocation(tcx, alloc)) @@ -894,11 +900,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, /// Reading and writing. impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn write_scalar( - &mut self, - range: AllocRange, - val: ScalarMaybeUninit, - ) -> InterpResult<'tcx> { + 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 @@ -908,15 +910,11 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { } /// `offset` is relative to this allocation reference, not the base of the allocation. - pub fn write_ptr_sized( - &mut self, - offset: Size, - val: ScalarMaybeUninit, - ) -> InterpResult<'tcx> { + 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 uninitalized + /// Mark the entire referenced range as uninitialized pub fn write_uninit(&mut self) -> InterpResult<'tcx> { Ok(self .alloc @@ -931,7 +929,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { &self, range: AllocRange, read_provenance: bool, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let range = self.range.subrange(range); let res = self .alloc @@ -942,12 +940,12 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { } /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit> { + 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, ScalarMaybeUninit> { + 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, @@ -955,29 +953,25 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { } /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn check_bytes( - &self, - range: AllocRange, - allow_uninit: bool, - allow_ptr: bool, - ) -> InterpResult<'tcx> { + pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> { Ok(self .alloc - .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr) + .get_bytes_strip_provenance(&self.tcx, self.range) .map_err(|e| e.to_interp_error(self.alloc_id))?) } - /// Returns whether the allocation has relocations for the entire range of the `AllocRef`. - pub(crate) fn has_relocations(&self) -> bool { - self.alloc.has_relocations(&self.tcx, self.range) + /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`. + pub(crate) fn has_provenance(&self) -> bool { + self.alloc.range_has_provenance(&self.tcx, self.range) } } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Reads the given number of bytes from memory. Returns them as a slice. + /// 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( + pub fn read_bytes_ptr_strip_provenance( &self, ptr: Pointer>, size: Size, @@ -990,7 +984,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // (We are staying inside the bounds here so all is good.) Ok(alloc_ref .alloc - .get_bytes(&alloc_ref.tcx, alloc_ref.range) + .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) } @@ -1071,7 +1065,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); - M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), src_range)?; + 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 { @@ -1079,24 +1079,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(()); }; - // This checks relocation edges on the src, which needs to happen before - // `prepare_relocation_copy`. - let src_bytes = src_alloc - .get_bytes_with_uninit_and_ptr(&tcx, src_range) - .map_err(|e| e.to_interp_error(src_alloc_id))? - .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation - // first copy the relocations to a temporary buffer, because - // `get_bytes_mut` will clear the relocations, which is correct, - // since we don't want to keep any relocations at the target. - let relocations = - src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies); + // Checks provenance edges on the src, which needs to happen before + // `prepare_provenance_copy`. + if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.start, Size::ZERO)) { + throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.start))); + } + if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.end(), Size::ZERO)) { + throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.end()))); + } + 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. + let provenance = + src_alloc.prepare_provenance_copy(self, src_range, dest_offset, num_copies); // Prepare a copy of the initialization mask. let compressed = src_alloc.compress_uninit_range(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::memory_written( + M::before_memory_write( *tcx, extra, &mut dest_alloc.extra, @@ -1118,7 +1121,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest_alloc .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; - // We can forget about the relocations, this is all not initialized anyway. + // We can forget about the provenance, this is all not initialized anyway. return Ok(()); } @@ -1162,8 +1165,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`) num_copies, ); - // copy the relocations to the destination - dest_alloc.mark_relocation_range(relocations); + // copy the provenance to the destination + dest_alloc.mark_provenance_range(provenance); Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 94ba62c16..0e3959b61 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -1,11 +1,9 @@ //! 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::fmt::Write; - use rustc_hir::def::Namespace; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; -use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; +use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty}; use rustc_middle::{mir, ty}; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding}; @@ -14,7 +12,7 @@ use rustc_target::abi::{VariantIdx, Variants}; use super::{ alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Place, PlaceTy, Pointer, - Provenance, Scalar, ScalarMaybeUninit, + Provenance, Scalar, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -27,23 +25,14 @@ use super::{ #[derive(Copy, Clone, Debug)] pub enum Immediate { /// A single scalar value (must have *initialized* `Scalar` ABI). - /// FIXME: we also currently often use this for ZST. - /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead. - Scalar(ScalarMaybeUninit), + Scalar(Scalar), /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are /// `Scalar::Initialized`). - ScalarPair(ScalarMaybeUninit, ScalarMaybeUninit), + ScalarPair(Scalar, Scalar), /// A value of fully uninitialized memory. Can have and size and layout. Uninit, } -impl From> for Immediate { - #[inline(always)] - fn from(val: ScalarMaybeUninit) -> Self { - Immediate::Scalar(val) - } -} - impl From> for Immediate { #[inline(always)] fn from(val: Scalar) -> Self { @@ -51,13 +40,13 @@ impl From> for Immediate { } } -impl<'tcx, Prov: Provenance> Immediate { +impl Immediate { pub fn from_pointer(p: Pointer, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx)) + Immediate::Scalar(Scalar::from_pointer(p, cx)) } pub fn from_maybe_pointer(p: Pointer>, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx)) + Immediate::Scalar(Scalar::from_maybe_pointer(p, cx)) } pub fn new_slice(val: Scalar, len: u64, cx: &impl HasDataLayout) -> Self { @@ -69,41 +58,28 @@ impl<'tcx, Prov: Provenance> Immediate { vtable: Pointer>, cx: &impl HasDataLayout, ) -> Self { - Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) + Immediate::ScalarPair(val.into(), 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_or_uninit(self) -> ScalarMaybeUninit { + 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 => ScalarMaybeUninit::Uninit, + 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(self) -> InterpResult<'tcx, Scalar> { - self.to_scalar_or_uninit().check_init() - } - - #[inline] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit, ScalarMaybeUninit) { + 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 => (ScalarMaybeUninit::Uninit, ScalarMaybeUninit::Uninit), + Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"), } } - - #[inline] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { - let (val1, val2) = self.to_scalar_or_uninit_pair(); - Ok((val1.check_init()?, val2.check_init()?)) - } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together @@ -119,27 +95,17 @@ impl std::fmt::Display for ImmTy<'_, Prov> { /// Helper function for printing a scalar to a FmtPrinter fn p<'a, 'tcx, Prov: Provenance>( cx: FmtPrinter<'a, 'tcx>, - s: ScalarMaybeUninit, + s: Scalar, ty: Ty<'tcx>, ) -> Result, std::fmt::Error> { match s { - ScalarMaybeUninit::Scalar(Scalar::Int(int)) => { - cx.pretty_print_const_scalar_int(int, ty, true) - } - ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _sz)) => { + 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, true) } - ScalarMaybeUninit::Uninit => cx.typed_value( - |mut this| { - this.write_str("uninit ")?; - Ok(this) - }, - |this| this.print_type(ty), - " ", - ), } } ty::tls::with(|tcx| { @@ -269,7 +235,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); - let int = self.to_scalar().expect("to_const_int doesn't work on scalar pairs").assert_int(); + let int = self.to_scalar().assert_int(); ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) } } @@ -327,7 +293,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn read_immediate_from_mplace_raw( &self, mplace: &MPlaceTy<'tcx, M::Provenance>, - force: bool, ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized @@ -345,47 +310,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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`). - let scalar_layout = match mplace.layout.abi { - // `if` does not work nested inside patterns, making this a bit awkward to express. - Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => Some(s), - Abi::Scalar(s) if force => Some(s.primitive()), - _ => None, - }; - if let Some(s) = scalar_layout { - 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*/ s.is_ptr())?; - return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })); - } - let scalar_pair_layout = match mplace.layout.abi { + 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*/ s.is_ptr(), + )?; + Some(ImmTy { imm: scalar.into(), layout: mplace.layout }) + } Abi::ScalarPair( abi::Scalar::Initialized { value: a, .. }, abi::Scalar::Initialized { value: b, .. }, - ) => Some((a, b)), - Abi::ScalarPair(a, b) if force => Some((a.primitive(), b.primitive())), - _ => None, - }; - if let Some((a, b)) = scalar_pair_layout { - // 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*/ a.is_ptr(), - )?; - let b_val = alloc - .read_scalar(alloc_range(b_offset, b_size), /*read_provenance*/ b.is_ptr())?; - return Ok(Some(ImmTy { - imm: Immediate::ScalarPair(a_val, b_val), - layout: mplace.layout, - })); - } - // Neither a scalar nor scalar pair. - return Ok(None); + ) => { + // 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*/ a.is_ptr(), + )?; + let b_val = alloc.read_scalar( + alloc_range(b_offset, b_size), + /*read_provenance*/ b.is_ptr(), + )?; + Some(ImmTy { + imm: Immediate::ScalarPair(a_val.into(), b_val.into()), + layout: mplace.layout, + }) + } + _ => { + // Neither a scalar nor scalar pair. + None + } + }) } /// Try returning an immediate for the operand. If the layout does not permit loading this as an @@ -394,20 +356,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// succeed! Whether it succeeds depends on whether the layout can be represented /// in an `Immediate`, not on which data is stored there currently. /// - /// If `force` is `true`, then even scalars with fields that can be ununit will be - /// read. This means the load is lossy and should not be written back! - /// This flag exists only for validity checking. - /// /// 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: &OpTy<'tcx, M::Provenance>, - force: bool, ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::Provenance>>> { Ok(match src.try_as_mplace() { Ok(ref mplace) => { - if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? { + if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Ok(val) } else { Err(*mplace) @@ -418,24 +375,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// Read an immediate from a place, asserting that that is possible with the given layout. + /// + /// If this suceeds, the `ImmTy` is never `Uninit`. #[inline(always)] pub fn read_immediate( &self, op: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? { - Ok(imm) - } else { - span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty); + 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)?.unwrap(); + if matches!(*imm, Immediate::Uninit) { + throw_ub!(InvalidUninitBytes(None)); + } + Ok(imm) } /// Read a scalar from a place pub fn read_scalar( &self, op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self.read_immediate(op)?.to_scalar_or_uninit()) + ) -> InterpResult<'tcx, Scalar> { + Ok(self.read_immediate(op)?.to_scalar()) } /// Read a pointer from a place. @@ -449,7 +415,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// 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(mplace.ptr, Size::from_bytes(len))?; + 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) } @@ -478,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// Read from a local. Will not actually access the local if reading from a ZST. + /// Read from a local. /// 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 @@ -490,12 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let layout = self.layout_of_local(frame, local, layout)?; - let op = if layout.is_zst() { - // Bypass `access_local` (helps in ConstProp) - Operand::Immediate(Immediate::Uninit) - } else { - *M::access_local(frame, local)? - }; + let op = *frame.locals[local].access()?; Ok(OpTy { op, layout, align: Some(layout.align.abi) }) } @@ -598,15 +559,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match c.kind() { - ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => { throw_inval!(AlreadyReported(reported)) } ty::ConstKind::Unevaluated(uv) => { + // NOTE: We evaluate to a `ValTree` here as a check to ensure + // we're working with valid constants, even though we never need it. let instance = self.resolve(uv.def, uv.substs)?; - Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) + let cid = GlobalId { instance, promoted: None }; + let _valtree = self + .tcx + .eval_to_valtree(self.param_env.and(cid))? + .unwrap_or_else(|| bug!("unable to create ValTree for {:?}", uv)); + + Ok(self.eval_to_allocation(cid)?.into()) } - ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c) } ty::ConstKind::Value(valtree) => { @@ -622,9 +591,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val: &mir::ConstantKind<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + // FIXME(const_prop): normalization needed b/c const prop lint in + // `mir_drops_elaborated_and_const_checked`, which happens before + // optimized MIR. Only after optimizing the MIR can we guarantee + // that the `RevealAll` pass has happened and that the body's consts + // are normalized, so any call to resolve before that needs to be + // manually normalized. + let val = self.tcx.normalize_erasing_regions(self.param_env, *val); match val { - mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout), - mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout), + mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout), + mir::ConstantKind::Unevaluated(uv, _) => { + let instance = self.resolve(uv.def, uv.substs)?; + Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) + } } } @@ -727,7 +707,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Figure out which discriminant and variant this corresponds to. Ok(match *tag_encoding { TagEncoding::Direct => { - let scalar = tag_val.to_scalar()?; + let scalar = tag_val.to_scalar(); // Generate a specific error if `tag_val` is not an integer. // (`tag_bits` itself is only used for error messages below.) let tag_bits = scalar @@ -757,8 +737,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Return the cast value, and the index. (discr_val, index.0) } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { - let tag_val = tag_val.to_scalar()?; + 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(); @@ -775,7 +755,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !ptr_valid { throw_ub!(InvalidTag(dbg_val)) } - dataful_variant + untagged_variant } Ok(tag_bits) => { let tag_bits = tag_bits.assert_bits(tag_layout.size); @@ -785,9 +765,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = self.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); + 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) @@ -806,7 +785,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(usize::try_from(variant_index).unwrap() < variants_len); VariantIdx::from_u32(variant_index) } else { - dataful_variant + untagged_variant } } }; @@ -820,12 +799,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Immediate, 56); - rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); - rustc_data_structures::static_assert_size!(Operand, 64); - rustc_data_structures::static_assert_size!(OpTy<'_>, 88); + static_assert_size!(Immediate, 48); + static_assert_size!(ImmTy<'_>, 64); + static_assert_size!(Operand, 56); + static_assert_size!(OpTy<'_>, 80); } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index f9912d706..1f1d06651 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -329,21 +329,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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()?; + 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()?; + 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 ty = left.layout.ty; - let left = left.to_scalar()?; - let right = right.to_scalar()?; + let left = left.to_scalar(); + let right = right.to_scalar(); Ok(match fty { FloatTy::F32 => { self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?) @@ -363,8 +363,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right.layout.ty ); - let l = left.to_scalar()?.to_bits(left.layout.size)?; - let r = right.to_scalar()?.to_bits(right.layout.size)?; + 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() => { @@ -410,7 +410,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::mir::UnOp::*; let layout = val.layout; - let val = val.to_scalar()?; + let val = val.to_scalar(); trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); match layout.ty.kind() { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f4571a1ca..b32889290 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -2,8 +2,6 @@ //! into a place. //! All high-level functions to write to memory work on places as destinations. -use std::hash::Hash; - use rustc_ast::Mutability; use rustc_middle::mir; use rustc_middle::ty; @@ -13,7 +11,7 @@ use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding, Vari use super::{ alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand, - Pointer, Provenance, Scalar, ScalarMaybeUninit, + Pointer, Provenance, Scalar, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -254,8 +252,6 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { // These are defined here because they produce a place. impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] - /// Note: do not call `as_ref` on the resulting place. This function should only be used to - /// read from the resulting mplace, not to get its address back. pub fn try_as_mplace(&self) -> Result, ImmTy<'tcx, Prov>> { match **self { Operand::Indirect(mplace) => { @@ -267,8 +263,6 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - /// Note: do not call `as_ref` on the resulting place. This function should only be used to - /// read from the resulting mplace, not to get its address back. pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { self.try_as_mplace().unwrap() } @@ -294,7 +288,7 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + Eq + Hash + 'static, + Prov: Provenance + 'static, M: Machine<'mir, 'tcx, Provenance = Prov>, { /// Take a value, which represents a (thin or wide) reference, and make it a place. @@ -312,7 +306,7 @@ where let layout = self.layout_of(pointee_type)?; let (ptr, meta) = match **val { Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), - Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)), + Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta)), Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; @@ -467,7 +461,7 @@ where #[inline(always)] pub fn write_scalar( &mut self, - val: impl Into>, + val: impl Into>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.write_immediate(Immediate::Scalar(val.into()), dest) @@ -644,9 +638,9 @@ where // Let us see if the layout is simple so we take a shortcut, // avoid force_allocation. - let src = match self.read_immediate_raw(src, /*force*/ false)? { + let src = match self.read_immediate_raw(src)? { Ok(src_val) => { - assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); + assert!(!src.layout.is_unsized(), "cannot copy unsized immediates"); assert!( !dest.layout.is_unsized(), "the src is sized, so the dest must also be sized" @@ -823,7 +817,7 @@ where } abi::Variants::Multiple { tag_encoding: - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, tag: tag_layout, tag_field, .. @@ -831,7 +825,7 @@ where // No need to validate that the discriminant here because the // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. - if variant_index != dataful_variant { + if variant_index != untagged_variant { let variants_start = niche_variants.start().as_u32(); let variant_index_relative = variant_index .as_u32() @@ -891,10 +885,13 @@ where #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); - rustc_data_structures::static_assert_size!(MemPlace, 40); - rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); - rustc_data_structures::static_assert_size!(Place, 48); - rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); + static_assert_size!(MemPlaceMeta, 24); + static_assert_size!(MemPlace, 40); + static_assert_size!(MPlaceTy<'_>, 64); + #[cfg(not(bootstrap))] + static_assert_size!(Place, 40); + #[cfg(not(bootstrap))] + static_assert_size!(PlaceTy<'_>, 64); } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 742339f2b..77da8f104 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -1,14 +1,12 @@ //! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy. //! -//! OpTy and PlaceTy genrally work by "let's see if we are actually an MPlaceTy, and do something custom if not". +//! OpTy and PlaceTy generally work by "let's see if we are actually an MPlaceTy, and do something custom if not". //! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway. //! For OpTy, the custom thing on field pojections has to be pretty clever (since `Operand::Immediate` can have fields), //! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial, //! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually //! implement the logic on OpTy, and MPlaceTy calls that. -use std::hash::Hash; - use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; @@ -22,7 +20,7 @@ use super::{ // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + Eq + Hash + 'static, + Prov: Provenance + 'static, M: Machine<'mir, 'tcx, Provenance = Prov>, { //# Field access @@ -100,6 +98,8 @@ where // 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 field_val: Immediate<_> = match (*base, base.layout.abi) { + // if the entire value is uninit, then so is the field (can happen in ConstProp) + (Immediate::Uninit, _) => Immediate::Uninit, // the field contains no information, can be left uninit _ if field_layout.is_zst() => Immediate::Uninit, // the field covers the entire type @@ -124,6 +124,7 @@ where b_val }) } + // everything else is a bug _ => span_bug!( self.cur_span(), "invalid field access on immediate {}, layout {:#?}", diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index fea158a9f..c6e04cbfb 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -53,7 +53,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.pop_stack_frame(/* unwinding */ true)?; return Ok(true); }; - let basic_block = &self.body().basic_blocks()[loc.block]; + 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(); @@ -114,13 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::retag(self, *kind, &dest)?; } - // Call CopyNonOverlapping - CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => { - 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)?; - } + Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, // Statements we do not track. AscribeUserType(..) => {} @@ -251,8 +245,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Len(place) => { let src = self.eval_place(place)?; - let mplace = self.force_allocation(&src)?; - let len = mplace.len(self)?; + let op = self.place_to_op(&src)?; + let len = op.len(self)?; self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index d563e35f9..50a82aa0e 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use rustc_ast::ast::InlineAsmOptions; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; use rustc_middle::{ @@ -129,8 +130,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Assert { ref cond, expected, ref msg, target, cleanup } => { - let cond_val = - self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?; + let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; if expected == cond_val { self.go_to_block(target); } else { @@ -167,8 +167,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator.kind ), - // Inline assembly can't be interpreted. - InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), + InlineAsm { template, ref operands, options, destination, .. } => { + M::eval_inline_asm(self, template, operands, options)?; + if options.contains(InlineAsmOptions::NORETURN) { + throw_ub_format!("returned from noreturn inline assembly"); + } + self.go_to_block( + destination + .expect("InlineAsm terminators without noreturn must have a destination"), + ) + } } Ok(()) @@ -215,12 +223,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => false, } }; - // Padding must be fully equal. - let pad_compat = || caller_abi.pad == callee_abi.pad; // When comparing the PassMode, we have to be smart about comparing the attributes. - let arg_attr_compat = |a1: ArgAttributes, a2: ArgAttributes| { + let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| { // There's only one regular attribute that matters for the call ABI: InReg. - // Everything else is things like noalias, dereferencable, nonnull, ... + // Everything else is things like noalias, dereferenceable, nonnull, ... // (This also applies to pointee_size, pointee_align.) if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg) { @@ -233,13 +239,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } return true; }; - let mode_compat = || match (caller_abi.mode, callee_abi.mode) { + let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) { (PassMode::Ignore, PassMode::Ignore) => true, (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2), (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) } - (PassMode::Cast(c1), PassMode::Cast(c2)) => c1 == c2, + (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1 == c2 && pad1 == pad2, ( PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, @@ -251,7 +257,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => false, }; - if layout_compat() && pad_compat() && mode_compat() { + if layout_compat() && mode_compat() { return true; } trace!( @@ -534,7 +540,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let mut non_zst_field = None; for i in 0..receiver.layout.fields.count() { let field = self.operand_field(&receiver, i)?; - if !field.layout.is_zst() { + let zst = + field.layout.is_zst() && field.layout.align.abi.bytes() == 1; + if !zst { assert!( non_zst_field.is_none(), "multiple non-ZST fields in dyn receiver type {}", @@ -557,7 +565,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .tcx .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); let ty::Dynamic(data, ..) = receiver_tail.kind() else { - span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail) + span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail) }; // Get the required information from the vtable. diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index b3a511d5a..cab23b724 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -32,7 +32,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(vtable_ptr.into()) } - /// Returns a high-level representation of the entires of the given vtable. + /// Returns a high-level representation of the entries of the given vtable. pub fn get_vtable_entries( &self, vtable: Pointer>, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 0e50d1ed4..14aaee6ac 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -5,9 +5,10 @@ //! to be const-safe. use std::convert::TryFrom; -use std::fmt::Write; +use std::fmt::{Display, Write}; use std::num::NonZeroUsize; +use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::mir::interpret::InterpError; @@ -19,9 +20,11 @@ use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, Wr use std::hash::Hash; +// for the validation errors +use super::UndefinedBehaviorInfo::*; use super::{ - alloc_range, CheckInAllocMsg, GlobalAlloc, Immediate, InterpCx, InterpResult, MPlaceTy, - Machine, MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor, + CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, OpTy, Scalar, ValueVisitor, }; macro_rules! throw_validation_failure { @@ -59,6 +62,7 @@ macro_rules! throw_validation_failure { /// }); /// ``` /// +/// The patterns must be of type `UndefinedBehaviorInfo`. /// An additional expected parameter can also be added to the failure message: /// /// ``` @@ -86,7 +90,7 @@ macro_rules! try_validation { // allocation here as this can only slow down builds that fail anyway. Err(e) => match e.kind() { $( - $($p)|+ => + InterpError::UndefinedBehavior($($p)|+) => throw_validation_failure!( $where, { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? @@ -304,6 +308,26 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(r) } + fn read_immediate( + &self, + op: &OpTy<'tcx, M::Provenance>, + expected: impl Display, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + Ok(try_validation!( + self.ecx.read_immediate(op), + self.path, + InvalidUninitBytes(None) => { "uninitialized memory" } expected { "{expected}" } + )) + } + + fn read_scalar( + &self, + op: &OpTy<'tcx, M::Provenance>, + expected: impl Display, + ) -> InterpResult<'tcx, Scalar> { + Ok(self.read_immediate(op, expected)?.to_scalar()) + } + fn check_wide_ptr_meta( &mut self, meta: MemPlaceMeta, @@ -317,8 +341,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let (_ty, _trait) = try_validation!( self.ecx.get_ptr_vtable(vtable), self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidVTablePointer(..)) => + DanglingIntPointer(..) | + InvalidVTablePointer(..) => { "{vtable}" } expected { "a vtable pointer" }, ); // FIXME: check if the type/trait match what ty::Dynamic says? @@ -344,14 +368,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' value: &OpTy<'tcx, M::Provenance>, kind: &str, ) -> InterpResult<'tcx> { - let value = self.ecx.read_immediate(value)?; + let place = + self.ecx.ref_to_mplace(&self.read_immediate(value, format_args!("a {kind}"))?)?; // Handle wide pointers. // Check metadata early, for better diagnostics - let place = try_validation!( - self.ecx.ref_to_mplace(&value), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind }, - ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } @@ -359,7 +379,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let size_and_align = try_validation!( self.ecx.size_and_align_of_mplace(&place), self.path, - err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg }, + InvalidMeta(msg) => { "invalid {} metadata: {}", kind, msg }, ); let (size, align) = size_and_align // for the purpose of validity, consider foreign types to have @@ -375,21 +395,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, - err_ub!(AlignmentCheckFailed { required, has }) => + AlignmentCheckFailed { required, has } => { "an unaligned {kind} (required {} byte alignment but found {})", required.bytes(), has.bytes() }, - err_ub!(DanglingIntPointer(0, _)) => + DanglingIntPointer(0, _) => { "a null {kind}" }, - err_ub!(DanglingIntPointer(i, _)) => + DanglingIntPointer(i, _) => { "a dangling {kind} (address {i:#x} is unallocated)" }, - err_ub!(PointerOutOfBounds { .. }) => + PointerOutOfBounds { .. } => { "a dangling {kind} (going beyond the bounds of its allocation)" }, // This cannot happen during const-eval (because interning already detects // dangling pointers), but it can happen in Miri. - err_ub!(PointerUseAfterFree(..)) => + PointerUseAfterFree(..) => { "a dangling {kind} (use-after-free)" }, ); // Do not allow pointers to uninhabited types. @@ -403,34 +423,51 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // 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) { - // Special handling for pointers to statics (irrespective of their type). + // Let's see what kind of memory this points to. let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); - if let Some(GlobalAlloc::Static(did)) = alloc_kind { - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - if matches!( - self.ctfe_mode, - Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) - ) { - // See const_eval::machine::MemoryExtra::can_access_statics for why - // this check is so important. - // This check is reachable when the const just referenced the static, - // but never read it (so we never entered `before_access_global`). - throw_validation_failure!(self.path, - { "a {} pointing to a static variable", kind } - ); + match alloc_kind { + Some(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)); + if matches!( + self.ctfe_mode, + Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) + ) { + // See const_eval::machine::MemoryExtra::can_access_statics for why + // this check is so important. + // This check is reachable when the const just referenced the static, + // but never read it (so we never entered `before_access_global`). + throw_validation_failure!(self.path, + { "a {} pointing to a static variable in a constant", kind } + ); + } + // 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. + // We might miss const-invalid data, + // but things are still sound otherwise (in particular re: consts + // referring to statics). + return Ok(()); } - // We skip 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. - // We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - return Ok(()); + Some(GlobalAlloc::Memory(alloc)) => { + if alloc.inner().mutability == Mutability::Mut + && matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) + { + // This should be unreachable, but if someone manages to copy a pointer + // out of a `static`, then that pointer might point to mutable memory, + // and we would catch that here. + throw_validation_failure!(self.path, + { "a {} pointing to mutable memory in a constant", kind } + ); + } + } + // Nothing to check for these. + None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {} } } let path = &self.path; @@ -446,20 +483,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(()) } - fn read_scalar( - &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - self.ecx.read_scalar(op) - } - - fn read_immediate_forced( - &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Immediate> { - Ok(*self.ecx.read_immediate_raw(op, /*force*/ true)?.unwrap()) - } - /// 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. fn try_visit_primitive( @@ -470,41 +493,39 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let ty = value.layout.ty; match ty.kind() { ty::Bool => { - let value = self.read_scalar(value)?; + let value = self.read_scalar(value, "a boolean")?; try_validation!( value.to_bool(), self.path, - err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) => + InvalidBool(..) => { "{:x}", value } expected { "a boolean" }, ); Ok(true) } ty::Char => { - let value = self.read_scalar(value)?; + let value = self.read_scalar(value, "a unicode scalar value")?; try_validation!( value.to_char(), self.path, - err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) => + InvalidChar(..) => { "{:x}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" }, ); Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { - let value = self.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - if M::enforce_number_init(self.ecx) { - try_validation!( - value.check_init(), - self.path, - err_ub!(InvalidUninitBytes(..)) => - { "{:x}", value } expected { "initialized bytes" } - ); - } + let value = self.read_scalar( + value, + if matches!(ty.kind(), ty::Float(..)) { + "a floating point number" + } else { + "an integer" + }, + )?; // As a special exception we *do* match on a `Scalar` here, since we truly want // to know its underlying representation (and *not* cast it to an integer). - let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..))); - if is_ptr { + if matches!(value, Scalar::Ptr(..)) { throw_validation_failure!(self.path, { "{:x}", value } expected { "plain (non-pointer) bytes" } ) @@ -515,11 +536,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // We are conservative with uninit for integers, but try to // actually enforce the strict rules for raw pointers (mostly because // that lets us re-use `ref_to_mplace`). - let place = try_validation!( - self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" }, - ); + let place = + self.ecx.ref_to_mplace(&self.read_immediate(value, "a raw pointer")?)?; if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } @@ -527,7 +545,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } ty::Ref(_, ty, mutbl) => { if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) - && *mutbl == hir::Mutability::Mut + && *mutbl == Mutability::Mut { // A mutable reference inside a const? That does not seem right (except if it is // a ZST). @@ -540,11 +558,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::FnPtr(_sig) => { - let value = try_validation!( - self.ecx.read_scalar(value).and_then(|v| v.check_init()), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" }, - ); + let value = self.read_scalar(value, "a function pointer")?; // If we check references recursively, also check that this points to a function. if let Some(_) = self.ref_tracking { @@ -552,8 +566,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidFunctionPointer(..)) => + DanglingIntPointer(..) | + InvalidFunctionPointer(..) => { "{ptr}" } expected { "a function pointer" }, ); // FIXME: Check if the signature matches @@ -595,40 +609,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn visit_scalar( &mut self, - scalar: ScalarMaybeUninit, + scalar: Scalar, scalar_layout: ScalarAbi, ) -> InterpResult<'tcx> { - // We check `is_full_range` in a slightly complicated way because *if* we are checking - // number validity, then we want to ensure that `Scalar::Initialized` is indeed initialized, - // i.e. that we go over the `check_init` below. let size = scalar_layout.size(self.ecx); - let is_full_range = match scalar_layout { - ScalarAbi::Initialized { .. } => { - if M::enforce_number_init(self.ecx) { - false // not "full" since uninit is not accepted - } else { - scalar_layout.is_always_valid(self.ecx) - } - } - ScalarAbi::Union { .. } => true, - }; - if is_full_range { - // Nothing to check. Cruciall we don't even `read_scalar` until here, since that would - // fail for `Union` scalars! - return Ok(()); - } - // We have something to check: it must at least be initialized. 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 value = try_validation!( - scalar.check_init(), - self.path, - err_ub!(InvalidUninitBytes(None)) => { "{:x}", scalar } - expected { "something {}", wrapping_range_format(valid_range, max_value) }, - ); - let bits = match value.try_to_int() { + 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. @@ -636,7 +625,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // 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(value)? { + if self.ecx.scalar_may_be_null(scalar)? { throw_validation_failure!(self.path, { "a potentially null pointer" } expected { @@ -693,9 +682,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Ok(try_validation!( this.ecx.read_discriminant(op), this.path, - err_ub!(InvalidTag(val)) => + InvalidTag(val) => { "{:x}", val } expected { "a valid enum tag" }, - err_ub!(InvalidUninitBytes(None)) => + InvalidUninitBytes(None) => { "uninitialized bytes" } expected { "a valid enum tag" }, ) .1) @@ -788,10 +777,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ); } Abi::Scalar(scalar_layout) => { - // We use a 'forced' read because we always need a `Immediate` here - // and treating "partially uninit" as "fully uninit" is fine for us. - let scalar = self.read_immediate_forced(op)?.to_scalar_or_uninit(); - self.visit_scalar(scalar, scalar_layout)?; + if !scalar_layout.is_uninit_valid() { + // There is something to check here. + let scalar = self.read_scalar(op, "initiailized scalar value")?; + self.visit_scalar(scalar, scalar_layout)?; + } } Abi::ScalarPair(a_layout, b_layout) => { // There is no `rustc_layout_scalar_valid_range_start` for pairs, so @@ -799,10 +789,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // but that can miss bugs in layout computation. Layout computation // is subtle due to enums having ScalarPair layout, where one field // is the discriminant. - if cfg!(debug_assertions) { - // We use a 'forced' read because we always need a `Immediate` here - // and treating "partially uninit" as "fully uninit" is fine for us. - let (a, b) = self.read_immediate_forced(op)?.to_scalar_or_uninit_pair(); + if cfg!(debug_assertions) + && !a_layout.is_uninit_valid() + && !b_layout.is_uninit_valid() + { + // 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. + let (a, b) = + self.read_immediate(op, "initiailized scalar value")?.to_scalar_pair(); self.visit_scalar(a, a_layout)?; self.visit_scalar(b, b_layout)?; } @@ -830,9 +825,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> 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(mplace.ptr, Size::from_bytes(len)), + self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)), self.path, - err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" }, + InvalidUninitBytes(..) => { "uninitialized data in `str`" }, ); } ty::Array(tys, ..) | ty::Slice(tys) @@ -880,13 +875,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // We also accept uninit, for consistency with the slow path. let alloc = self.ecx.get_ptr_alloc(mplace.ptr, size, mplace.align)?.expect("we already excluded size 0"); - match alloc.check_bytes( - alloc_range(Size::ZERO, size), - /*allow_uninit*/ !M::enforce_number_init(self.ecx), - /*allow_ptr*/ false, - ) { + match alloc.get_bytes_strip_provenance() { // In the happy case, we needn't check anything else. - Ok(()) => {} + Ok(_) => {} // Some error happened, try to provide a more detailed description. Err(err) => { // For some errors we might be able to provide extra information. @@ -981,6 +972,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// 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) } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 72ac6af68..9f47d302a 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -10,7 +10,7 @@ Rust MIR: a lowered representation of Rust. #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(slice_ptr_get)] diff --git a/compiler/rustc_const_eval/src/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/might_permit_raw_init.rs index f971c2238..37ffa19cc 100644 --- a/compiler/rustc_const_eval/src/might_permit_raw_init.rs +++ b/compiler/rustc_const_eval/src/might_permit_raw_init.rs @@ -13,7 +13,11 @@ pub fn might_permit_raw_init<'tcx>( let strict = tcx.sess.opts.unstable_opts.strict_init_checks; if strict { - let machine = CompileTimeInterpreter::new(Limit::new(0), false); + let machine = CompileTimeInterpreter::new( + Limit::new(0), + /*can_access_statics:*/ false, + /*check_alignment:*/ true, + ); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); 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 0adb88a18..7e15858c8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -135,7 +135,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { // qualifs for the return type. let return_block = ccx .body - .basic_blocks() + .basic_blocks .iter_enumerated() .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return)) .map(|(bb, _)| bb); @@ -546,6 +546,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Since no pointer can ever get exposed (rejected above), this is easy to support. } + Rvalue::Cast(CastKind::DynStar, _, _) => { + unimplemented!() + } + Rvalue::Cast(CastKind::Misc, _, _) => {} Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} @@ -678,7 +682,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } 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 338022616..5fb4bf638 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,6 +1,7 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::def_id::LocalDefId; +use hir::ConstContext; use rustc_errors::{ error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; @@ -23,8 +24,11 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors::{ - MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, - TransientMutBorrowErr, TransientMutBorrowErrRaw, + InteriorMutabilityBorrow, InteriorMutableDataRefer, MutDerefErr, NonConstFmtMacroCall, + NonConstFnCall, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, + TransientMutBorrowErr, TransientMutBorrowErrRaw, UnallowedFnPointerCall, + UnallowedHeapAllocations, UnallowedInlineAsm, UnallowedMutableRefs, UnallowedMutableRefsRaw, + UnallowedOpInConstContext, UnstableConstFn, }; use crate::util::{call_kind, CallDesugaringKind, CallKind}; @@ -96,10 +100,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err( - span, - &format!("function pointer calls are not allowed in {}s", ccx.const_kind()), - ) + ccx.tcx.sess.create_err(UnallowedFnPointerCall { span, kind: ccx.const_kind() }) } } @@ -307,22 +308,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const formatting macro in {}s", - ccx.const_kind(), - ) + ccx.tcx.sess.create_err(NonConstFmtMacroCall { span, kind: ccx.const_kind() }) } - _ => struct_span_err!( - ccx.tcx.sess, + _ => ccx.tcx.sess.create_err(NonConstFnCall { span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(callee, substs), - ccx.const_kind(), - ), + def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs), + kind: ccx.const_kind(), + }), }; err.note(&format!( @@ -331,6 +323,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); + 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 } } @@ -349,10 +345,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let FnCallUnstable(def_id, feature) = *self; - let mut err = ccx.tcx.sess.struct_span_err( - span, - &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), - ); + let mut err = ccx + .tcx + .sess + .create_err(UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); if ccx.is_const_stable_const_fn() { err.help("const-stable functions can only call other const-stable functions"); @@ -387,9 +383,12 @@ impl<'tcx> NonConstOp<'tcx> for Generator { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) + ccx.tcx.sess.create_feature_err( + UnallowedOpInConstContext { span, msg }, + sym::const_async_blocks, + ) } else { - ccx.tcx.sess.struct_span_err(span, &msg) + ccx.tcx.sess.create_err(UnallowedOpInConstContext { span, msg }) } } } @@ -402,23 +401,11 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, + ccx.tcx.sess.create_err(UnallowedHeapAllocations { span, - E0010, - "allocations are not allowed in {}s", - ccx.const_kind() - ); - err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "The value of statics and constants must be known at compile time, \ - and they live for the entire lifetime of a program. Creating a boxed \ - value allocates memory on the heap at runtime, and therefore cannot \ - be done at compile time.", - ); - } - err + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + }) } } @@ -430,13 +417,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "inline assembly is not allowed in {}s", - ccx.const_kind() - ) + ccx.tcx.sess.create_err(UnallowedInlineAsm { span, kind: ccx.const_kind() }) } } @@ -482,12 +463,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_refs_to_cell, - span, - "cannot borrow here, since the borrowed element may contain interior mutability", - ) + ccx.tcx.sess.create_feature_err(InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) } } @@ -502,32 +478,22 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "{}s cannot refer to interior mutable data", - ccx.const_kind(), - ); - err.span_label( - span, - "this borrow of an interior mutable value may end up in the final value", - ); + // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { - err.help( - "to fix this, the value can be extracted to a separate \ - `static` item and then referenced", - ); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A constant containing interior mutable data behind a reference can allow you - to modify that data. This would make multiple uses of a constant to be able to - see different values and allow circumventing the `Send` and `Sync` requirements - for shared mutable data, which is unsound.", - ); + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: Some(()), + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) + } else { + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: None, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) } - err } } @@ -553,33 +519,18 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell.", - ); + match self.0 { + hir::BorrowKind::Raw => ccx.tcx.sess.create_err(UnallowedMutableRefsRaw { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), + hir::BorrowKind::Ref => ccx.tcx.sess.create_err(UnallowedMutableRefs { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), } - err } } 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 c8a63c9c3..6c73ef5a8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -5,12 +5,11 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngine; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngineExt, + self, ImplSource, Obligation, ObligationCause, SelectionContext, }; use super::ConstCx; @@ -189,15 +188,8 @@ impl Qualif for NeedsNonConstDrop { return false; } - // If we successfully found one, then select all of the predicates - // implied by our const drop impl. - let mut fcx = >::new(cx.tcx); - for nested in impl_src.nested_obligations() { - fcx.register_predicate_obligation(&infcx, nested); - } - // If we had any errors, then it's bad - !fcx.select_all_or_error(&infcx).is_empty() + !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() }) } @@ -354,31 +346,43 @@ where }; // Check the qualifs of the value of `const` items. - if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.kind() - { - // 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.did).is_none() { - let qualifs = if let Some((did, param_did)) = def.as_const_arg() { - cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) - } else { - cx.tcx.at(constant.span).mir_const_qualif(def.did) - }; - - if !Q::in_qualifs(&qualifs) { - return false; - } + // FIXME(valtrees): check whether const qualifs should behave the same + // way for type and mir constants. + let uneval = match constant.literal { + ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Unevaluated(_)) => { + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { unreachable!() }; + + Some(uv.expand()) + } + ConstantKind::Ty(_) => None, + ConstantKind::Unevaluated(uv, _) => Some(uv), + ConstantKind::Val(..) => None, + }; - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. + if let Some(ty::Unevaluated { def, substs: _, promoted }) = uneval { + // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible + // only for `NeedsNonConstDrop` with precise drop checking. This is the only const + // check performed after the promotion. Verify that with an assertion. + assert!(promoted.is_none() || Q::ALLOW_PROMOTED); + + // Don't peek inside trait associated constants. + if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() { + let qualifs = if let Some((did, param_did)) = def.as_const_arg() { + cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) + } else { + cx.tcx.at(constant.span).mir_const_qualif(def.did) + }; + + 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.literal.ty()) } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index ed4d8c95d..f7a7cc88a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> { impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { fn phase_change(&self) -> Option { - Some(MirPhase::ConstsPromoted) + Some(MirPhase::Analysis(AnalysisPhase::Initial)) } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -710,7 +710,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { - let last = self.promoted.basic_blocks().last().unwrap(); + let last = self.promoted.basic_blocks.last().unwrap(); let data = &mut self.promoted[last]; data.statements.push(Statement { source_info: SourceInfo::outermost(span), @@ -803,7 +803,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.visit_operand(arg, loc); } - let last = self.promoted.basic_blocks().last().unwrap(); + let last = self.promoted.basic_blocks.last().unwrap(); let new_target = self.new_block(); *self.promoted[last].terminator_mut() = Terminator { @@ -839,27 +839,16 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); - let _const = tcx.mk_const(ty::ConstS { - ty, - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs: InternalSubsts::for_item(tcx, def.did, |param, _| { - if let ty::GenericParamDefKind::Lifetime = param.kind { - tcx.lifetimes.re_erased.into() - } else { - tcx.mk_param_from_def(param) - } - }), - promoted: Some(promoted_id), - }), - }); + let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def.did)); + let uneval = ty::Unevaluated { def, substs, promoted: Some(promoted_id) }; Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ConstantKind::from_const(_const, tcx), + literal: ConstantKind::Unevaluated(uneval, ty), })) }; + let blocks = self.source.basic_blocks.as_mut(); let local_decls = &mut self.source.local_decls; let loc = candidate.location; @@ -969,7 +958,7 @@ pub fn promote_candidates<'tcx>( let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone(); scope.parent_scope = None; - let promoted = Body::new( + let mut promoted = Body::new( body.source, // `promoted` gets filled in below IndexVec::new(), IndexVec::from_elem_n(scope, 1), @@ -981,6 +970,7 @@ pub fn promote_candidates<'tcx>( body.generator_kind(), body.tainted_by_errors, ); + promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial); let promoter = Promoter { promoted, @@ -1046,7 +1036,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( _ => {} } - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 15e820f2d..4aa98cb13 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -7,9 +7,10 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location, - MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, - Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, + traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, + Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, + ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, + TerminatorKind, UnOp, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::Subst; @@ -89,9 +90,8 @@ pub fn equal_up_to_regions<'tcx>( // Normalize lifetimes away on both sides, then compare. let normalize = |ty: Ty<'tcx>| { - tcx.normalize_erasing_regions( - param_env, - ty.fold_with(&mut BottomUpFolder { + tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with( + &mut BottomUpFolder { tcx, // FIXME: We erase all late-bound lifetimes, but this is not fully correct. // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, @@ -103,7 +103,7 @@ pub fn equal_up_to_regions<'tcx>( // Leave consts and types unchanged. ct_op: |ct| ct, ty_op: |ty| ty, - }), + }, ) }; tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) @@ -142,8 +142,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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(); + 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) @@ -183,16 +183,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if (src, dest).has_opaque_types() { return true; } - // Normalize projections and things like that. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - let src = self.tcx.normalize_erasing_regions(param_env, src); - let dest = self.tcx.normalize_erasing_regions(param_env, dest); + // Normalize projections and things like that. // 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. So we compare ignoring lifetimes. - equal_up_to_regions(self.tcx, param_env, src, dest) + + // First, try with reveal_all. This might not work in some cases, as the predicates + // can be cleared in reveal_all mode. We try the reveal first anyways as it is used + // by some other passes like inlining as well. + let param_env = self.param_env.with_reveal_all_normalized(self.tcx); + if equal_up_to_regions(self.tcx, param_env, src, dest) { + return true; + } + + // If this fails, we can try it without the reveal. + equal_up_to_regions(self.tcx, self.param_env, src, dest) } } @@ -223,7 +230,8 @@ 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::DropsLowered + 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 { @@ -254,7 +262,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("bad index ({:?} != usize)", index_ty)) } } - ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => { + ProjectionElem::Deref + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) => + { let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty; if base_ty.is_box() { @@ -362,7 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // Set off any `bug!`s in the type computation code let _ = place.ty(&self.body.local_decls, self.tcx); - if self.mir_phase >= MirPhase::Derefered + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) && place.projection.len() > 1 && cntxt != PlaceContext::NonUse(VarDebugInfo) && place.projection[1..].contains(&ProjectionElem::Deref) @@ -386,8 +396,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Aggregate(agg_kind, _) => { let disallowed = match **agg_kind { AggregateKind::Array(..) => false, - AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered, - _ => self.mir_phase >= MirPhase::Deaggregated, + _ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup), }; if disallowed { self.fail( @@ -397,10 +406,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } Rvalue::Ref(_, BorrowKind::Shallow, _) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, - "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase", + "`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR", ); } } @@ -560,6 +569,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::DynStar => { + // FIXME(dyn-star): make sure nothing needs to be done here. + } // Nothing to check here CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress @@ -614,7 +626,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::AscribeUserType(..) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`AscribeUserType` should have been removed after drop lowering phase", @@ -622,18 +634,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::FakeRead(..) => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FakeRead` should have been removed after drop lowering phase", ); } } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { + 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 @@ -666,7 +685,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::SetDiscriminant { place, .. } => { - if self.mir_phase < MirPhase::Deaggregated { + 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(); @@ -681,7 +700,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } StatementKind::Deinit(..) => { - if self.mir_phase < MirPhase::Deaggregated { + if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`Deinit`is not allowed until deaggregation"); } } @@ -761,7 +780,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } TerminatorKind::DropAndReplace { target, unwind, .. } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`DropAndReplace` should have been removed during drop elaboration", @@ -832,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if self.body.generator.is_none() { self.fail(location, "`Yield` cannot appear outside generator bodies"); } - if self.mir_phase >= MirPhase::GeneratorsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail(location, "`Yield` should have been replaced by generator lowering"); } self.check_edge(location, *resume, EdgeKind::Normal); @@ -841,7 +860,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } TerminatorKind::FalseEdge { real_target, imaginary_target } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FalseEdge` should have been removed after drop elaboration", @@ -851,7 +870,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.check_edge(location, *imaginary_target, EdgeKind::Normal); } TerminatorKind::FalseUnwind { real_target, unwind } => { - if self.mir_phase >= MirPhase::DropsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`FalseUnwind` should have been removed after drop elaboration", @@ -874,7 +893,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if self.body.generator.is_none() { self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies"); } - if self.mir_phase >= MirPhase::GeneratorsLowered { + if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( location, "`GeneratorDrop` should have been replaced by generator lowering", @@ -883,13 +902,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Resume | TerminatorKind::Abort => { let bb = location.block; - if !self.body.basic_blocks()[bb].is_cleanup { + if !self.body.basic_blocks[bb].is_cleanup { self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block") } } TerminatorKind::Return => { let bb = location.block; - if self.body.basic_blocks()[bb].is_cleanup { + if self.body.basic_blocks[bb].is_cleanup { self.fail(location, "Cannot `Return` from cleanup basic block") } } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 5c641f54f..2d8658db5 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -8,25 +8,26 @@ doctest = false [dependencies] arrayvec = { version = "0.7", default-features = false } +bitflags = "1.2.1" +cfg-if = "0.1.2" ena = "0.14" indexmap = { version = "1.9.1" } -tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } -rustc_serialize = { path = "../rustc_serialize" } -rustc_macros = { path = "../rustc_macros" } -rustc_graphviz = { path = "../rustc_graphviz" } -cfg-if = "0.1.2" -stable_deref_trait = "1.0.0" -rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } +libc = "0.2" +measureme = "10.0.0" rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true } +rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } +rustc_graphviz = { path = "../rustc_graphviz" } rustc-hash = "1.1.0" -smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } rustc_index = { path = "../rustc_index", package = "rustc_index" } -bitflags = "1.2.1" -measureme = "10.0.0" -libc = "0.2" +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } +stable_deref_trait = "1.0.0" stacker = "0.1.14" tempfile = "3.2" +thin-vec = "0.2.8" +tracing = "0.1" [dependencies.parking_lot] version = "0.11" diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 5ff2d18dd..a39178016 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -29,7 +29,7 @@ impl Fingerprint { // 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 halfs makes sure we get a good quality hash in such cases too. + // two halves makes sure we get a good quality hash in such cases too. self.0.wrapping_mul(3).wrapping_add(self.1) } @@ -120,7 +120,7 @@ impl FingerprintHasher for crate::unhash::Unhasher { // 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 halfs makes sure we get a good quality hash in such cases too. + // 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 diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index bbeb193db..0d0c51b68 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -2,13 +2,26 @@ 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>; #[macro_export] macro_rules! define_id_collections { - ($map_name:ident, $set_name:ident, $key:ty) => { + ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { pub type $map_name = $crate::fx::FxHashMap<$key, T>; pub type $set_name = $crate::fx::FxHashSet<$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>; }; } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 265f45b72..56f7823ef 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -13,7 +13,7 @@ #![feature(cell_leak)] #![feature(control_flow_enum)] #![feature(extend_one)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] #![feature(maybe_uninit_uninit_array)] @@ -28,6 +28,8 @@ #![feature(vec_into_raw_parts)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -73,7 +75,6 @@ pub mod profiling; pub mod sharded; pub mod stack; pub mod sync; -pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; pub mod vec_linked_list; diff --git a/compiler/rustc_data_structures/src/map_in_place.rs b/compiler/rustc_data_structures/src/map_in_place.rs index 874de03d3..a0d4b7ade 100644 --- a/compiler/rustc_data_structures/src/map_in_place.rs +++ b/compiler/rustc_data_structures/src/map_in_place.rs @@ -1,5 +1,6 @@ use smallvec::{Array, SmallVec}; use std::ptr; +use thin_vec::ThinVec; pub trait MapInPlace: Sized { fn map_in_place(&mut self, mut f: F) @@ -15,94 +16,64 @@ pub trait MapInPlace: Sized { I: IntoIterator; } -impl MapInPlace for Vec { - 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 +// 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; + 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); + 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); + old_len = self.len(); + self.set_len(0); - read_i += 1; - write_i += 1; + read_i += 1; + write_i += 1; + } } } - } - // write_i tracks the number of actually written new items. - self.set_len(write_i); + // write_i tracks the number of actually written new items. + self.set_len(write_i); + } } - } + }; } -impl> MapInPlace for SmallVec { - 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); +impl MapInPlace for Vec { + flat_map_in_place!(); +} - read_i += 1; - write_i += 1; - } - } - } +impl> MapInPlace for SmallVec { + flat_map_in_place!(); +} - // write_i tracks the number of actually written new items. - self.set_len(write_i); - } - } +impl MapInPlace for ThinVec { + flat_map_in_place!(); } diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 07a96dd7d..e351b650a 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -117,6 +117,10 @@ pub trait ObligationProcessor { } /// 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, diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 9efea1228..937cb6715 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -164,7 +164,7 @@ impl SortedMap { /// 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, mut elements: Vec<(K, V)>) { + pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) { if elements.is_empty() { return; } @@ -173,28 +173,28 @@ impl SortedMap { let start_index = self.lookup_index_for(&elements[0].0); - let drain = match start_index { + let elements = match start_index { Ok(index) => { - let mut drain = elements.drain(..); - self.data[index] = drain.next().unwrap(); - drain + 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.drain(..)); + self.data.splice(index..index, elements.into_iter()); return; } - let mut drain = elements.drain(..); - self.data.insert(index, drain.next().unwrap()); - drain + let mut elements = elements.into_iter(); + self.data.insert(index, elements.next().unwrap()); + elements } }; // Insert the rest - for (k, v) in drain { + for (k, v) in elements { self.insert(k, v); } } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 52952a793..9c0fb8265 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -48,7 +48,7 @@ cfg_if! { /// 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)] + #[derive(Debug, Default)] pub struct Atomic(Cell); impl Atomic { @@ -56,9 +56,7 @@ cfg_if! { pub fn new(v: T) -> Self { Atomic(Cell::new(v)) } - } - impl Atomic { #[inline] pub fn into_inner(self) -> T { self.0.into_inner() diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs deleted file mode 100644 index 716259142..000000000 --- a/compiler/rustc_data_structures/src/thin_vec.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::stable_hasher::{HashStable, StableHasher}; - -use std::iter::FromIterator; - -/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`). -/// The `Option>` wrapping allows us to represent a zero sized vector with `None`, -/// which uses only a single (null) pointer. -#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)] -pub struct ThinVec(Option>>); - -impl ThinVec { - pub fn new() -> Self { - ThinVec(None) - } - - pub fn iter(&self) -> std::slice::Iter<'_, T> { - self.into_iter() - } - - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { - self.into_iter() - } - - pub fn push(&mut self, item: T) { - match *self { - ThinVec(Some(ref mut vec)) => vec.push(item), - ThinVec(None) => *self = vec![item].into(), - } - } -} - -impl From> for ThinVec { - fn from(vec: Vec) -> Self { - if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) } - } -} - -impl Into> for ThinVec { - fn into(self) -> Vec { - match self { - ThinVec(None) => Vec::new(), - ThinVec(Some(vec)) => *vec, - } - } -} - -impl ::std::ops::Deref for ThinVec { - type Target = [T]; - fn deref(&self) -> &[T] { - match *self { - ThinVec(None) => &[], - ThinVec(Some(ref vec)) => vec, - } - } -} - -impl ::std::ops::DerefMut for ThinVec { - fn deref_mut(&mut self) -> &mut [T] { - match *self { - ThinVec(None) => &mut [], - ThinVec(Some(ref mut vec)) => vec, - } - } -} - -impl FromIterator for ThinVec { - fn from_iter>(iter: I) -> Self { - // `Vec::from_iter()` should not allocate if the iterator is empty. - let vec: Vec<_> = iter.into_iter().collect(); - if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) } - } -} - -impl IntoIterator for ThinVec { - type Item = T; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - // This is still performant because `Vec::new()` does not allocate. - self.0.map_or_else(Vec::new, |ptr| *ptr).into_iter() - } -} - -impl<'a, T> IntoIterator for &'a ThinVec { - type Item = &'a T; - type IntoIter = std::slice::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_ref().iter() - } -} - -impl<'a, T> IntoIterator for &'a mut ThinVec { - type Item = &'a mut T; - type IntoIter = std::slice::IterMut<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_mut().iter_mut() - } -} - -impl Extend for ThinVec { - fn extend>(&mut self, iter: I) { - match *self { - ThinVec(Some(ref mut vec)) => vec.extend(iter), - ThinVec(None) => *self = iter.into_iter().collect::>().into(), - } - } - - fn extend_one(&mut self, item: T) { - self.push(item) - } - - fn extend_reserve(&mut self, additional: usize) { - match *self { - ThinVec(Some(ref mut vec)) => vec.reserve(additional), - ThinVec(None) => *self = Vec::with_capacity(additional).into(), - } - } -} - -impl, CTX> HashStable for ThinVec { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(hcx, hasher) - } -} - -impl Default for ThinVec { - fn default() -> Self { - Self(None) - } -} - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/thin_vec/tests.rs b/compiler/rustc_data_structures/src/thin_vec/tests.rs deleted file mode 100644 index 0221b9912..000000000 --- a/compiler/rustc_data_structures/src/thin_vec/tests.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::*; - -impl ThinVec { - fn into_vec(self) -> Vec { - self.into() - } -} - -#[test] -fn test_from_iterator() { - assert_eq!(std::iter::empty().collect::>().into_vec(), Vec::::new()); - assert_eq!(std::iter::once(42).collect::>().into_vec(), vec![42]); - assert_eq!([1, 2].into_iter().collect::>().into_vec(), vec![1, 2]); - assert_eq!([1, 2, 3].into_iter().collect::>().into_vec(), vec![1, 2, 3]); -} - -#[test] -fn test_into_iterator_owned() { - assert_eq!(ThinVec::new().into_iter().collect::>(), Vec::::new()); - assert_eq!(ThinVec::from(vec![1]).into_iter().collect::>(), vec![1]); - assert_eq!(ThinVec::from(vec![1, 2]).into_iter().collect::>(), vec![1, 2]); - assert_eq!(ThinVec::from(vec![1, 2, 3]).into_iter().collect::>(), vec![1, 2, 3]); -} - -#[test] -fn test_into_iterator_ref() { - assert_eq!(ThinVec::new().iter().collect::>(), Vec::<&String>::new()); - assert_eq!(ThinVec::from(vec![1]).iter().collect::>(), vec![&1]); - assert_eq!(ThinVec::from(vec![1, 2]).iter().collect::>(), vec![&1, &2]); - assert_eq!(ThinVec::from(vec![1, 2, 3]).iter().collect::>(), vec![&1, &2, &3]); -} - -#[test] -fn test_into_iterator_ref_mut() { - assert_eq!(ThinVec::new().iter_mut().collect::>(), Vec::<&mut String>::new()); - assert_eq!(ThinVec::from(vec![1]).iter_mut().collect::>(), vec![&mut 1]); - assert_eq!(ThinVec::from(vec![1, 2]).iter_mut().collect::>(), vec![&mut 1, &mut 2]); - assert_eq!( - ThinVec::from(vec![1, 2, 3]).iter_mut().collect::>(), - vec![&mut 1, &mut 2, &mut 3], - ); -} diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index 0ff64969b..f016c391f 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -1,45 +1,57 @@ +use crate::frozen::Frozen; use crate::fx::FxIndexSet; -use crate::sync::Lock; 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 TransitiveRelation { +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: Vec, +} + +#[derive(Debug)] +pub struct TransitiveRelation { + // Frozen transitive relation elements and edges. + builder: Frozen>, - // This is a cached transitive closure derived from the edges. - // Currently, we build it lazily and just throw out any existing - // copy whenever a new edge is added. (The Lock is to permit - // the lazy computation.) This is kind of silly, except for the - // fact its size is tied to `self.elements.len()`, so I wanted to - // wait before building it up to avoid reallocating as new edges - // are added with new elements. Perhaps better would be to ask the - // user for a batch of edges to minimize this effect, but I - // already wrote the code this way. :P -nmatsakis - closure: Lock>>, + // Cached transitive closure derived from the edges. + closure: Frozen>, } -// HACK(eddyb) manual impl avoids `Default` bound on `T`. -impl Default for TransitiveRelation { - fn default() -> Self { +impl Deref for TransitiveRelation { + type Target = Frozen>; + + fn deref(&self) -> &Self::Target { + &self.builder + } +} + +impl Clone for TransitiveRelation { + fn clone(&self) -> Self { TransitiveRelation { - elements: Default::default(), - edges: Default::default(), - closure: Default::default(), + 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)] struct Index(usize); @@ -49,7 +61,7 @@ struct Edge { target: Index, } -impl TransitiveRelation { +impl TransitiveRelationBuilder { pub fn is_empty(&self) -> bool { self.edges.is_empty() } @@ -63,23 +75,19 @@ impl TransitiveRelation { } fn add_index(&mut self, a: T) -> Index { - let (index, added) = self.elements.insert_full(a); - if added { - // if we changed the dimensions, clear the cache - *self.closure.get_mut() = None; - } + let (index, _added) = self.elements.insert_full(a); Index(index) } /// Applies the (partial) function to each edge and returns a new - /// relation. If `f` returns `None` for any end-point, returns - /// `None`. - pub fn maybe_map(&self, mut f: F) -> Option> + /// 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 = TransitiveRelation::default(); + let mut result = TransitiveRelationBuilder::default(); for edge in &self.edges { result.add(f(self.elements[edge.source.0])?, f(self.elements[edge.target.0])?); } @@ -93,10 +101,38 @@ impl TransitiveRelation { let edge = Edge { source: a, target: b }; if !self.edges.contains(&edge) { self.edges.push(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); - // added an edge, clear the cache - *self.closure.get_mut() = None; + // 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) @@ -322,30 +358,7 @@ impl TransitiveRelation { where OP: FnOnce(&BitMatrix) -> R, { - let mut closure_cell = self.closure.borrow_mut(); - let mut closure = closure_cell.take(); - if closure.is_none() { - closure = Some(self.compute_closure()); - } - let result = op(closure.as_ref().unwrap()); - *closure_cell = closure; - result - } - - fn compute_closure(&self) -> BitMatrix { - 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); - } - } - matrix + op(&self.closure) } /// Lists all the base edges in the graph: the initial _non-transitive_ set of element diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs index e1f4c7ee0..e756c546e 100644 --- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs +++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs @@ -10,9 +10,10 @@ impl TransitiveRelation { #[test] fn test_one_step() { - let mut relation = TransitiveRelation::default(); + 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")); @@ -21,7 +22,7 @@ fn test_one_step() { #[test] fn test_many_steps() { - let mut relation = TransitiveRelation::default(); + let mut relation = TransitiveRelationBuilder::default(); relation.add("a", "b"); relation.add("a", "c"); relation.add("a", "f"); @@ -31,6 +32,7 @@ fn test_many_steps() { relation.add("b", "e"); relation.add("e", "g"); + let relation = relation.freeze(); assert!(relation.contains("a", "b")); assert!(relation.contains("a", "c")); @@ -51,9 +53,10 @@ fn mubs_triangle() { // ^ // | // b - let mut relation = TransitiveRelation::default(); + 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"]); @@ -72,7 +75,7 @@ fn mubs_best_choice1() { // need the second pare down call to get the right result (after // intersection, we have [1, 2], but 2 -> 1). - let mut relation = TransitiveRelation::default(); + let mut relation = TransitiveRelationBuilder::default(); relation.add("0", "1"); relation.add("0", "2"); @@ -80,6 +83,7 @@ fn mubs_best_choice1() { 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"]); @@ -99,7 +103,7 @@ fn mubs_best_choice2() { // 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 = TransitiveRelation::default(); + let mut relation = TransitiveRelationBuilder::default(); relation.add("0", "1"); relation.add("0", "2"); @@ -107,6 +111,7 @@ fn mubs_best_choice2() { 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"]); @@ -118,12 +123,13 @@ fn mubs_best_choice2() { 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 = TransitiveRelation::default(); + 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"]); @@ -135,7 +141,7 @@ fn mubs_best_choice_scc() { // in this case, 1 and 2 form a cycle; we pick arbitrarily (but // consistently). - let mut relation = TransitiveRelation::default(); + let mut relation = TransitiveRelationBuilder::default(); relation.add("0", "1"); relation.add("0", "2"); @@ -144,6 +150,7 @@ fn mubs_best_choice_scc() { 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"]); @@ -157,13 +164,14 @@ fn pdub_crisscross() { // /\ | // b -> b1 ---+ - let mut relation = TransitiveRelation::default(); + 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")); @@ -179,7 +187,7 @@ fn pdub_crisscross_more() { // /\ /\ | // b -> b1 -> b2 ---------+ - let mut relation = TransitiveRelation::default(); + let mut relation = TransitiveRelationBuilder::default(); relation.add("a", "a1"); relation.add("a", "b1"); relation.add("b", "a1"); @@ -194,6 +202,7 @@ fn pdub_crisscross_more() { 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"]); @@ -210,11 +219,12 @@ fn pdub_lub() { // | // b -> b1 ---+ - let mut relation = TransitiveRelation::default(); + 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")); @@ -233,10 +243,11 @@ fn mubs_intermediate_node_on_one_side_only() { // b // "digraph { a -> c -> d; b -> d; }", - let mut relation = TransitiveRelation::default(); + 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"]); } @@ -252,12 +263,13 @@ fn mubs_scc_1() { // b // "digraph { a -> c -> d; d -> c; a -> d; b -> d; }", - let mut relation = TransitiveRelation::default(); + 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"]); } @@ -272,12 +284,13 @@ fn mubs_scc_2() { // +--- b // "digraph { a -> c -> d; d -> c; b -> d; b -> c; }", - let mut relation = TransitiveRelation::default(); + 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"]); } @@ -292,13 +305,14 @@ fn mubs_scc_3() { // b ---+ // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }", - let mut relation = TransitiveRelation::default(); + 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"]); } @@ -314,13 +328,14 @@ fn mubs_scc_4() { // b ---+ // "digraph { a -> c -> d -> e -> c; a -> d; b -> e; }" - let mut relation = TransitiveRelation::default(); + 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"]); } @@ -352,10 +367,11 @@ fn parent() { (1, /*->*/ 3), ]; - let mut relation = TransitiveRelation::default(); + 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)); diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 08d5d4f34..d1d02ed73 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" crate-type = ["dylib"] [dependencies] -tracing = { version = "0.1.28" } +tracing = { version = "0.1.35" } serde_json = "1.0.59" rustc_log = { path = "../rustc_log" } rustc_middle = { path = "../rustc_middle" } @@ -19,6 +19,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_parse = { path = "../rustc_parse" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 53ae913f9..8fb950819 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -5,10 +5,12 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -16,7 +18,7 @@ extern crate tracing; pub extern crate rustc_plugin_impl as plugin; use rustc_ast as ast; -use rustc_codegen_ssa::{traits::CodegenBackend, CodegenResults}; +use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; @@ -56,6 +58,12 @@ use std::time::Instant; pub mod args; pub mod pretty; +mod session_diagnostics; + +use crate::session_diagnostics::{ + RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, + RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead, +}; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -581,18 +589,35 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp sess.init_crate_types(collect_crate_types(sess, &[])); let outputs = compiler.build_output_filenames(sess, &[]); let rlink_data = fs::read(file).unwrap_or_else(|err| { - sess.fatal(&format!("failed to read rlink file: {}", err)); + sess.emit_fatal(RlinkUnableToRead { err }); }); let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) { Ok(codegen) => codegen, - Err(error) => { - sess.fatal(&format!("Could not deserialize .rlink file: {error}")); + Err(err) => { + match err { + CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType), + CodegenErrors::EmptyVersionNumber => { + sess.emit_fatal(RLinkEmptyVersionNumber) + } + CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => { + sess.emit_fatal(RLinkEncodingVersionMismatch { + version_array, + rlink_version, + }) + } + CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => { + sess.emit_fatal(RLinkRustcVersionMismatch { + rustc_version, + current_version, + }) + } + }; } }; let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); abort_on_err(result, sess); } else { - sess.fatal("rlink must be a file") + sess.emit_fatal(RlinkNotAFile {}) } Compilation::Stop } else { @@ -1070,7 +1095,7 @@ pub fn handle_options(args: &[String]) -> Option { Some(matches) } -fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec> { +fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::AttrVec> { match input { Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess), Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str( @@ -1094,22 +1119,25 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { while let Some(arg) = args.next() { if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) { let content = if arg.len() == a.len() { + // A space-separated option, like `-C incremental=foo` or `--crate-type rlib` match args.next() { Some(arg) => arg.to_string(), None => continue, } } else if arg.get(a.len()..a.len() + 1) == Some("=") { + // An equals option, like `--crate-type=rlib` arg[a.len() + 1..].to_string() } else { + // A non-space option, like `-Cincremental=foo` arg[a.len()..].to_string() }; - if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) { + let option = content.split_once('=').map(|s| s.0).unwrap_or(&content); + if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) { excluded_cargo_defaults = true; } else { result.push(a.to_string()); - match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s)) - { - Some(s) => result.push(s.to_string()), + match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) { + Some(s) => result.push(format!("{}=[REDACTED]", s)), None => result.push(content), } } @@ -1148,6 +1176,17 @@ static DEFAULT_HOOK: LazyLock) + Sync + Send + LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| { + // If the error was caused by a broken pipe then this is not a bug. + // Write the error and return immediately. See #98700. + #[cfg(windows)] + if let Some(msg) = info.payload().downcast_ref::() { + if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") + { + early_error_no_abort(ErrorOutputType::default(), &msg); + return; + } + }; + // Invoke the default handler, which prints the actual panic message and optionally a backtrace (*DEFAULT_HOOK)(info); diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index f66b1a297..2874fa0ca 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -1,5 +1,6 @@ //! The various pretty-printing routines. +use crate::session_diagnostics::UnprettyDumpFail; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; @@ -357,12 +358,15 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) { (src, src_name) } -fn write_or_print(out: &str, ofile: Option<&Path>) { +fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) { match ofile { None => print!("{}", out), Some(p) => { if let Err(e) = std::fs::write(p, out) { - panic!("print-print failed to write {} due to {}", p.display(), e); + sess.emit_fatal(UnprettyDumpFail { + path: p.display().to_string(), + err: e.to_string(), + }); } } } @@ -392,6 +396,7 @@ pub fn print_after_parsing( annotation.pp_ann(), false, parse.edition, + &sess.parse_sess.attr_id_generator, ) }) } @@ -402,7 +407,7 @@ pub fn print_after_parsing( _ => unreachable!(), }; - write_or_print(&out, ofile); + write_or_print(&out, ofile, sess); } pub fn print_after_hir_lowering<'tcx>( @@ -434,6 +439,7 @@ pub fn print_after_hir_lowering<'tcx>( annotation.pp_ann(), true, parse.edition, + &sess.parse_sess.attr_id_generator, ) }) } @@ -468,7 +474,7 @@ pub fn print_after_hir_lowering<'tcx>( _ => unreachable!(), }; - write_or_print(&out, ofile); + write_or_print(&out, ofile, tcx.sess); } // In an ideal world, this would be a public function called by the driver after @@ -512,7 +518,7 @@ fn print_with_analysis( _ => unreachable!(), }; - write_or_print(&out, ofile); + write_or_print(&out, ofile, tcx.sess); Ok(()) } diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs new file mode 100644 index 000000000..e9696792d --- /dev/null +++ b/compiler/rustc_driver/src/session_diagnostics.rs @@ -0,0 +1,40 @@ +use rustc_macros::SessionDiagnostic; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_unable_to_read)] +pub(crate) struct RlinkUnableToRead { + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_wrong_file_type)] +pub(crate) struct RLinkWrongFileType; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_empty_version_number)] +pub(crate) struct RLinkEmptyVersionNumber; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_encoding_version_mismatch)] +pub(crate) struct RLinkEncodingVersionMismatch { + pub version_array: String, + pub rlink_version: u32, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_rustc_version_mismatch)] +pub(crate) struct RLinkRustcVersionMismatch<'a> { + pub rustc_version: String, + pub current_version: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_no_a_file)] +pub(crate) struct RlinkNotAFile; + +#[derive(SessionDiagnostic)] +#[diag(driver::unpretty_dump_fail)] +pub(crate) struct UnprettyDumpFail { + pub path: String, + pub err: String, +} diff --git a/compiler/rustc_error_codes/src/error_codes/E0695.md b/compiler/rustc_error_codes/src/error_codes/E0695.md index 5013e83ca..577f42ef3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0695.md +++ b/compiler/rustc_error_codes/src/error_codes/E0695.md @@ -3,7 +3,6 @@ A `break` statement without a label appeared inside a labeled block. Erroneous code example: ```compile_fail,E0695 -# #![feature(label_break_value)] loop { 'a: { break; @@ -14,7 +13,6 @@ loop { Make sure to always label the `break`: ``` -# #![feature(label_break_value)] 'l: loop { 'a: { break 'l; @@ -25,7 +23,6 @@ Make sure to always label the `break`: Or if you want to `break` the labeled block: ``` -# #![feature(label_break_value)] loop { 'a: { break 'a; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index f2432f616..bd424dd9d 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,4 +1,6 @@ #![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] //! This library is used to gather all error codes into one place, //! the goal being to make their maintenance easier. diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl new file mode 100644 index 000000000..c45e045b4 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -0,0 +1,139 @@ +ast_lowering_generic_type_with_parentheses = + parenthesized type parameters may only be used with a `Fn` trait + .label = only `Fn` traits may use parentheses + +ast_lowering_use_angle_brackets = use angle brackets instead + +ast_lowering_invalid_abi = + invalid ABI: found `{$abi}` + .label = invalid ABI + .help = valid ABIs: {$valid_abis} + +ast_lowering_assoc_ty_parentheses = + parenthesized generic arguments cannot be used in associated type constraints + +ast_lowering_remove_parentheses = remove these parentheses + +ast_lowering_misplaced_impl_trait = + `impl Trait` only allowed in function and inherent method return types, not in {$position} + +ast_lowering_rustc_box_attribute_error = + #[rustc_box] requires precisely one argument and no other attributes are allowed + +ast_lowering_underscore_expr_lhs_assign = + in expressions, `_` can only be used on the left-hand side of an assignment + .label = `_` not allowed here + +ast_lowering_base_expression_double_dot = + base expression required after `..` + .label = add a base expression here + +ast_lowering_await_only_in_async_fn_and_blocks = + `await` is only allowed inside `async` functions and blocks + .label = only allowed inside `async` functions and blocks + +ast_lowering_this_not_async = this is not `async` + +ast_lowering_generator_too_many_parameters = + too many parameters for a generator (expected 0 or 1 parameters) + +ast_lowering_closure_cannot_be_static = closures cannot be static + +ast_lowering_async_non_move_closure_not_supported = + `async` non-`move` closures with parameters are not currently supported + .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure + +ast_lowering_functional_record_update_destructuring_assignment = + functional record updates are not allowed in destructuring assignments + .suggestion = consider removing the trailing pattern + +ast_lowering_async_generators_not_supported = + `async` generators are not yet supported + +ast_lowering_inline_asm_unsupported_target = + inline assembly is unsupported on this target + +ast_lowering_att_syntax_only_x86 = + the `att_syntax` option is only supported on x86 + +ast_lowering_abi_specified_multiple_times = + `{$prev_name}` ABI specified multiple times + .label = previously specified here + .note = these ABIs are equivalent on the current target + +ast_lowering_clobber_abi_not_supported = + `clobber_abi` is not supported on this target + +ast_lowering_invalid_abi_clobber_abi = + invalid ABI for `clobber_abi` + .note = the following ABIs are supported on this target: {$supported_abis} + +ast_lowering_invalid_register = + invalid register `{$reg}`: {$error} + +ast_lowering_invalid_register_class = + invalid register class `{$reg_class}`: {$error} + +ast_lowering_invalid_asm_template_modifier_reg_class = + invalid asm template modifier for this register class + +ast_lowering_argument = argument + +ast_lowering_template_modifier = template modifier + +ast_lowering_support_modifiers = + the `{$class_name}` register class supports the following template modifiers: {$modifiers} + +ast_lowering_does_not_support_modifiers = + the `{$class_name}` register class does not support template modifiers + +ast_lowering_invalid_asm_template_modifier_const = + asm template modifiers are not allowed for `const` arguments + +ast_lowering_invalid_asm_template_modifier_sym = + asm template modifiers are not allowed for `sym` arguments + +ast_lowering_register_class_only_clobber = + register class `{$reg_class_name}` can only be used as a clobber, not as an input or output + +ast_lowering_register_conflict = + register `{$reg1_name}` conflicts with register `{$reg2_name}` + .help = use `lateout` instead of `out` to avoid conflict + +ast_lowering_register1 = register `{$reg1_name}` + +ast_lowering_register2 = register `{$reg2_name}` + +ast_lowering_sub_tuple_binding = + `{$ident_name} @` is not allowed in a {$ctx} + .label = this is only allowed in slice patterns + .help = remove this and bind each tuple field independently + +ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields + +ast_lowering_extra_double_dot = + `..` can only be used once per {$ctx} pattern + .label = can only be used once per {$ctx} pattern + +ast_lowering_previously_used_here = previously used here + +ast_lowering_misplaced_double_dot = + `..` patterns are not allowed here + .note = only allowed in tuple, tuple struct, and slice patterns + +ast_lowering_misplaced_relax_trait_bound = + `?Trait` bounds are only permitted at the point where a type parameter is declared + +ast_lowering_not_supported_for_lifetime_binder_async_closure = + `for<...>` binders on `async` closures are not currently supported + +ast_lowering_arbitrary_expression_in_pattern = + arbitrary expressions aren't allowed in patterns + +ast_lowering_inclusive_range_with_no_end = inclusive range with no end + +ast_lowering_trait_fn_async = + functions in traits cannot be declared `async` + .label = `async` because of this + .note = `async` trait functions are not currently supported + .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl new file mode 100644 index 000000000..e5cd1142b --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl @@ -0,0 +1,91 @@ +ast_passes_forbidden_let = + `let` expressions are not supported here + .note = only supported directly in conditions of `if` and `while` expressions + .not_supported_or = `||` operators are not supported in let chain expressions + .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains + +ast_passes_forbidden_let_stable = + expected expression, found statement (`let`) + .note = variable declaration using `let` is a statement + +ast_passes_deprecated_where_clause_location = + where clause not allowed here + +ast_passes_forbidden_assoc_constraint = + associated type bounds are not allowed within structs, enums, or unions + +ast_passes_keyword_lifetime = + lifetimes cannot use keyword names + +ast_passes_invalid_label = + invalid label name `{$name}` + +ast_passes_invalid_visibility = + unnecessary visibility qualifier + .implied = `pub` not permitted here because it's implied + .individual_impl_items = place qualifiers on individual impl items instead + .individual_foreign_items = place qualifiers on individual foreign items instead + +ast_passes_trait_fn_const = + functions in traits cannot be declared const + .label = functions in traits cannot be const + +ast_passes_forbidden_lifetime_bound = + lifetime bounds cannot be used in this context + +ast_passes_forbidden_non_lifetime_param = + only lifetime parameters can be used in this context + +ast_passes_fn_param_too_many = + function can not have more than {$max_num_args} arguments + +ast_passes_fn_param_c_var_args_only = + C-variadic function must be declared with at least one named argument + +ast_passes_fn_param_c_var_args_not_last = + `...` must be the last argument of a C-variadic function + +ast_passes_fn_param_doc_comment = + documentation comments cannot be applied to function parameters + .label = doc comments are not allowed here + +ast_passes_fn_param_forbidden_attr = + allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +ast_passes_fn_param_forbidden_self = + `self` parameter is only allowed in associated functions + .label = not semantically valid as function parameter + .note = associated functions are those in `impl` or `trait` definitions + +ast_passes_forbidden_default = + `default` is only allowed on items in trait impls + .label = `default` because of this + +ast_passes_assoc_const_without_body = + associated constant in `impl` without body + .suggestion = provide a definition for the constant + +ast_passes_assoc_fn_without_body = + associated function in `impl` without body + .suggestion = provide a definition for the function + +ast_passes_assoc_type_without_body = + associated type in `impl` without body + .suggestion = provide a definition for the type + +ast_passes_const_without_body = + free constant item without body + .suggestion = provide a definition for the constant + +ast_passes_static_without_body = + free static item without body + .suggestion = provide a definition for the static + +ast_passes_ty_alias_without_body = + free type alias without body + .suggestion = provide a definition for the type + +ast_passes_fn_without_body = + free function without a body + .suggestion = provide a definition for the function + .extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block diff --git a/compiler/rustc_error_messages/locales/en-US/attr.ftl b/compiler/rustc_error_messages/locales/en-US/attr.ftl new file mode 100644 index 000000000..a7f8c993d --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/attr.ftl @@ -0,0 +1,107 @@ +attr_expected_one_cfg_pattern = + expected 1 cfg-pattern + +attr_invalid_predicate = + invalid predicate `{$predicate}` + +attr_multiple_item = + multiple '{$item}' items + +attr_incorrect_meta_item = + incorrect meta item + +attr_unknown_meta_item = + unknown meta item '{$item}' + .label = expected one of {$expected} + +attr_missing_since = + missing 'since' + +attr_missing_note = + missing 'note' + +attr_multiple_stability_levels = + multiple stability levels + +attr_invalid_issue_string = + `issue` must be a non-zero numeric string or "none" + .must_not_be_zero = `issue` must not be "0", use "none" instead + .empty = cannot parse integer from empty string + .invalid_digit = invalid digit found in string + .pos_overflow = number too large to fit in target type + .neg_overflow = number too small to fit in target type + +attr_missing_feature = + missing 'feature' + +attr_non_ident_feature = + 'feature' is not an identifier + +attr_missing_issue = + missing 'issue' + +attr_incorrect_repr_format_packed_one_or_zero_arg = + incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all + +attr_invalid_repr_hint_no_paren = + invalid representation hint: `{$name}` does not take a parenthesized argument list + +attr_invalid_repr_hint_no_value = + invalid representation hint: `{$name}` does not take a value + +attr_unsupported_literal_generic = + unsupported literal +attr_unsupported_literal_cfg_string = + literal in `cfg` predicate value must be a string +attr_unsupported_literal_deprecated_string = + literal in `deprecated` value must be a string +attr_unsupported_literal_deprecated_kv_pair = + item in `deprecated` must be a key/value pair +attr_unsupported_literal_suggestion = + consider removing the prefix + +attr_invalid_repr_align_need_arg = + invalid `repr(align)` attribute: `align` needs an argument + .suggestion = supply an argument here + +attr_invalid_repr_generic = + invalid `repr({$repr_arg})` attribute: {$error_part} + +attr_incorrect_repr_format_align_one_arg = + incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + +attr_incorrect_repr_format_generic = + incorrect `repr({$repr_arg})` attribute format + .suggestion = use parentheses instead + +attr_rustc_promotable_pairing = + `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute + +attr_rustc_allowed_unstable_pairing = + `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute + +attr_cfg_predicate_identifier = + `cfg` predicate key must be an identifier + +attr_deprecated_item_suggestion = + suggestions on deprecated items are unstable + .help = add `#![feature(deprecated_suggestion)]` to the crate root + .note = see #94785 for more details + +attr_expected_single_version_literal = + expected single version literal + +attr_expected_version_literal = + expected a version literal + +attr_expects_feature_list = + `{$name}` expects a list of feature names + +attr_expects_features = + `{$name}` expects feature names + +attr_soft_no_args = + `soft` should not have any arguments + +attr_unknown_version_literal = + unknown version literal format, assuming it refers to a future version diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index 645673ef4..67f2156f3 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -1,18 +1,60 @@ -borrowck-move-unsized = +borrowck_move_unsized = cannot move a value of type `{$ty}` .label = the size of `{$ty}` cannot be statically determined -borrowck-higher-ranked-lifetime-error = +borrowck_higher_ranked_lifetime_error = higher-ranked lifetime error -borrowck-could-not-prove = +borrowck_could_not_prove = could not prove `{$predicate}` -borrowck-could-not-normalize = +borrowck_could_not_normalize = could not normalize `{$value}` -borrowck-higher-ranked-subtype-error = +borrowck_higher_ranked_subtype_error = higher-ranked subtype error - -generic-does-not-live-long-enough = - `{$kind}` does not live long enough \ No newline at end of file + +borrowck_generic_does_not_live_long_enough = + `{$kind}` does not live long enough + +borrowck_move_borrowed = + cannot move out of `{$desc}` beacause it is borrowed + +borrowck_var_does_not_need_mut = + variable does not need to be mutable + .suggestion = remove this `mut` + +borrowck_const_not_used_in_type_alias = + const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias + +borrowck_var_cannot_escape_closure = + captured variable cannot escape `FnMut` closure body + .note = `FnMut` closures only have access to their captured variables while they are executing... + .cannot_escape = ...therefore, they cannot allow references to captured variables to escape + +borrowck_var_here_defined = variable defined here + +borrowck_var_here_captured = variable captured here + +borrowck_closure_inferred_mut = inferred to be a `FnMut` closure + +borrowck_returned_closure_escaped = + returns a closure that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_async_block_escaped = + returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_ref_escaped = + returns a reference to a captured variable which escapes the closure body + +borrowck_lifetime_constraints_error = + lifetime may not live long enough + +borrowck_returned_lifetime_wrong = + {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` + +borrowck_returned_lifetime_short = + {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` + +borrowck_used_impl_require_static = + the used `impl` has a `'static` requirement diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl index 1d3e33c81..4d088e27b 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -1,5 +1,5 @@ -builtin-macros-requires-cfg-pattern = +builtin_macros_requires_cfg_pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required -builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern +builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl index 3f2ff8610..33bb116d6 100644 --- a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl +++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl @@ -1,31 +1,83 @@ -const-eval-unstable-in-stable = +const_eval_unstable_in_stable = const-stable function cannot use `#[feature({$gate})]` - .unstable-sugg = if it is not part of the public API, make this function unstably const - .bypass-sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + .unstable_sugg = if it is not part of the public API, make this function unstably const + .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks -const-eval-thread-local-access = +const_eval_thread_local_access = thread-local statics cannot be accessed at compile-time -const-eval-static-access = +const_eval_static_access = {$kind}s cannot refer to statics .help = consider extracting the value of the `static` to a `const`, and referring to that - .teach-note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - .teach-help = To fix this, the value can be extracted to a `const` and then used. + .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. + .teach_help = To fix this, the value can be extracted to a `const` and then used. -const-eval-raw-ptr-to-int = +const_eval_raw_ptr_to_int = pointers cannot be cast to integers during const eval .note = at compile-time, pointers do not have an integer value .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -const-eval-raw-ptr-comparison = +const_eval_raw_ptr_comparison = pointers cannot be reliably compared during const eval .note = see issue #53020 for more information -const-eval-panic-non-str = argument to `panic!()` in a const context must have type `&str` +const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` -const-eval-mut-deref = +const_eval_mut_deref = mutation through a reference is not allowed in {$kind}s -const-eval-transient-mut-borrow = mutable references are not allowed in {$kind}s +const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s -const-eval-transient-mut-borrow-raw = raw mutable references are not allowed in {$kind}s +const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s + +const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} + +const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s + +const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn + +const_eval_unallowed_mutable_refs = + mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_unallowed_mutable_refs_raw = + raw mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_non_const_fmt_macro_call = + cannot call non-const formatting macro in {$kind}s + +const_eval_non_const_fn_call = + cannot call non-const fn `{$def_path_str}` in {$kind}s + +const_eval_unallowed_op_in_const_context = + {$msg} + +const_eval_unallowed_heap_allocations = + allocations are not allowed in {$kind}s + .label = allocation not allowed in {$kind}s + .teach_note = + The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + +const_eval_unallowed_inline_asm = + inline assembly is not allowed in {$kind}s + +const_eval_interior_mutable_data_refer = + {$kind}s cannot refer to interior mutable data + .label = this borrow of an interior mutable value may end up in the final value + .help = to fix this, the value can be extracted to a separate `static` item and then referenced + .teach_note = + A constant containing interior mutable data behind a reference can allow you to modify that data. + This would make multiple uses of a constant to be able to see different values and allow circumventing + the `Send` and `Sync` requirements for shared mutable data, which is unsound. + +const_eval_interior_mutability_borrow = + cannot borrow here, since the borrowed element may contain interior mutability diff --git a/compiler/rustc_error_messages/locales/en-US/driver.ftl b/compiler/rustc_error_messages/locales/en-US/driver.ftl new file mode 100644 index 000000000..8ad198c86 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/driver.ftl @@ -0,0 +1,13 @@ +driver_rlink_unable_to_read = failed to read rlink file: `{$err}` + +driver_rlink_wrong_file_type = The input does not look like a .rlink file + +driver_rlink_empty_version_number = The input does not contain version number + +driver_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}` + +driver_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}` + +driver_rlink_no_a_file = rlink must be a file + +driver_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl index 8d506a3ea..572059115 100644 --- a/compiler/rustc_error_messages/locales/en-US/expand.ftl +++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl @@ -1,5 +1,22 @@ -expand-explain-doc-comment-outer = +expand_explain_doc_comment_outer = outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match -expand-explain-doc-comment-inner = +expand_explain_doc_comment_inner = inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match + +expand_expr_repeat_no_syntax_vars = + attempted to repeat an expression containing no syntax variables matched as repeating at this depth + +expand_must_repeat_once = + this must repeat at least once + +expand_count_repetition_misplaced = + `count` can not be placed inside the inner-most repetition + +expand_meta_var_expr_unrecognized_var = + variable `{$key}` is not recognized in meta-variable expression + +expand_var_still_repeating = + variable '{$ident}' is still repeating at this depth + +expand_meta_var_dif_seq_matchers = {$msg} diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl new file mode 100644 index 000000000..65371a285 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -0,0 +1,171 @@ +infer_opaque_hidden_type = + opaque type's hidden type cannot be another opaque type from the same scope + .label = one of the two opaque types used here has to be outside its defining scope + .opaque_type = opaque type whose hidden type is being assigned + .hidden_type = opaque type being used as hidden type + +infer_type_annotations_needed = {$source_kind -> + [closure] type annotations needed for the closure `{$source_name}` + [normal] type annotations needed for `{$source_name}` + *[other] type annotations needed +} + .label = type must be known at this point + +infer_label_bad = {$bad_kind -> + *[other] cannot infer type + [more_info] cannot infer {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$name}`{$has_parent -> + [true] {" "}declared on the {$parent_prefix} `{$parent_name}` + *[false] {""} + } +} + +infer_source_kind_subdiag_let = {$kind -> + [with_pattern] consider giving `{$name}` an explicit type + [closure] consider giving this closure parameter an explicit type + *[other] consider giving this pattern a type +}{$x_kind -> + [has_name] , where the {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$arg_name}` is specified + [underscore] , where the placeholders `_` are specified + *[empty] {""} +} + +infer_source_kind_subdiag_generic_label = + cannot infer {$is_type -> + [true] type + *[false] the value + } of the {$is_type -> + [true] type + *[false] const + } {$parent_exists -> + [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` + *[false] parameter {$param_name} + } + +infer_source_kind_subdiag_generic_suggestion = + consider specifying the generic {$arg_count -> + [one] argument + *[other] arguments + } + +infer_source_kind_fully_qualified = + try using a fully qualified path to specify the expected types + +infer_source_kind_closure_return = + try giving this closure an explicit return type + +# generator_kind may need to be translated +infer_need_type_info_in_generator = + type inside {$generator_kind -> + [async_block] `async` block + [async_closure] `async` closure + [async_fn] `async fn` body + *[generator] generator + } must be known in this context + + +infer_subtype = ...so that the {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] #[start]` function has the correct type + [intristic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} +infer_subtype_2 = ...so that {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] #[start]` function has the correct type + [intristic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} + +infer_reborrow = ...so that reference does not outlive borrowed content +infer_reborrow_upvar = ...so that closure can access `{$name}` +infer_relate_object_bound = ...so that it can be closed over into an object +infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long +infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at +infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> + [true] ... + *[false] {""} +} +infer_relate_param_bound_2 = ...that is required by this bound +infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied +infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait +infer_ascribe_user_type_prove_predicate = ...so that the where clause holds + +infer_nothing = {""} + +infer_lifetime_mismatch = lifetime mismatch + +infer_declared_different = this parameter and the return type are declared with different lifetimes... +infer_data_returned = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} is returned here + +infer_data_lifetime_flow = ...but data with one lifetime flows into the other here +infer_declared_multiple = this type is declared with multiple lifetimes... +infer_types_declared_different = these two types are declared with different lifetimes... +infer_data_flows = ...but data{$label_var1_exists -> + [true] -> {" "}from `{$label_var1}` + *[false] -> {""} +} flows{$label_var2_exists -> + [true] -> {" "}into `{$label_var2}` + *[false] -> {""} +} here + +infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl -> + [true] {" "}and update trait if needed + *[false] {""} +} +infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + +infer_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [reempty] the empty lifetime + [reemptyuni] the empty lifetime in universe {$desc_arg} + [revar] lifetime {$desc_arg} + + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... +} + +infer_mismatched_static_lifetime = incompatible lifetime on type +infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_msl_introduces_static = introduces a `'static` lifetime requirement +infer_msl_unmet_req = because this has an unmet lifetime requirement +infer_msl_trait_note = this has an implicit `'static` lifetime requirement +infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_error_messages/locales/en-US/interface.ftl new file mode 100644 index 000000000..bbcb8fc28 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/interface.ftl @@ -0,0 +1,43 @@ +interface_ferris_identifier = + Ferris cannot be used as an identifier + .suggestion = try using their name instead + +interface_emoji_identifier = + identifiers cannot contain emoji: `{$ident}` + +interface_mixed_bin_crate = + cannot mix `bin` crate type with others + +interface_mixed_proc_macro_crate = + cannot mix `proc-macro` crate type with others + +interface_proc_macro_doc_without_arg = + Trying to document proc macro crate without passing '--crate-type proc-macro to rustdoc + .warn = The generated documentation may be incorrect + +interface_error_writing_dependencies = + error writing dependencies to `{$path}`: {$error} + +interface_input_file_would_be_overwritten = + the input file "{$path}" would be overwritten by the generated executable + +interface_generated_file_conflicts_with_directory = + the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}" + +interface_temps_dir_error = + failed to find or create the directory specified by `--temps-dir` + +interface_out_dir_error = + failed to find or create the directory specified by `--out-dir` + +interface_cant_emit_mir = + could not emit MIR: {$error} + +interface_rustc_error_fatal = + fatal error triggered by #[rustc_error] + +interface_rustc_error_unexpected_annotation = + unexpected annotation used with `#[rustc_error(...)]! + +interface_failed_writing_file = + failed to write file {$path}: {$error}" diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 55e96e58e..7f9918e4f 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -1,22 +1,22 @@ -lint-array-into-iter = +lint_array_into_iter = this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 - .use-iter-suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity - .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value - .use-explicit-into-iter-suggestion = + .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value + .use_explicit_into_iter_suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value -lint-enum-intrinsics-mem-discriminant = +lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. -lint-enum-intrinsics-mem-variant = +lint_enum_intrinsics_mem_variant = the return value of `mem::variant_count` is unspecified when called with a non-enum type .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. -lint-expectation = this lint expectation is unfulfilled +lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message -lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of text present in {$label} +lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> [one] an invisible *[other] invisible @@ -25,68 +25,68 @@ lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of *[other] codepoints } .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen - .suggestion-remove = if their presence wasn't intentional, you can remove them - .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them - .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + .suggestion_remove = if their presence wasn't intentional, you can remove them + .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them + .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} -lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance +lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary -lint-query-instability = using `{$query}` can result in unstable query results +lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale -lint-tykind-kind = usage of `ty::TyKind::` +lint_tykind_kind = usage of `ty::TyKind::` .suggestion = try using `ty::` directly -lint-tykind = usage of `ty::TyKind` +lint_tykind = usage of `ty::TyKind` .help = try using `Ty` instead -lint-ty-qualified = usage of qualified `ty::{$ty}` +lint_ty_qualified = usage of qualified `ty::{$ty}` .suggestion = try importing it and using it unqualified -lint-lintpass-by-hand = implementing `LintPass` by hand +lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead -lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` +lint_non_existant_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` .help = only existing keywords are allowed in core/std -lint-diag-out-of-impl = +lint_diag_out_of_impl = diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls -lint-untranslatable-diag = diagnostics should be created using translatable messages +lint_untranslatable_diag = diagnostics should be created using translatable messages -lint-cstring-ptr = getting the inner pointer of a temporary `CString` - .as-ptr-label = this pointer will be invalid - .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime +lint_cstring_ptr = getting the inner pointer of a temporary `CString` + .as_ptr_label = this pointer will be invalid + .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html -lint-identifier-non-ascii-char = identifier contains non-ASCII characters +lint_identifier_non_ascii_char = identifier contains non-ASCII characters -lint-identifier-uncommon-codepoints = identifier contains uncommon Unicode codepoints +lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints -lint-confusable-identifier-pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` +lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` .label = this is where the previous identifier occurred -lint-mixed-script-confusables = +lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables - .includes-note = the usage includes {$includes} + .includes_note = the usage includes {$includes} .note = please recheck to make sure their usages are indeed what you want -lint-non-fmt-panic = panic message is not a string literal +lint_non_fmt_panic = panic message is not a string literal .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 - .more-info-note = for more information, see - .supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here - .supports-fmt-suggestion = remove the `format!(..)` macro call - .display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message - .debug-suggestion = + .more_info_note = for more information, see + .supports_fmt_note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here + .supports_fmt_suggestion = remove the `format!(..)` macro call + .display_suggestion = add a "{"{"}{"}"}" format string to `Display` the message + .debug_suggestion = add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}` - .panic-suggestion = {$already_suggested -> + .panic_suggestion = {$already_suggested -> [true] or use *[false] use } std::panic::panic_any instead -lint-non-fmt-panic-unused = +lint_non_fmt_panic_unused = panic message contains {$count -> [one] an unused *[other] unused @@ -95,13 +95,13 @@ lint-non-fmt-panic-unused = *[other] placeholders } .note = this message is not used as a format string when given without arguments, but will be in Rust 2021 - .add-args-suggestion = add the missing {$count -> + .add_args_suggestion = add the missing {$count -> [one] argument *[other] arguments } - .add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally + .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally -lint-non-fmt-panic-braces = +lint_non_fmt_panic_braces = panic message contains {$count -> [one] a brace *[other] braces @@ -109,30 +109,30 @@ lint-non-fmt-panic-braces = .note = this message is not used as a format string, but will be in Rust 2021 .suggestion = add a "{"{"}{"}"}" format string to use the message literally -lint-non-camel-case-type = {$sort} `{$name}` should have an upper camel case name +lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name .suggestion = convert the identifier to upper camel case .label = should have an UpperCamelCase name -lint-non-snake-case = {$sort} `{$name}` should have a snake case name - .rename-or-convert-suggestion = rename the identifier or convert it to a snake case raw identifier - .cannot-convert-note = `{$sc}` cannot be used as a raw identifier - .rename-suggestion = rename the identifier - .convert-suggestion = convert the identifier to snake case +lint_non_snake_case = {$sort} `{$name}` should have a snake case name + .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier + .cannot_convert_note = `{$sc}` cannot be used as a raw identifier + .rename_suggestion = rename the identifier + .convert_suggestion = convert the identifier to snake case .help = convert the identifier to snake case: `{$sc}` .label = should have a snake_case name -lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name +lint_non_upper_case_global = {$sort} `{$name}` should have an upper case name .suggestion = convert the identifier to upper case .label = should have an UPPER_CASE name -lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing +lint_noop_method_call = call to `.{$method}()` on a reference in this situation does nothing .label = unnecessary method call .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed -lint-pass-by-value = passing `{$ty}` by reference +lint_pass_by_value = passing `{$ty}` by reference .suggestion = try passing by value -lint-redundant-semicolons = +lint_redundant_semicolons = unnecessary trailing {$multiple -> [true] semicolons *[false] semicolon @@ -142,254 +142,294 @@ lint-redundant-semicolons = *[false] this semicolon } -lint-drop-trait-constraints = +lint_drop_trait_constraints = bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped -lint-drop-glue = +lint_drop_glue = types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped -lint-range-endpoint-out-of-range = range endpoint is out of range for `{$ty}` +lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` .suggestion = use an inclusive range instead -lint-overflowing-bin-hex = literal out of range for `{$ty}` - .negative-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` - .negative-becomes-note = and the value `-{$lit}` will become `{$actually}{$ty}` - .positive-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` +lint_overflowing_bin_hex = literal out of range for `{$ty}` + .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` + .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` + .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` .suggestion = consider using the type `{$suggestion_ty}` instead .help = consider using the type `{$suggestion_ty}` instead -lint-overflowing-int = literal out of range for `{$ty}` +lint_overflowing_int = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` .help = consider using the type `{$suggestion_ty}` instead -lint-only-cast-u8-to-char = only `u8` can be cast into `char` +lint_only_cast_u8_to_char = only `u8` can be cast into `char` .suggestion = use a `char` literal instead -lint-overflowing-uint = literal out of range for `{$ty}` +lint_overflowing_uint = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` -lint-overflowing-literal = literal out of range for `{$ty}` +lint_overflowing_literal = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` -lint-unused-comparisons = comparison is useless due to type limits +lint_unused_comparisons = comparison is useless due to type limits -lint-improper-ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe +lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe .label = not FFI-safe .note = the type is defined here -lint-improper-ctypes-opaque = opaque types have no C equivalent +lint_improper_ctypes_opaque = opaque types have no C equivalent -lint-improper-ctypes-fnptr-reason = this function pointer has Rust-specific calling convention -lint-improper-ctypes-fnptr-help = consider using an `extern fn(...) -> ...` function pointer instead +lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention +lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead -lint-improper-ctypes-tuple-reason = tuples have unspecified layout -lint-improper-ctypes-tuple-help = consider using a struct instead +lint_improper_ctypes_tuple_reason = tuples have unspecified layout +lint_improper_ctypes_tuple_help = consider using a struct instead -lint-improper-ctypes-str-reason = string slices have no C equivalent -lint-improper-ctypes-str-help = consider using `*const u8` and a length instead +lint_improper_ctypes_str_reason = string slices have no C equivalent +lint_improper_ctypes_str_help = consider using `*const u8` and a length instead -lint-improper-ctypes-dyn = trait objects have no C equivalent +lint_improper_ctypes_dyn = trait objects have no C equivalent -lint-improper-ctypes-slice-reason = slices have no C equivalent -lint-improper-ctypes-slice-help = consider using a raw pointer instead +lint_improper_ctypes_slice_reason = slices have no C equivalent +lint_improper_ctypes_slice_help = consider using a raw pointer instead -lint-improper-ctypes-128bit = 128-bit integers don't currently have a known stable ABI +lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI -lint-improper-ctypes-char-reason = the `char` type has no C equivalent -lint-improper-ctypes-char-help = consider using `u32` or `libc::wchar_t` instead +lint_improper_ctypes_char_reason = the `char` type has no C equivalent +lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead -lint-improper-ctypes-non-exhaustive = this enum is non-exhaustive -lint-improper-ctypes-non-exhaustive-variant = this enum has non-exhaustive variants +lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive +lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants -lint-improper-ctypes-enum-repr-reason = enum has no representation hint -lint-improper-ctypes-enum-repr-help = +lint_improper_ctypes_enum_repr_reason = enum has no representation hint +lint_improper_ctypes_enum_repr_help = consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum -lint-improper-ctypes-struct-fieldless-reason = this struct has no fields -lint-improper-ctypes-struct-fieldless-help = consider adding a member to this struct +lint_improper_ctypes_struct_fieldless_reason = this struct has no fields +lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct -lint-improper-ctypes-union-fieldless-reason = this union has no fields -lint-improper-ctypes-union-fieldless-help = consider adding a member to this union +lint_improper_ctypes_union_fieldless_reason = this union has no fields +lint_improper_ctypes_union_fieldless_help = consider adding a member to this union -lint-improper-ctypes-struct-non-exhaustive = this struct is non-exhaustive -lint-improper-ctypes-union-non-exhaustive = this union is non-exhaustive +lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive +lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive -lint-improper-ctypes-struct-layout-reason = this struct has unspecified layout -lint-improper-ctypes-struct-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct +lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout +lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct -lint-improper-ctypes-union-layout-reason = this union has unspecified layout -lint-improper-ctypes-union-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union +lint_improper_ctypes_union_layout_reason = this union has unspecified layout +lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union -lint-improper-ctypes-box = box cannot be represented as a single pointer +lint_improper_ctypes_box = box cannot be represented as a single pointer -lint-improper-ctypes-enum-phantomdata = this enum contains a PhantomData field +lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field -lint-improper-ctypes-struct-zst = this struct contains only zero-sized fields +lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields -lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe -lint-improper-ctypes-array-help = consider passing a pointer to the array +lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe +lint_improper_ctypes_array_help = consider passing a pointer to the array -lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` +lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` -lint-variant-size-differences = +lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest -lint-atomic-ordering-load = atomic loads cannot have `Release` or `AcqRel` ordering +lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` -lint-atomic-ordering-store = atomic stores cannot have `Acquire` or `AcqRel` ordering +lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` -lint-atomic-ordering-fence = memory fences cannot have `Relaxed` ordering +lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` -lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write +lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write .label = invalid failure ordering .help = consider using `Acquire` or `Relaxed` failure ordering instead -lint-unused-op = unused {$op} that must be used +lint_unused_op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value -lint-unused-result = unused result of type `{$ty}` +lint_unused_result = unused result of type `{$ty}` -lint-unused-closure = +lint_unused_closure = unused {$pre}{$count -> [one] closure *[other] closures }{$post} that must be used .note = closures are lazy and do nothing unless called -lint-unused-generator = +lint_unused_generator = unused {$pre}{$count -> [one] generator *[other] generator }{$post} that must be used .note = generators are lazy and do nothing unless resumed -lint-unused-def = unused {$pre}`{$def}`{$post} that must be used +lint_unused_def = unused {$pre}`{$def}`{$post} that must be used -lint-path-statement-drop = path statement drops value +lint_path_statement_drop = path statement drops value .suggestion = use `drop` to clarify the intent -lint-path-statement-no-effect = path statement with no effect +lint_path_statement_no_effect = path statement with no effect -lint-unused-delim = unnecessary {$delim} around {$item} +lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} -lint-unused-import-braces = braces around {$node} is unnecessary +lint_unused_import_braces = braces around {$node} is unnecessary -lint-unused-allocation = unnecessary allocation, use `&` instead -lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead +lint_unused_allocation = unnecessary allocation, use `&` instead +lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead -lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` +lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` -lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} +lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} -lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant +lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant .suggestion = use shorthand field pattern -lint-builtin-overridden-symbol-name = +lint_builtin_overridden_symbol_name = the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them -lint-builtin-overridden-symbol-section = +lint_builtin_overridden_symbol_section = the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them -lint-builtin-allow-internal-unsafe = +lint_builtin_allow_internal_unsafe = `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site -lint-builtin-unsafe-block = usage of an `unsafe` block +lint_builtin_unsafe_block = usage of an `unsafe` block -lint-builtin-unsafe-trait = declaration of an `unsafe` trait +lint_builtin_unsafe_trait = declaration of an `unsafe` trait -lint-builtin-unsafe-impl = implementation of an `unsafe` trait +lint_builtin_unsafe_impl = implementation of an `unsafe` trait -lint-builtin-no-mangle-fn = declaration of a `no_mangle` function -lint-builtin-export-name-fn = declaration of a function with `export_name` -lint-builtin-link-section-fn = declaration of a function with `link_section` +lint_builtin_no_mangle_fn = declaration of a `no_mangle` function +lint_builtin_export_name_fn = declaration of a function with `export_name` +lint_builtin_link_section_fn = declaration of a function with `link_section` -lint-builtin-no-mangle-static = declaration of a `no_mangle` static -lint-builtin-export-name-static = declaration of a static with `export_name` -lint-builtin-link-section-static = declaration of a static with `link_section` +lint_builtin_no_mangle_static = declaration of a `no_mangle` static +lint_builtin_export_name_static = declaration of a static with `export_name` +lint_builtin_link_section_static = declaration of a static with `link_section` -lint-builtin-no-mangle-method = declaration of a `no_mangle` method -lint-builtin-export-name-method = declaration of a method with `export_name` +lint_builtin_no_mangle_method = declaration of a `no_mangle` method +lint_builtin_export_name_method = declaration of a method with `export_name` -lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function -lint-builtin-decl-unsafe-method = declaration of an `unsafe` method -lint-builtin-impl-unsafe-method = implementation of an `unsafe` method +lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function +lint_builtin_decl_unsafe_method = declaration of an `unsafe` method +lint_builtin_impl_unsafe_method = implementation of an `unsafe` method -lint-builtin-missing-doc = missing documentation for {$article} {$desc} +lint_builtin_missing_doc = missing documentation for {$article} {$desc} -lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy` +lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy` -lint-builtin-missing-debug-impl = +lint_builtin_missing_debug_impl = type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation -lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition +lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition .suggestion = try naming the parameter or explicitly ignoring it -lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link} -lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used. -lint-builtin-deprecated-attr-default-suggestion = remove this attribute +lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} +lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. +lint_builtin_deprecated_attr_default_suggestion = remove this attribute -lint-builtin-unused-doc-comment = unused doc comment +lint_builtin_unused_doc_comment = unused doc comment .label = rustdoc does not generate documentation for {$kind} - .plain-help = use `//` for a plain comment - .block-help = use `/* */` for a plain comment + .plain_help = use `//` for a plain comment + .block_help = use `/* */` for a plain comment -lint-builtin-no-mangle-generic = functions generic over types or consts must be mangled +lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled .suggestion = remove this attribute -lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` +lint_builtin_const_no_mangle = const items should never be `#[no_mangle]` .suggestion = try a static value -lint-builtin-mutable-transmutes = +lint_builtin_mutable_transmutes = transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell -lint-builtin-unstable-features = unstable feature +lint_builtin_unstable_features = unstable feature -lint-builtin-unreachable-pub = unreachable `pub` {$what} +lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility .help = or consider exporting it for use by other crates -lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases +lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name + .help = was set with `--cfg` but isn't in the `--check-cfg` expected names -lint-builtin-type-alias-where-clause = where clauses are not enforced in type aliases +lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}` + .help = was set with `--cfg` but isn't in the `--check-cfg` expected values + +lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases + +lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases .suggestion = the clause will not be checked when the type alias is used, and should be removed -lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases +lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases .suggestion = the bound will not be checked when the type alias is used, and should be removed -lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters +lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters -lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated +lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated .suggestion = use `..=` for an inclusive range -lint-builtin-unnameable-test-items = cannot test inner items +lint_builtin_unnameable_test_items = cannot test inner items -lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition +lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition .suggestion = you can use a raw identifier to stay compatible -lint-builtin-explicit-outlives = outlives requirements can be inferred +lint_builtin_explicit_outlives = outlives requirements can be inferred .suggestion = remove {$count -> [one] this bound *[other] these bounds } -lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes +lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes .note = see issue #{$n} for more information .help = consider using `min_{$name}` instead, which is more stable and complete -lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a different signature - .previous-decl-label = `{$orig}` previously declared here - .mismatch-label = this signature doesn't match the previous declaration -lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature - .previous-decl-label = `{$orig}` previously declared here - .mismatch-label = this signature doesn't match the previous declaration +lint_builtin_clashing_extern_same_name = `{$this_fi}` redeclared with a different signature + .previous_decl_label = `{$orig}` previously declared here + .mismatch_label = this signature doesn't match the previous declaration +lint_builtin_clashing_extern_diff_name = `{$this_fi}` redeclares `{$orig}` with a different signature + .previous_decl_label = `{$orig}` previously declared here + .mismatch_label = this signature doesn't match the previous declaration -lint-builtin-deref-nullptr = dereferencing a null pointer +lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed -lint-builtin-asm-labels = avoid using named labels in inline assembly +lint_builtin_asm_labels = avoid using named labels in inline assembly + +lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid + .label = overruled by previous forbid + +lint_default_source = `forbid` lint level is the default for {$id} + +lint_node_source = `forbid` level set here + .note = {$reason} + +lint_command_line_source = `forbid` lint level was set on command line + +lint_malformed_attribute = malformed lint attribute input + +lint_bad_attribute_argument = bad attribute argument + +lint_reason_must_be_string_literal = reason must be a string literal + +lint_reason_must_come_last = reason in lint attribute must come last + +lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` + .help = add `#![register_tool({$tool_name})]` to the crate root + +lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ + +lint_requested_level = requested on the command line with `{$level} {$lint_name}` + +lint_check_name_unknown = unknown lint: `{$lint_name}` + .help = did you mean: `{$suggestion}` + +lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` + +lint_check_name_warning = {$msg} + +lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl new file mode 100644 index 000000000..d27100c56 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -0,0 +1,275 @@ +metadata_rlib_required = + crate `{$crate_name}` required to be available in rlib format, but was not found in this form + +metadata_lib_required = + crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form + +metadata_crate_dep_multiple = + cannot satisfy dependencies so `{$crate_name}` only shows up once + .help = having upstream crates all available in one format will likely make this go away + +metadata_two_panic_runtimes = + cannot link together two panic runtimes: {$prev_name} and {$cur_name} + +metadata_bad_panic_strategy = + the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}` + +metadata_required_panic_strategy = + the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` + +metadata_incompatible_panic_in_drop_strategy = + the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` + +metadata_multiple_names_in_link = + multiple `name` arguments in a single `#[link]` attribute + +metadata_multiple_kinds_in_link = + multiple `kind` arguments in a single `#[link]` attribute + +metadata_link_name_form = + link name must be of the form `name = "string"` + +metadata_link_kind_form = + link kind must be of the form `kind = "string"` + +metadata_link_modifiers_form = + link modifiers must be of the form `modifiers = "string"` + +metadata_link_cfg_form = + link cfg must be of the form `cfg(/* predicate */)` + +metadata_wasm_import_form = + wasm import module must be of the form `wasm_import_module = "string"` + +metadata_empty_link_name = + link name must not be empty + .label = empty link name + +metadata_link_framework_apple = + link kind `framework` is only supported on Apple targets + +metadata_framework_only_windows = + link kind `raw-dylib` is only supported on Windows targets + +metadata_unknown_link_kind = + unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib + .label = unknown link kind + +metadata_multiple_link_modifiers = + multiple `modifiers` arguments in a single `#[link]` attribute + +metadata_multiple_cfgs = + multiple `cfg` arguments in a single `#[link]` attribute + +metadata_link_cfg_single_predicate = + link cfg must have a single predicate argument + +metadata_multiple_wasm_import = + multiple `wasm_import_module` arguments in a single `#[link]` attribute + +metadata_unexpected_link_arg = + unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type + +metadata_invalid_link_modifier = + invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + +metadata_multiple_modifiers = + multiple `{$modifier}` modifiers in a single `modifiers` argument + +metadata_bundle_needs_static = + linking modifier `bundle` is only compatible with `static` linking kind + +metadata_whole_archive_needs_static = + linking modifier `whole-archive` is only compatible with `static` linking kind + +metadata_as_needed_compatibility = + linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds + +metadata_unknown_link_modifier = + unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed + +metadata_incompatible_wasm_link = + `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + +metadata_link_requires_name = + `#[link]` attribute requires a `name = "string"` argument + .label = missing `name` argument + +metadata_raw_dylib_no_nul = + link name must not contain NUL characters if link kind is `raw-dylib` + +metadata_link_ordinal_raw_dylib = + `#[link_ordinal]` is only supported if link kind is `raw-dylib` + +metadata_lib_framework_apple = + library kind `framework` is only supported on Apple targets + +metadata_empty_renaming_target = + an empty renaming target was specified for library `{$lib_name}` + +metadata_renaming_no_link = + renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library + +metadata_multiple_renamings = + multiple renamings were specified for library `{$lib_name}` + +metadata_no_link_mod_override = + overriding linking modifiers from command line is not supported + +metadata_unsupported_abi_i686 = + ABI not supported by `#[link(kind = "raw-dylib")]` on i686 + +metadata_unsupported_abi = + ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture + +metadata_fail_create_file_encoder = + failed to create file encoder: {$err} + +metadata_fail_seek_file = + failed to seek the file: {$err} + +metadata_fail_write_file = + failed to write to the file: {$err} + +metadata_crate_not_panic_runtime = + the crate `{$crate_name}` is not a panic runtime + +metadata_no_panic_strategy = + the crate `{$crate_name}` does not have the panic strategy `{$strategy}` + +metadata_profiler_builtins_needs_core = + `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` + +metadata_not_profiler_runtime = + the crate `{$crate_name}` is not a profiler runtime + +metadata_no_multiple_global_alloc = + cannot define multiple global allocators + .label = cannot define a new global allocator + +metadata_prev_global_alloc = + previous global allocator defined here + +metadata_conflicting_global_alloc = + the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} + +metadata_global_alloc_required = + no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait + +metadata_no_transitive_needs_dep = + the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` + +metadata_failed_write_error = + failed to write {$filename}: {$err} + +metadata_missing_native_library = + could not find native static library `{$libname}`, perhaps an -L flag is missing? + +metadata_failed_create_tempdir = + couldn't create a temp dir: {$err} + +metadata_failed_create_file = + failed to create the file {$filename}: {$err} + +metadata_failed_create_encoded_metadata = + failed to create encoded metadata from file: {$err} + +metadata_non_ascii_name = + cannot load a crate with a non-ascii name `{$crate_name}` + +metadata_extern_location_not_exist = + extern location for {$crate_name} does not exist: {$location} + +metadata_extern_location_not_file = + extern location for {$crate_name} is not a file: {$location} + +metadata_multiple_candidates = + multiple {$flavor} candidates for `{$crate_name}` found + +metadata_multiple_matching_crates = + multiple matching crates for `{$crate_name}` + .note = candidates:{$candidates} + +metadata_symbol_conflicts_current = + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. + +metadata_symbol_conflicts_others = + found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two. + +metadata_stable_crate_id_collision = + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. + +metadata_dl_error = + {$err} + +metadata_newer_crate_version = + found possibly newer version of crate `{$crate_name}`{$add_info} + .note = perhaps that crate needs to be recompiled? + +metadata_found_crate_versions = + the following crate versions were found:{$found_crates} + +metadata_no_crate_with_triple = + couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info} + +metadata_found_staticlib = + found staticlib `{$crate_name}` instead of rlib or dylib{$add_info} + .help = please recompile that crate using --crate-type lib + +metadata_incompatible_rustc = + found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info} + .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first) + +metadata_invalid_meta_files = + found invalid metadata files for crate `{$crate_name}`{$add_info} + +metadata_cannot_find_crate = + can't find crate for `{$crate_name}`{$add_info} + +metadata_no_dylib_plugin = + plugin `{$crate_name}` only found in rlib format, but must be available in dylib format + +metadata_target_not_installed = + the `{$locator_triple}` target may not be installed + +metadata_target_no_std_support = + the `{$locator_triple}` target may not support the standard library + +metadata_consider_downloading_target = + consider downloading the target with `rustup target add {$locator_triple}` + +metadata_std_required = + `std` is required by `{$current_crate}` because it does not declare `#![no_std]` + +metadata_consider_building_std = + consider building the standard library from source with `cargo build -Zbuild-std` + +metadata_compiler_missing_profiler = + the compiler may have been built without the profiler runtime + +metadata_install_missing_components = + maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` + +metadata_cant_find_crate = + can't find crate + +metadata_crate_location_unknown_type = + extern location for {$crate_name} is of an unknown type: {$path} + +metadata_lib_filename_form = + file name should be lib*.rlib or {dll_prefix}*.{dll_suffix} + +metadata_multiple_import_name_type = + multiple `import_name_type` arguments in a single `#[link]` attribute + +metadata_import_name_type_form = + import name type must be of the form `import_name_type = "string"` + +metadata_import_name_type_x86 = + import name type is only supported on x86 + +metadata_unknown_import_name_type = + unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated + +metadata_import_name_type_raw = + import name type can only be used with link kind `raw-dylib` diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl new file mode 100644 index 000000000..ed8348864 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -0,0 +1,17 @@ +middle_drop_check_overflow = + overflow while adding drop-check rules for {$ty} + .note = overflowed on {$overflow_ty} + +middle_opaque_hidden_type_mismatch = + concrete type differs from previous defining opaque type use + .label = expected `{$self_ty}`, got `{$other_ty}` + +middle_conflict_types = + this expression supplies two conflicting concrete types for the same opaque type + +middle_previous_use_here = + previous use here + +middle_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} diff --git a/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl b/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl new file mode 100644 index 000000000..988541525 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl @@ -0,0 +1,29 @@ +mir_dataflow_path_must_end_in_filename = + path must end in a filename + +mir_dataflow_unknown_formatter = + unknown formatter + +mir_dataflow_duplicate_values_for = + duplicate values for `{$name}` + +mir_dataflow_requires_an_argument = + `{$name}` requires an argument + +mir_dataflow_stop_after_dataflow_ended_compilation = + stop_after_dataflow ended compilation + +mir_dataflow_peek_must_be_place_or_ref_place = + rustc_peek: argument expression must be either `place` or `&place` + +mir_dataflow_peek_must_be_not_temporary = + dataflow::sanity_check cannot feed a non-temp to rustc_peek + +mir_dataflow_peek_bit_not_set = + rustc_peek: bit not set + +mir_dataflow_peek_argument_not_a_local = + rustc_peek: argument was not a local + +mir_dataflow_peek_argument_untracked = + rustc_peek: argument untracked diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl new file mode 100644 index 000000000..42c84fdd2 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl @@ -0,0 +1,26 @@ +monomorphize_recursion_limit = + reached the recursion limit while instantiating `{$shrunk}` + .note = `{$def_path_str}` defined here + +monomorphize_written_to_path = the full type name has been written to '{$path}' + +monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` + +monomorphize_consider_type_length_limit = + consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate + +monomorphize_fatal_error = {$error_message} + +monomorphize_unknown_partition_strategy = unknown partitioning strategy + +monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined + +monomorphize_unused_generic_params = item has unused generic parameters + +monomorphize_large_assignments = + moving {$size} bytes + .label = value moved from here + .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +monomorphize_requires_lang_item = + requires `{$lang_item}` lang_item diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 076b1b1ca..f74df3d97 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -1,34 +1,158 @@ -parser-struct-literal-body-without-path = +parser_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block -parser-maybe-report-ambiguous-plus = +parser_maybe_report_ambiguous_plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate -parser-maybe-recover-from-bad-type-plus = +parser_maybe_recover_from_bad_type_plus = expected a path on the left-hand side of `+`, not `{$ty}` -parser-add-paren = try adding parentheses +parser_add_paren = try adding parentheses -parser-forgot-paren = perhaps you forgot parentheses? +parser_forgot_paren = perhaps you forgot parentheses? -parser-expect-path = expected a path +parser_expect_path = expected a path -parser-maybe-recover-from-bad-qpath-stage-2 = +parser_maybe_recover_from_bad_qpath_stage_2 = missing angle brackets in associated item path .suggestion = try: `{$ty}` -parser-incorrect-semicolon = +parser_incorrect_semicolon = expected item, found `;` .suggestion = remove this semicolon .help = {$name} declarations are not followed by a semicolon -parser-incorrect-use-of-await = +parser_incorrect_use_of_await = incorrect use of `await` - .parentheses-suggestion = `await` is not a method call, remove the parentheses - .postfix-suggestion = `await` is a postfix operation + .parentheses_suggestion = `await` is not a method call, remove the parentheses + .postfix_suggestion = `await` is a postfix operation -parser-in-in-typo = +parser_in_in_typo = expected iterable, found keyword `in` .suggestion = remove the duplicated `in` + +parser_invalid_variable_declaration = + invalid variable declaration + +parser_switch_mut_let_order = + switch the order of `mut` and `let` +parser_missing_let_before_mut = missing keyword +parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable +parser_use_let_not_var = write `let` instead of `var` to introduce a new variable + +parser_invalid_comparison_operator = invalid comparison operator `{$invalid}` + .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` + .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` + +parser_invalid_logical_operator = `{$incorrect}` is not a logical operator + .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators + .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction + .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction + +parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator + .suggestion = use `!` to perform bitwise not + +parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier + .suggestion = use `!` to perform logical negation + +parser_malformed_loop_label = malformed loop label + .suggestion = use the correct loop label format + +parser_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes + .suggestion = remove the lifetime annotation + .label = annotated with lifetime here + +parser_field_expression_with_generic = field expressions cannot have generic arguments + +parser_macro_invocation_with_qualified_path = macros cannot use qualified paths + +parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label + +parser_require_colon_after_labeled_expression = labeled expression must be followed by `:` + .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them + .label = the label + .suggestion = add `:` after the label + +parser_do_catch_syntax_removed = found removed `do catch` syntax + .note = following RFC #2388, the new non-placeholder syntax is `try` + .suggestion = replace with the new syntax + +parser_float_literal_requires_integer_part = float literals must have an integer part + .suggestion = must have an integer part + +parser_invalid_int_literal_width = invalid width `{$width}` for integer literal + .help = valid widths are 8, 16, 32, 64 and 128 + +parser_invalid_num_literal_base_prefix = invalid base prefix for number literal + .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase + .suggestion = try making the prefix lowercase + +parser_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal + .label = invalid suffix `{$suffix}` + .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +parser_invalid_float_literal_width = invalid width `{$width}` for float literal + .help = valid widths are 32 and 64 + +parser_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal + .label = invalid suffix `{$suffix}` + .help = valid suffixes are `f32` and `f64` + +parser_int_literal_too_large = integer literal is too large + +parser_missing_semicolon_before_array = expected `;`, found `[` + .suggestion = consider adding `;` here + +parser_invalid_block_macro_segment = cannot use a `block` macro fragment here + .label = the `block` fragment is within this context + +parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition + .add_then_block = add a block here + .condition_possibly_unfinished = this binary operation is possibly unfinished + +parser_if_expression_missing_condition = missing condition for `if` expression + .condition_label = expected condition here + .block_label = if this block is the condition of the `if` expression, then it must be followed by another block + +parser_expected_expression_found_let = expected expression, found `let` statement + +parser_expected_else_block = expected `{"{"}`, found {$first_tok} + .label = expected an `if` or a block after this `else` + .suggestion = add an `if` if this is the condition of a chained `else if` statement + +parser_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches + .branch_label = the attributes are attached to this branch + .ctx_label = the branch belongs to this `{$ctx}` + .suggestion = remove the attributes + +parser_missing_in_in_for_loop = missing `in` in `for` loop + .use_in_not_of = try using `in` here instead + .add_in = try adding `in` here + +parser_missing_comma_after_match_arm = expected `,` following `match` arm + .suggestion = missing a comma here to end this `match` arm + +parser_catch_after_try = keyword `catch` cannot follow a `try` block + .help = try using `match` on the result of the `try` block instead + +parser_comma_after_base_struct = cannot use a comma after the base struct + .note = the base struct must always be the last field + .suggestion = remove this comma + +parser_eq_field_init = expected `:`, found `=` + .suggestion = replace equals symbol with a colon + +parser_dotdotdot = unexpected token: `...` + .suggest_exclusive_range = use `..` for an exclusive range + .suggest_inclusive_range = or `..=` for an inclusive range + +parser_left_arrow_operator = unexpected token: `<-` + .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` + +parser_remove_let = expected pattern, found `let` + .suggestion = remove the unnecessary `let` keyword + +parser_use_eq_instead = unexpected `==` + .suggestion = try using `=` instead diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index b17eb9c2d..556a6452f 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -1,178 +1,178 @@ --passes-previously-accepted = +-passes_previously_accepted = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! --passes-see-issue = +-passes_see_issue = see issue #{$issue} for more information -passes-outer-crate-level-attr = +passes_outer_crate_level_attr = crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` -passes-inner-crate-level-attr = +passes_inner_crate_level_attr = crate-level attribute should be in the root module -passes-ignored-attr-with-macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs - .warn = {-passes-previously-accepted} - .note = {-passes-see-issue(issue: "80564")} +passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs + .warn = {-passes_previously_accepted} + .note = {-passes_see_issue(issue: "80564")} -passes-ignored-attr = `#[{$sym}]` is ignored on struct fields and match arms - .warn = {-passes-previously-accepted} - .note = {-passes-see-issue(issue: "80564")} +passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms + .warn = {-passes_previously_accepted} + .note = {-passes_see_issue(issue: "80564")} -passes-inline-ignored-function-prototype = `#[inline]` is ignored on function prototypes +passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes -passes-inline-ignored-constants = `#[inline]` is ignored on constants - .warn = {-passes-previously-accepted} - .note = {-passes-see-issue(issue: "65833")} +passes_inline_ignored_constants = `#[inline]` is ignored on constants + .warn = {-passes_previously_accepted} + .note = {-passes_see_issue(issue: "65833")} -passes-inline-not-fn-or-closure = attribute should be applied to function or closure +passes_inline_not_fn_or_closure = attribute should be applied to function or closure .label = not a function or closure -passes-no-coverage-ignored-function-prototype = `#[no_coverage]` is ignored on function prototypes +passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes -passes-no-coverage-propagate = +passes_no_coverage_propagate = `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly -passes-no-coverage-fn-defn = `#[no_coverage]` may only be applied to function definitions +passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions -passes-no-coverage-not-coverable = `#[no_coverage]` must be applied to coverable code +passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code .label = not coverable code -passes-should-be-applied-to-fn = attribute should be applied to a function definition +passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = not a function definition -passes-naked-tracked-caller = cannot use `#[track_caller]` with `#[naked]` +passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]` -passes-should-be-applied-to-struct-enum = attribute should be applied to a struct or enum +passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum .label = not a struct or enum -passes-should-be-applied-to-trait = attribute should be applied to a trait +passes_should_be_applied_to_trait = attribute should be applied to a trait .label = not a trait -passes-target-feature-on-statement = {passes-should-be-applied-to-fn} - .warn = {-passes-previously-accepted} - .label = {passes-should-be-applied-to-fn.label} +passes_target_feature_on_statement = {passes_should_be_applied_to_fn} + .warn = {-passes_previously_accepted} + .label = {passes_should_be_applied_to_fn.label} -passes-should-be-applied-to-static = attribute should be applied to a static +passes_should_be_applied_to_static = attribute should be applied to a static .label = not a static -passes-doc-expect-str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] +passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] -passes-doc-alias-empty = {$attr_str} attribute cannot have empty value +passes_doc_alias_empty = {$attr_str} attribute cannot have empty value -passes-doc-alias-bad-char = {$char_} character isn't allowed in {$attr_str} +passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} -passes-doc-alias-start-end = {$attr_str} cannot start or end with ' ' +passes_doc_alias_start_end = {$attr_str} cannot start or end with ' ' -passes-doc-alias-bad-location = {$attr_str} isn't allowed on {$location} +passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location} -passes-doc-alias-not-an-alias = {$attr_str} is the same as the item's name +passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name -passes-doc-alias-duplicated = doc alias is duplicated +passes_doc_alias_duplicated = doc alias is duplicated .label = first defined here -passes-doc-alias-not-string-literal = `#[doc(alias("a"))]` expects string literals +passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals -passes-doc-alias-malformed = +passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` -passes-doc-keyword-empty-mod = `#[doc(keyword = "...")]` should be used on empty modules +passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules -passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules +passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules -passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier +passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier -passes-doc-fake-variadic-not-valid = +passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity -passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks +passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks -passes-doc-inline-conflict-first = this attribute... -passes-doc-inline-conflict-second = ...conflicts with this attribute -passes-doc-inline-conflict = conflicting doc inlining attributes +passes_doc_inline_conflict_first = this attribute... +passes_doc_inline_conflict_second = ...conflicts with this attribute +passes_doc_inline_conflict = conflicting doc inlining attributes .help = remove one of the conflicting attributes -passes-doc-inline-only-use = this attribute can only be applied to a `use` item +passes_doc_inline_only_use = this attribute can only be applied to a `use` item .label = only applicable on `use` items - .not-a-use-item-label = not a `use` item + .not_a_use_item_label = not a `use` item .note = read for more information -passes-doc-attr-not-crate-level = +passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute -passes-attr-crate-level = this attribute can only be applied at the crate level +passes_attr_crate_level = this attribute can only be applied at the crate level .suggestion = to apply to the crate, use an inner attribute .help = to apply to the crate, use an inner attribute .note = read for more information -passes-doc-test-unknown = unknown `doc(test)` attribute `{$path}` +passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}` -passes-doc-test-takes-list = `#[doc(test(...)]` takes a list of attributes +passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes -passes-doc-primitive = `doc(primitive)` should never have been stable +passes_doc_primitive = `doc(primitive)` should never have been stable -passes-doc-test-unknown-any = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` -passes-doc-test-unknown-spotlight = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` .suggestion = use `notable_trait` instead - .no-op-note = `doc(spotlight)` is now a no-op + .no_op_note = `doc(spotlight)` is now a no-op -passes-doc-test-unknown-include = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_include = unknown `doc` attribute `{$path}` .suggestion = use `doc = include_str!` instead -passes-doc-invalid = invalid `doc` attribute +passes_doc_invalid = invalid `doc` attribute -passes-pass-by-value = `pass_by_value` attribute should be applied to a struct, enum or type alias +passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias .label = is not a struct, enum or type alias -passes-allow-incoherent-impl = +passes_allow_incoherent_impl = `rustc_allow_incoherent_impl` attribute should be applied to impl items. .label = the only currently supported targets are inherent methods -passes-has-incoherent-inherent-impl = +passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported -passes-must-use-async = +passes_must_use_async = `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` -passes-must-use-no-effect = `#[must_use]` has no effect when applied to {$article} {$target} +passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes-must-not-suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait +passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait .label = is not a struct, enum, or trait -passes-cold = {passes-should-be-applied-to-fn} - .warn = {-passes-previously-accepted} - .label = {passes-should-be-applied-to-fn.label} +passes_cold = {passes_should_be_applied_to_fn} + .warn = {-passes_previously_accepted} + .label = {passes_should_be_applied_to_fn.label} -passes-link = attribute should be applied to an `extern` block with non-Rust ABI - .warn = {-passes-previously-accepted} +passes_link = attribute should be applied to an `extern` block with non-Rust ABI + .warn = {-passes_previously_accepted} .label = not an `extern` block -passes-link-name = attribute should be applied to a foreign function or static - .warn = {-passes-previously-accepted} +passes_link_name = attribute should be applied to a foreign function or static + .warn = {-passes_previously_accepted} .label = not a foreign function or static .help = try `#[link(name = "{$value}")]` instead -passes-no-link = attribute should be applied to an `extern crate` item +passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item -passes-export-name = attribute should be applied to a free function, impl method or static +passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static -passes-rustc-layout-scalar-valid-range-not-struct = attribute should be applied to a struct +passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct .label = not a struct -passes-rustc-layout-scalar-valid-range-arg = expected exactly one integer literal argument +passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument -passes-rustc-legacy-const-generics-only = #[rustc_legacy_const_generics] functions must only have const generics +passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics .label = non-const generic parameter -passes-rustc-legacy-const-generics-index = #[rustc_legacy_const_generics] must have one index for each generic parameter +passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter .label = generic parameters -passes-rustc-legacy-const-generics-index-exceed = index exceeds number of arguments +passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments .label = there {$arg_count -> [one] is *[other] are @@ -181,84 +181,90 @@ passes-rustc-legacy-const-generics-index-exceed = index exceeds number of argume *[other] arguments } -passes-rustc-legacy-const-generics-index-negative = arguments should be non-negative integers +passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers -passes-rustc-dirty-clean = attribute requires -Z query-dep-graph to be enabled +passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled -passes-link-section = attribute should be applied to a function or static - .warn = {-passes-previously-accepted} +passes_link_section = attribute should be applied to a function or static + .warn = {-passes_previously_accepted} .label = not a function or static -passes-no-mangle-foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} - .warn = {-passes-previously-accepted} +passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} + .warn = {-passes_previously_accepted} .label = foreign {$foreign_item_kind} .note = symbol names in extern blocks are not mangled .suggestion = remove this attribute -passes-no-mangle = attribute should be applied to a free function, impl method or static - .warn = {-passes-previously-accepted} +passes_no_mangle = attribute should be applied to a free function, impl method or static + .warn = {-passes_previously_accepted} .label = not a free function, impl method or static -passes-repr-ident = meta item in `repr` must be an identifier +passes_repr_ident = meta item in `repr` must be an identifier -passes-repr-conflicting = conflicting representation hints +passes_repr_conflicting = conflicting representation hints -passes-used-static = attribute must be applied to a `static` variable +passes_used_static = attribute must be applied to a `static` variable -passes-used-compiler-linker = `used(compiler)` and `used(linker)` can't be used together +passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together -passes-allow-internal-unstable = attribute should be applied to a macro +passes_allow_internal_unstable = attribute should be applied to a macro .label = not a macro -passes-debug-visualizer-placement = attribute should be applied to a module +passes_debug_visualizer_placement = attribute should be applied to a module -passes-debug-visualizer-invalid = invalid argument - .note-1 = expected: `natvis_file = "..."` - .note-2 = OR - .note-3 = expected: `gdb_script_file = "..."` +passes_debug_visualizer_invalid = invalid argument + .note_1 = expected: `natvis_file = "..."` + .note_2 = OR + .note_3 = expected: `gdb_script_file = "..."` -passes-rustc-allow-const-fn-unstable = attribute should be applied to `const fn` +passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` -passes-rustc-std-internal-symbol = attribute should be applied to functions or statics +passes_rustc_std_internal_symbol = attribute should be applied to functions or statics .label = not a function or static -passes-const-trait = attribute should be applied to a trait +passes_const_trait = attribute should be applied to a trait -passes-stability-promotable = attribute cannot be applied to an expression +passes_stability_promotable = attribute cannot be applied to an expression -passes-deprecated = attribute is ignored here +passes_deprecated = attribute is ignored here -passes-macro-use = `#[{$name}]` only has an effect on `extern crate` and modules +passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules -passes-macro-export = `#[macro_export]` only has an effect on macro definitions +passes_macro_export = `#[macro_export]` only has an effect on macro definitions -passes-plugin-registrar = `#[plugin_registrar]` only has an effect on functions +passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions -passes-unused-empty-lints-note = attribute `{$name}` with an empty list has no effect +passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect -passes-unused-no-lints-note = attribute `{$name}` without any lints has no effect +passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect -passes-unused-default-method-body-const-note = +passes_unused_default_method_body_const_note = `default_method_body_is_const` has been replaced with `#[const_trait]` on traits -passes-unused = unused attribute +passes_unused = unused attribute .suggestion = remove this attribute -passes-non-exported-macro-invalid-attrs = attribute should be applied to function or closure +passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure .label = not a function or closure -passes-unused-duplicate = unused attribute +passes_unused_duplicate = unused attribute .suggestion = remove this attribute .note = attribute also specified here - .warn = {-passes-previously-accepted} + .warn = {-passes_previously_accepted} -passes-unused-multiple = multiple `{$name}` attributes +passes_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here -passes-rustc-lint-opt-ty = `#[rustc_lint_opt_ty]` should be applied to a struct +passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct .label = not a struct -passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field +passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field .label = not a field + +passes_link_ordinal = attribute should be applied to a foreign function or static + .label = not a foreign function or static + +passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions + .label = not a macro definition diff --git a/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl new file mode 100644 index 000000000..8db32a42c --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl @@ -0,0 +1,4 @@ +plugin_impl_load_plugin_error = {$msg} + +plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute + .label = malformed attribute diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl index f8a750da9..da987152f 100644 --- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -1,20 +1,22 @@ -privacy-field-is-private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private -privacy-field-is-private-is-update-syntax-label = field `{$field_name}` is private -privacy-field-is-private-label = private field +privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private +privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private +privacy_field_is_private_label = private field -privacy-item-is-private = {$kind} `{$descr}` is private +privacy_item_is_private = {$kind} `{$descr}` is private .label = private {$kind} -privacy-unnamed-item-is-private = {$kind} is private +privacy_unnamed_item_is_private = {$kind} is private .label = private {$kind} -privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface +privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interface .label = can't leak {$vis_descr} {$kind} - .visibility-label = `{$descr}` declared as {$vis_descr} + .visibility_label = `{$descr}` declared as {$vis_descr} -privacy-from-private-dep-in-public-interface = +privacy_report_access_level = {$descr} + +privacy_from_private_dep_in_public_interface = {$kind} `{$descr}` from private dependency '{$krate}' in public interface -private-in-public-lint = +privacy_private_in_public_lint = {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind -> [trait] E0445 *[other] E0446 diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl new file mode 100644 index 000000000..167704e46 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl @@ -0,0 +1,25 @@ +query_system_reentrant = internal compiler error: re-entrant incremental verify failure, suppressing message + +query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} + .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile + +query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information +query_system_increment_compilation_note2 = See for more information + +query_system_cycle = cycle detected when {$stack_bottom} + +query_system_cycle_usage = cycle used when {$usage} + +query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again + +query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle + +query_system_cycle_recursive_ty_alias = type aliases cannot be recursive +query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle +query_system_cycle_recursive_ty_alias_help2 = see for more information + +query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive + +query_system_cycle_which_requires = ...which requires {$desc}... + +query_system_query_overflow = queries overflow the depth limit! diff --git a/compiler/rustc_error_messages/locales/en-US/save_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/save_analysis.ftl new file mode 100644 index 000000000..36c2ff468 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/save_analysis.ftl @@ -0,0 +1 @@ +save_analysis_could_not_open = Could not open `{$file_name}`: `{$err}` diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl new file mode 100644 index 000000000..76cae3c81 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -0,0 +1,68 @@ +session_incorrect_cgu_reuse_type = + CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> + [one] {"at least "} + *[other] {""} + }`{$expected_reuse}` + +session_cgu_not_recorded = + CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded` + +session_feature_gate_error = {$explain} + +session_feature_diagnostic_for_issue = + see issue #{$n} for more information + +session_feature_diagnostic_help = + add `#![feature({$feature})]` to the crate attributes to enable + +session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. + +session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets + +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. + +session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` + +session_sanitizer_not_supported = {$us} sanitizer is not supported for this target + +session_sanitizers_not_supported = {$us} sanitizers are not supported for this target + +session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` + +session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto` + +session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` + +session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 + +session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err} + +session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err} + +session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout" + +session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err} + +session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}` + +session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}` + +session_target_invalid_bits_size = {$err} + +session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored + +session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform + +session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions + +session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}` + +session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen + +session_crate_name_empty = crate name must not be empty + +session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` diff --git a/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl b/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl new file mode 100644 index 000000000..b7d48280f --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl @@ -0,0 +1 @@ +symbol_mangling_test_output = {$kind}({$content}) diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl new file mode 100644 index 000000000..004e0ab18 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl @@ -0,0 +1,26 @@ +trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} + +trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} + +trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` + .label = deref recursion limit reached + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) + +trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty on-clause here + +trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` + .label = invalid on-clause here + +trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value + .label = expected value here + .note = eg `#[rustc_on_unimplemented(message="foo")]` + +trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> + [none] {""} + *[default] {" "}for type `{$self_desc}` + }: + .negative_implementation_here = negative implementation here + .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}` + .positive_implementation_here = positive implementation here + .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` diff --git a/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl new file mode 100644 index 000000000..1040ee1c9 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl @@ -0,0 +1,47 @@ +ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop + +ty_utils_generic_constant_too_complex = overly complex generic constant + .help = consider moving this anonymous constant into a `const` function + .maybe_supported = this operation may be supported in the future + +ty_utils_borrow_not_supported = borrowing is not supported in generic constants + +ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants + +ty_utils_array_not_supported = array construction is not supported in generic constants + +ty_utils_block_not_supported = blocks are not supported in generic constant + +ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constant + +ty_utils_tuple_not_supported = tuple construction is not supported in generic constants + +ty_utils_index_not_supported = indexing is not supported in generic constant + +ty_utils_field_not_supported = field access is not supported in generic constant + +ty_utils_const_block_not_supported = const blocks are not supported in generic constant + +ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants + +ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants + +ty_utils_yield_not_supported = generator control flow is not allowed in generic constants + +ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants + +ty_utils_box_not_supported = allocations are not allowed in generic constants + +ty_utils_binary_not_supported = unsupported binary operation in generic constants + +ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow + +ty_utils_assign_not_supported = assignment is not supported in generic constants + +ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants + +ty_utils_control_flow_not_supported = control flow is not supported in generic constants + +ty_utils_inline_asm_not_supported = assembly is not supported in generic constants + +ty_utils_operation_not_supported = unsupported operation in generic constant diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index c61735a57..272731d99 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -1,101 +1,101 @@ -typeck-field-multiply-specified-in-initializer = +typeck_field_multiply_specified_in_initializer = field `{$ident}` specified more than once .label = used more than once - .previous-use-label = first use of `{$ident}` + .previous_use_label = first use of `{$ident}` -typeck-unrecognized-atomic-operation = +typeck_unrecognized_atomic_operation = unrecognized atomic operation function: `{$op}` .label = unrecognized atomic operation -typeck-wrong-number-of-generic-arguments-to-intrinsic = +typeck_wrong_number_of_generic_arguments_to_intrinsic = intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} .label = expected {$expected} {$descr} {$expected -> [one] parameter *[other] parameters } -typeck-unrecognized-intrinsic-function = +typeck_unrecognized_intrinsic_function = unrecognized intrinsic function: `{$name}` .label = unrecognized intrinsic -typeck-lifetimes-or-bounds-mismatch-on-trait = +typeck_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait - .generics-label = lifetimes in impl do not match this {$item_kind} in trait + .generics_label = lifetimes in impl do not match this {$item_kind} in trait -typeck-drop-impl-on-wrong-item = - the `Drop` trait may only be implemented for structs, enums, and unions - .label = must be a struct, enum, or union +typeck_drop_impl_on_wrong_item = + the `Drop` trait may only be implemented for local structs, enums, and unions + .label = must be a struct, enum, or union in the current crate -typeck-field-already-declared = +typeck_field_already_declared = field `{$field_name}` is already declared .label = field already declared - .previous-decl-label = `{$field_name}` first declared here + .previous_decl_label = `{$field_name}` first declared here -typeck-copy-impl-on-type-with-dtor = +typeck_copy_impl_on_type_with_dtor = the trait `Copy` may not be implemented for this type; the type has a destructor .label = `Copy` not allowed on types with destructors -typeck-multiple-relaxed-default-bounds = +typeck_multiple_relaxed_default_bounds = type parameter has more than one relaxed default bound, only one is supported -typeck-copy-impl-on-non-adt = +typeck_copy_impl_on_non_adt = the trait `Copy` may not be implemented for this type .label = type is not a structure or enumeration -typeck-trait-object-declared-with-no-traits = +typeck_trait_object_declared_with_no_traits = at least one trait is required for an object type - .alias-span = this alias does not contain a trait + .alias_span = this alias does not contain a trait -typeck-ambiguous-lifetime-bound = +typeck_ambiguous_lifetime_bound = ambiguous lifetime bound, explicit lifetime bound required -typeck-assoc-type-binding-not-allowed = +typeck_assoc_type_binding_not_allowed = associated type bindings are not allowed here .label = associated type not allowed here -typeck-functional-record-update-on-non-struct = +typeck_functional_record_update_on_non_struct = functional record update syntax requires a struct -typeck-typeof-reserved-keyword-used = +typeck_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented .suggestion = consider replacing `typeof(...)` with an actual type .label = reserved keyword -typeck-return-stmt-outside-of-fn-body = +typeck_return_stmt_outside_of_fn_body = return statement outside of function body - .encl-body-label = the return is part of this body... - .encl-fn-label = ...not the enclosing function body + .encl_body_label = the return is part of this body... + .encl_fn_label = ...not the enclosing function body -typeck-yield-expr-outside-of-generator = +typeck_yield_expr_outside_of_generator = yield expression outside of generator literal -typeck-struct-expr-non-exhaustive = +typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression -typeck-method-call-on-unknown-type = +typeck_method_call_on_unknown_type = the type of this value must be known to call a method on a raw pointer on it -typeck-value-of-associated-struct-already-specified = +typeck_value_of_associated_struct_already_specified = the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified .label = re-bound here - .previous-bound-label = `{$item_name}` bound here first + .previous_bound_label = `{$item_name}` bound here first -typeck-address-of-temporary-taken = cannot take address of a temporary +typeck_address_of_temporary_taken = cannot take address of a temporary .label = temporary value -typeck-add-return-type-add = try adding a return type +typeck_add_return_type_add = try adding a return type -typeck-add-return-type-missing-here = a return type might be missing here +typeck_add_return_type_missing_here = a return type might be missing here -typeck-expected-default-return-type = expected `()` because of default return type +typeck_expected_default_return_type = expected `()` because of default return type -typeck-expected-return-type = expected `{$expected}` because of return type +typeck_expected_return_type = expected `{$expected}` because of return type -typeck-unconstrained-opaque-type = unconstrained opaque type +typeck_unconstrained_opaque_type = unconstrained opaque type .note = `{$name}` must be used in combination with a concrete type within the same module -typeck-missing-type-params = +typeck_missing_type_params = the type {$parameterCount -> [one] parameter *[other] parameters @@ -111,15 +111,25 @@ typeck-missing-type-params = [one] type *[other] types } - .no-suggestion-label = missing {$parameterCount -> + .no_suggestion_label = missing {$parameterCount -> [one] reference *[other] references } to {$parameters} .note = because of the default `Self` reference, type parameters must be specified on object types -typeck-manual-implementation = +typeck_manual_implementation = manual implementations of `{$trait_name}` are experimental .label = manual implementations of `{$trait_name}` are experimental .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable -typeck-substs-on-overridden-impl = could not resolve substs on overridden impl +typeck_substs_on_overridden_impl = could not resolve substs on overridden impl + +typeck_unused_extern_crate = + unused extern crate + .suggestion = remove it + +typeck_extern_crate_not_idiomatic = + `extern crate` is not idiomatic in the new edition + .suggestion = convert it to a `{$msg_code}` + +typeck_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 02bb04d98..b6e0f3faa 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -2,6 +2,11 @@ #![feature(once_cell)] #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + +#[macro_use] +extern crate tracing; use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; @@ -14,7 +19,6 @@ use std::fmt; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use tracing::{instrument, trace}; #[cfg(not(parallel_compiler))] use std::cell::LazyCell as Lazy; @@ -31,15 +35,32 @@ pub use unic_langid::{langid, LanguageIdentifier}; // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + ast_lowering => "../locales/en-US/ast_lowering.ftl", + ast_passes => "../locales/en-US/ast_passes.ftl", + attr => "../locales/en-US/attr.ftl", borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", const_eval => "../locales/en-US/const_eval.ftl", + driver => "../locales/en-US/driver.ftl", expand => "../locales/en-US/expand.ftl", + session => "../locales/en-US/session.ftl", + interface => "../locales/en-US/interface.ftl", + infer => "../locales/en-US/infer.ftl", lint => "../locales/en-US/lint.ftl", + middle => "../locales/en-US/middle.ftl", + monomorphize => "../locales/en-US/monomorphize.ftl", + metadata => "../locales/en-US/metadata.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", + plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", + query_system => "../locales/en-US/query_system.ftl", + trait_selection => "../locales/en-US/trait_selection.ftl", + save_analysis => "../locales/en-US/save_analysis.ftl", + ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", + mir_dataflow => "../locales/en-US/mir_dataflow.ftl", + symbol_mangling => "../locales/en-US/symbol_mangling.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 7d7e92c52..c36ca11fa 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -13,15 +13,16 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_target = { path = "../rustc_target" } rustc_hir = { path = "../rustc_hir" } rustc_lint_defs = { path = "../rustc_lint_defs" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" -annotate-snippets = "0.8.0" +annotate-snippets = "0.9" termize = "0.1.1" -serde = { version = "1.0.125", features = ["derive"] } +serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] } +winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 0fcd61d1e..b32fc3c71 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -7,6 +7,7 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; +use crate::translation::Translate; use crate::{ CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic, @@ -32,6 +33,16 @@ pub struct AnnotateSnippetEmitterWriter { macro_backtrace: bool, } +impl Translate for AnnotateSnippetEmitterWriter { + fn fluent_bundle(&self) -> Option<&Lrc> { + self.fluent_bundle.as_ref() + } + + fn fallback_fluent_bundle(&self) -> &FluentBundle { + &**self.fallback_bundle + } +} + impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, diag: &Diagnostic) { @@ -63,14 +74,6 @@ impl Emitter for AnnotateSnippetEmitterWriter { self.source_map.as_ref() } - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle - } - fn should_show_explain(&self) -> bool { !self.short_message } @@ -183,7 +186,11 @@ impl AnnotateSnippetEmitterWriter { annotation_type: annotation_type_for_level(*level), }), footer: vec![], - opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing }, + opt: FormatOptions { + color: true, + anonymized_line_numbers: self.ui_testing, + margin: None, + }, slices: annotated_files .iter() .map(|(source, line_index, annotations)| { diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 17e6c9e95..a774b52c8 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -8,11 +8,14 @@ use rustc_error_messages::FluentValue; use rustc_hir as hir; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::{edition::Edition, Span, DUMMY_SP}; +use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::num::ParseIntError; +use std::path::{Path, PathBuf}; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -83,10 +86,16 @@ into_diagnostic_arg_using_display!( u64, i128, u128, + std::io::Error, std::num::NonZeroU32, hir::Target, Edition, Ident, + MacroRulesNormalizedIdent, + ParseIntError, + StackProtector, + &TargetTriple, + SplitDebuginfo ); impl IntoDiagnosticArg for bool { @@ -123,12 +132,30 @@ impl IntoDiagnosticArg for String { } } +impl<'a> IntoDiagnosticArg for &'a Path { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + +impl IntoDiagnosticArg for PathBuf { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + impl IntoDiagnosticArg for usize { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Number(self) } } +impl IntoDiagnosticArg for PanicStrategy { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) + } +} + impl<'source> Into> for DiagnosticArgValue<'source> { fn into(self) -> FluentValue<'source> { match self { @@ -671,19 +698,12 @@ impl Diagnostic { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { - assert!(!suggestion.is_empty()); - self.push_suggestion(CodeSuggestion { - substitutions: vec![Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::CompletelyHidden, + self.multipart_suggestion_with_style( + msg, + suggestion, applicability, - }); - self + SuggestionStyle::CompletelyHidden, + ) } /// Prints out a message with a suggested edit of the code. @@ -966,12 +986,12 @@ impl Diagnostic { fn sub_with_highlights>( &mut self, level: Level, - mut message: Vec<(M, Style)>, + message: Vec<(M, Style)>, span: MultiSpan, render_span: Option, ) { let message = message - .drain(..) + .into_iter() .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) .collect(); let sub = SubDiagnostic { level, message, span, render_span }; diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 9e68ee282..7e29dc207 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -12,7 +12,6 @@ use std::fmt::{self, Debug}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::thread::panicking; -use tracing::debug; /// Used for emitting structured error messages and other diagnostic information. /// @@ -84,6 +83,13 @@ pub trait EmissionGuarantee: Sized { /// of `Self` without actually performing the emission. #[track_caller] fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self; + + /// Creates a new `DiagnosticBuilder` that will return this type of guarantee. + #[track_caller] + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self>; } /// Private module for sealing the `IsError` helper trait. @@ -166,6 +172,15 @@ impl EmissionGuarantee for ErrorGuaranteed { } } } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>( + handler, msg, + ) + } } impl<'a> DiagnosticBuilder<'a, ()> { @@ -208,6 +223,13 @@ impl EmissionGuarantee for () { DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} } } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new(handler, Level::Warning(None), msg) + } } impl<'a> DiagnosticBuilder<'a, !> { @@ -247,6 +269,13 @@ impl EmissionGuarantee for ! { // Then fatally error, returning `!` crate::FatalError.raise() } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_fatal(handler, msg) + } } /// In general, the `DiagnosticBuilder` uses deref to allow access to @@ -566,7 +595,7 @@ impl Drop for DiagnosticBuilderInner<'_> { ), )); handler.emit_diagnostic(&mut self.diagnostic); - panic!(); + panic!("error was constructed but not emitted"); } } // `.emit()` was previously called, or maybe we're during `.cancel()`. diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 61d953cd6..66fbb8f12 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -14,15 +14,15 @@ use rustc_span::{FileLines, SourceFile, Span}; use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; use crate::styled_buffer::StyledBuffer; +use crate::translation::Translate; use crate::{ - CodeSuggestion, Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticMessage, FluentBundle, - Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, - SuggestionStyle, + CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler, + LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle, }; use rustc_lint_defs::pluralize; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -34,7 +34,6 @@ use std::iter; use std::path::Path; use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; use termcolor::{Buffer, Color, WriteColor}; -use tracing::*; /// Default column width, used in tests and when terminal dimensions cannot be determined. const DEFAULT_COLUMN_WIDTH: usize = 140; @@ -200,7 +199,7 @@ impl Margin { const ANONYMIZED_LINE_NUM: &str = "LL"; /// Emitter trait for emitting errors. -pub trait Emitter { +pub trait Emitter: Translate { /// Emit a structured diagnostic. fn emit_diagnostic(&mut self, diag: &Diagnostic); @@ -231,84 +230,6 @@ pub trait Emitter { fn source_map(&self) -> Option<&Lrc>; - /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no - /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` - /// should be used. - fn fluent_bundle(&self) -> Option<&Lrc>; - - /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. - /// Used when the user has not requested a specific language or when a localized diagnostic is - /// unavailable for the requested locale. - fn fallback_fluent_bundle(&self) -> &FluentBundle; - - /// Convert diagnostic arguments (a rustc internal type that exists to implement - /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. - /// - /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then - /// passed around as a reference thereafter. - fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> { - FromIterator::from_iter(args.to_vec().drain(..)) - } - - /// Convert `DiagnosticMessage`s to a string, performing translation if necessary. - fn translate_messages( - &self, - messages: &[(DiagnosticMessage, Style)], - args: &FluentArgs<'_>, - ) -> Cow<'_, str> { - Cow::Owned( - messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::(), - ) - } - - /// Convert a `DiagnosticMessage` to a string, performing translation if necessary. - fn translate_message<'a>( - &'a self, - message: &'a DiagnosticMessage, - args: &'a FluentArgs<'_>, - ) -> Cow<'_, str> { - trace!(?message, ?args); - let (identifier, attr) = match message { - DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg), - DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), - }; - - let bundle = match self.fluent_bundle() { - Some(bundle) if bundle.has_message(&identifier) => bundle, - _ => self.fallback_fluent_bundle(), - }; - - let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle"); - let value = match attr { - Some(attr) => { - if let Some(attr) = message.get_attribute(attr) { - attr.value() - } else { - panic!("missing attribute `{attr}` in fluent message `{identifier}`") - } - } - None => { - if let Some(value) = message.value() { - value - } else { - panic!("missing value in fluent message `{identifier}`") - } - } - }; - - let mut err = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut err); - trace!(?translated, ?err); - debug_assert!( - err.is_empty(), - "identifier: {:?}, args: {:?}, errors: {:?}", - identifier, - args, - err - ); - translated - } - /// Formats the substitutions of the primary_span /// /// There are a lot of conditions to this method, but in short: @@ -598,11 +519,7 @@ pub trait Emitter { } } -impl Emitter for EmitterWriter { - fn source_map(&self) -> Option<&Lrc> { - self.sm.as_ref() - } - +impl Translate for EmitterWriter { fn fluent_bundle(&self) -> Option<&Lrc> { self.fluent_bundle.as_ref() } @@ -610,6 +527,12 @@ impl Emitter for EmitterWriter { fn fallback_fluent_bundle(&self) -> &FluentBundle { &**self.fallback_bundle } +} + +impl Emitter for EmitterWriter { + fn source_map(&self) -> Option<&Lrc> { + self.sm.as_ref() + } fn emit_diagnostic(&mut self, diag: &Diagnostic) { let fluent_args = self.to_fluent_args(diag.args()); @@ -654,11 +577,7 @@ pub struct SilentEmitter { pub fatal_note: Option, } -impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { - None - } - +impl Translate for SilentEmitter { fn fluent_bundle(&self) -> Option<&Lrc> { None } @@ -666,6 +585,12 @@ impl Emitter for SilentEmitter { fn fallback_fluent_bundle(&self) -> &FluentBundle { panic!("silent emitter attempted to translate message") } +} + +impl Emitter for SilentEmitter { + fn source_map(&self) -> Option<&Lrc> { + None + } fn emit_diagnostic(&mut self, d: &Diagnostic) { if d.level == Level::Fatal { @@ -1562,7 +1487,7 @@ impl EmitterWriter { ); // Contains the vertical lines' positions for active multiline annotations - let mut multilines = FxHashMap::default(); + let mut multilines = FxIndexMap::default(); // Get the left-side margin to remove it let mut whitespace_margin = usize::MAX; @@ -1779,7 +1704,7 @@ impl EmitterWriter { { notice_capitalization |= only_capitalization; - let has_deletion = parts.iter().any(|p| p.is_deletion()); + let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); let is_multiline = complete.lines().count() > 1; if let Some(span) = span.primary_span() { @@ -1955,16 +1880,23 @@ impl EmitterWriter { let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; + // If this addition is _only_ whitespace, then don't trim it, + // or else we're just not rendering anything. + let is_whitespace_addition = part.snippet.trim().is_empty(); + // Do not underline the leading... - let start = part.snippet.len().saturating_sub(part.snippet.trim_start().len()); + let start = if is_whitespace_addition { + 0 + } else { + part.snippet.len().saturating_sub(part.snippet.trim_start().len()) + }; // ...or trailing spaces. Account for substitutions containing unicode // characters. - let sub_len: usize = part - .snippet - .trim() - .chars() - .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) - .sum(); + let sub_len: usize = + if is_whitespace_addition { &part.snippet } else { part.snippet.trim() } + .chars() + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum(); let offset: isize = offsets .iter() @@ -2205,7 +2137,7 @@ impl EmitterWriter { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum DisplaySuggestion { Underline, Diff, diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index b8cd334b4..1680c6acc 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -13,6 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use crate::emitter::{Emitter, HumanReadableErrorType}; use crate::registry::Registry; +use crate::translation::Translate; use crate::DiagnosticId; use crate::{ CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic, @@ -122,6 +123,16 @@ impl JsonEmitter { } } +impl Translate for JsonEmitter { + fn fluent_bundle(&self) -> Option<&Lrc> { + self.fluent_bundle.as_ref() + } + + fn fallback_fluent_bundle(&self) -> &FluentBundle { + &**self.fallback_bundle + } +} + impl Emitter for JsonEmitter { fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) { let data = Diagnostic::from_errors_diagnostic(diag, self); @@ -189,14 +200,6 @@ impl Emitter for JsonEmitter { Some(&self.sm) } - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle - } - fn should_show_explain(&self) -> bool { !matches!(self.json_rendered, HumanReadableErrorType::Short(_)) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2409c0b5a..a7b01feeb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -4,15 +4,14 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(drain_filter)] -#![feature(backtrace)] #![feature(if_let_guard)] +#![feature(adt_const_params)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] -#![feature(adt_const_params)] +#![feature(result_option_inspect)] #![feature(rustc_attrs)] #![allow(incomplete_features)] -#![allow(rustc::potential_query_instability)] #[macro_use] extern crate rustc_macros; @@ -27,7 +26,7 @@ use Level::*; use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; @@ -59,6 +58,7 @@ mod lock; pub mod registry; mod snippet; mod styled_buffer; +pub mod translation; pub use snippet::Style; @@ -68,8 +68,8 @@ pub type PResult<'a, T> = Result>; // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.) #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))] +rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { @@ -150,21 +150,20 @@ pub struct SubstitutionHighlight { impl SubstitutionPart { pub fn is_addition(&self, sm: &SourceMap) -> bool { - !self.snippet.is_empty() - && sm - .span_to_snippet(self.span) - .map_or(self.span.is_empty(), |snippet| snippet.trim().is_empty()) + !self.snippet.is_empty() && !self.replaces_meaningful_content(sm) } - pub fn is_deletion(&self) -> bool { - self.snippet.trim().is_empty() + pub fn is_deletion(&self, sm: &SourceMap) -> bool { + self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm) } pub fn is_replacement(&self, sm: &SourceMap) -> bool { - !self.snippet.is_empty() - && sm - .span_to_snippet(self.span) - .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) + !self.snippet.is_empty() && self.replaces_meaningful_content(sm) + } + + fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool { + sm.span_to_snippet(self.span) + .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) } } @@ -412,7 +411,7 @@ struct HandlerInner { taught_diagnostics: FxHashSet, /// Used to suggest rustc --explain - emitted_diagnostic_codes: FxHashSet, + emitted_diagnostic_codes: FxIndexSet, /// This set contains a hash of every diagnostic that has been emitted by /// this handler. These hashes is used to avoid emitting the same error @@ -455,9 +454,11 @@ struct HandlerInner { } /// A key denoting where from a diagnostic was stashed. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum StashKey { ItemNoType, + UnderscoreForArrayLengths, + EarlySyntaxWarning, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -625,19 +626,17 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { let mut inner = self.inner.borrow_mut(); - // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic - // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. - // See the PR for a discussion. - inner.stashed_diagnostics.insert((span, key), diag); + inner.stash((span, key), diag); } /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key. pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option> { - self.inner - .borrow_mut() - .stashed_diagnostics - .remove(&(span, key)) - .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + let mut inner = self.inner.borrow_mut(); + inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + } + + pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool { + self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some() } /// Emit all stashed diagnostics. @@ -645,6 +644,15 @@ impl Handler { self.inner.borrow_mut().emit_stashed_diagnostics() } + /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`. + #[rustc_lint_diagnostics] + pub fn struct_diagnostic( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, G> { + G::make_diagnostic_builder(self, msg) + } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// /// Attempting to `.emit()` the builder will only emit if either: @@ -1105,13 +1113,31 @@ impl HandlerInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option { + let has_errors = self.has_errors(); let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); let mut reported = None; for mut diag in diags { + // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - reported = Some(ErrorGuaranteed(())); + if matches!(diag.level, Level::Error { lint: true }) { + self.lint_err_count -= 1; + } else { + self.err_count -= 1; + } + } else { + if diag.is_force_warn() { + self.warn_count -= 1; + } else { + // Unless they're forced, don't flush stashed warnings when + // there are errors, to avoid causing warning overload. The + // stash would've been stolen already if it were important. + if has_errors { + continue; + } + } } - self.emit_diagnostic(&mut diag); + let reported_this = self.emit_diagnostic(&mut diag); + reported = reported.or(reported_this); } reported } @@ -1225,9 +1251,13 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags - .treat_err_as_bug - .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get()) + self.flags.treat_err_as_bug.map_or(false, |c| { + self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get() + }) + } + + fn delayed_bug_count(&self) -> usize { + self.delayed_span_bugs.len() + self.delayed_good_path_bugs.len() } fn print_error_count(&mut self, registry: &Registry) { @@ -1301,9 +1331,47 @@ impl HandlerInner { } } + fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) { + // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug + // yet; that happens when we actually emit the diagnostic. + if diagnostic.is_error() { + if matches!(diagnostic.level, Level::Error { lint: true }) { + self.lint_err_count += 1; + } else { + self.err_count += 1; + } + } else { + // Warnings are only automatically flushed if they're forced. + if diagnostic.is_force_warn() { + self.warn_count += 1; + } + } + + // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic + // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. + // See the PR for a discussion. + self.stashed_diagnostics.insert(key, diagnostic); + } + + fn steal(&mut self, key: (Span, StashKey)) -> Option { + let diagnostic = self.stashed_diagnostics.remove(&key)?; + if diagnostic.is_error() { + if matches!(diagnostic.level, Level::Error { lint: true }) { + self.lint_err_count -= 1; + } else { + self.err_count -= 1; + } + } else { + if diagnostic.is_force_warn() { + self.warn_count -= 1; + } + } + Some(diagnostic) + } + #[inline] fn err_count(&self) -> usize { - self.err_count + self.stashed_diagnostics.len() + self.err_count } fn has_errors(&self) -> bool { @@ -1345,7 +1413,9 @@ impl HandlerInner { // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) { + if self.flags.treat_err_as_bug.map_or(false, |c| { + self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get() + }) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } @@ -1445,14 +1515,24 @@ impl HandlerInner { if self.treat_err_as_bug() { match ( self.err_count() + self.lint_err_count, + self.delayed_bug_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), ) { - (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), - (0 | 1, _) => {} - (count, as_bug) => panic!( - "aborting after {} errors due to `-Z treat-err-as-bug={}`", - count, as_bug, - ), + (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), + (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"), + (count, delayed_count, as_bug) => { + if delayed_count > 0 { + panic!( + "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`", + count, delayed_count, as_bug, + ) + } else { + panic!( + "aborting after {} errors due to `-Z treat-err-as-bug={}`", + count, as_bug, + ) + } + } } } } diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs new file mode 100644 index 000000000..4f407badb --- /dev/null +++ b/compiler/rustc_errors/src/translation.rs @@ -0,0 +1,103 @@ +use crate::snippet::Style; +use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle}; +use rustc_data_structures::sync::Lrc; +use rustc_error_messages::FluentArgs; +use std::borrow::Cow; + +pub trait Translate { + /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no + /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` + /// should be used. + fn fluent_bundle(&self) -> Option<&Lrc>; + + /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. + /// Used when the user has not requested a specific language or when a localized diagnostic is + /// unavailable for the requested locale. + fn fallback_fluent_bundle(&self) -> &FluentBundle; + + /// Convert diagnostic arguments (a rustc internal type that exists to implement + /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. + /// + /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then + /// passed around as a reference thereafter. + fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> { + FromIterator::from_iter(args.iter().cloned()) + } + + /// Convert `DiagnosticMessage`s to a string, performing translation if necessary. + fn translate_messages( + &self, + messages: &[(DiagnosticMessage, Style)], + args: &FluentArgs<'_>, + ) -> Cow<'_, str> { + Cow::Owned( + messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::(), + ) + } + + /// Convert a `DiagnosticMessage` to a string, performing translation if necessary. + fn translate_message<'a>( + &'a self, + message: &'a DiagnosticMessage, + args: &'a FluentArgs<'_>, + ) -> Cow<'_, str> { + trace!(?message, ?args); + let (identifier, attr) = match message { + DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg), + DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), + }; + + let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> { + let message = bundle.get_message(&identifier)?; + let value = match attr { + Some(attr) => message.get_attribute(attr)?.value(), + None => message.value()?, + }; + debug!(?message, ?value); + + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(&args), &mut errs); + debug!(?translated, ?errs); + Some((translated, errs)) + }; + + self.fluent_bundle() + .and_then(|bundle| translate_with_bundle(bundle)) + // If `translate_with_bundle` returns `None` with the primary bundle, this is likely + // just that the primary bundle doesn't contain the message being translated, so + // proceed to the fallback bundle. + // + // However, when errors are produced from translation, then that means the translation + // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided). + // + // In debug builds, assert so that compiler devs can spot the broken translation and + // fix it.. + .inspect(|(_, errs)| { + debug_assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + }) + // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so + // just hide it and try with the fallback bundle. + .filter(|(_, errs)| errs.is_empty()) + .or_else(|| translate_with_bundle(self.fallback_fluent_bundle())) + .map(|(translated, errs)| { + // Always bail out for errors with the fallback bundle. + assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + translated + }) + .expect("failed to find message in primary or fallback fluent bundles") + } +} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 6e093811f..e1da3ecde 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -6,7 +6,7 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Nonterminal}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::sync::{self, Lrc}; @@ -71,7 +71,7 @@ impl Annotatable { } } - pub fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + pub fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { match self { Annotatable::Item(item) => item.visit_attrs(f), Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f), @@ -693,10 +693,6 @@ pub struct SyntaxExtension { pub span: Span, /// List of unstable features that are treated as stable inside this macro. pub allow_internal_unstable: Option>, - /// Suppresses the `unsafe_code` lint for code produced by this macro. - pub allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. - pub local_inner_macros: bool, /// The macro's stability info. pub stability: Option, /// The macro's deprecation info. @@ -708,6 +704,13 @@ pub struct SyntaxExtension { /// Built-in macros have a couple of special properties like availability /// in `#[no_implicit_prelude]` modules, so we have to keep this flag. pub builtin_name: Option, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other + /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? + pub collapse_debuginfo: bool, } impl SyntaxExtension { @@ -729,14 +732,15 @@ impl SyntaxExtension { SyntaxExtension { span: DUMMY_SP, allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, stability: None, deprecation: None, helper_attrs: Vec::new(), edition, builtin_name: None, kind, + allow_internal_unsafe: false, + local_inner_macros: false, + collapse_debuginfo: false, } } @@ -754,12 +758,13 @@ impl SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs).collect::>(); - let mut local_inner_macros = false; - if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); - } - } + let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe); + let local_inner_macros = sess + .find_by_name(attrs, sym::macro_export) + .and_then(|macro_export| macro_export.meta_item_list()) + .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros)); + let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo); + tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); let (builtin_name, helper_attrs) = sess .find_by_name(attrs, sym::rustc_builtin_macro) @@ -772,7 +777,7 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - let (stability, const_stability) = attr::find_stability(&sess, attrs, span); + let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span); if let Some((_, sp)) = const_stability { sess.parse_sess .span_diagnostic @@ -784,19 +789,31 @@ impl SyntaxExtension { ) .emit(); } + if let Some((_, sp)) = body_stability { + sess.parse_sess + .span_diagnostic + .struct_span_err(sp, "macros cannot have body stability attributes") + .span_label(sp, "invalid body stability attribute") + .span_label( + sess.source_map().guess_head_span(span), + "body stability attribute affects this macro", + ) + .emit(); + } SyntaxExtension { kind, span, allow_internal_unstable: (!allow_internal_unstable.is_empty()) .then(|| allow_internal_unstable.into()), - allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe), - local_inner_macros, stability: stability.map(|(s, _)| s), deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d), helper_attrs, edition, builtin_name, + allow_internal_unsafe, + local_inner_macros, + collapse_debuginfo, } } @@ -841,11 +858,12 @@ impl SyntaxExtension { call_site, self.span, self.allow_internal_unstable.clone(), - self.allow_internal_unsafe, - self.local_inner_macros, self.edition, macro_def_id, parent_module, + self.allow_internal_unsafe, + self.local_inner_macros, + self.collapse_debuginfo, ) } } @@ -1216,7 +1234,7 @@ pub fn expr_to_spanned_string<'a>( ); Some((err, true)) } - ast::LitKind::Err(_) => None, + ast::LitKind::Err => None, _ => Some((cx.struct_span_err(l.span, err_msg), false)), }, ast::ExprKind::Err => None, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index fa3e2a4a5..50d2be3ce 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,6 +3,7 @@ use crate::base::ExtCtxt; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp}; +use rustc_data_structures::sync::Lrc; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -106,14 +107,13 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, ident: Ident, - attrs: Vec, bounds: ast::GenericBounds, default: Option>, ) -> ast::GenericParam { ast::GenericParam { ident: ident.with_span_pos(span), id: ast::DUMMY_NODE_ID, - attrs: attrs.into(), + attrs: AttrVec::new(), bounds, kind: ast::GenericParamKind::Type { default }, is_placeholder: false, @@ -178,8 +178,7 @@ impl<'a> ExtCtxt<'a> { ex: P, ) -> ast::Stmt { let pat = if mutbl { - let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut); - self.pat_ident_binding_mode(sp, ident, binding_mode) + self.pat_ident_binding_mode(sp, ident, ast::BindingAnnotation::MUT) } else { self.pat_ident(sp, ident) }; @@ -330,23 +329,38 @@ impl<'a> ExtCtxt<'a> { self.expr_struct(span, self.path_ident(span, id), fields) } - pub fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P { + fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P { let lit = ast::Lit::from_lit_kind(lit_kind, span); self.expr(span, ast::ExprKind::Lit(lit)) } + pub fn expr_usize(&self, span: Span, i: usize) -> P { self.expr_lit( span, ast::LitKind::Int(i as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)), ) } + pub fn expr_u32(&self, sp: Span, u: u32) -> P { self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U32))) } + pub fn expr_bool(&self, sp: Span, value: bool) -> P { self.expr_lit(sp, ast::LitKind::Bool(value)) } + pub fn expr_str(&self, sp: Span, s: Symbol) -> P { + self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked)) + } + + pub fn expr_char(&self, sp: Span, ch: char) -> P { + self.expr_lit(sp, ast::LitKind::Char(ch)) + } + + pub fn expr_byte_str(&self, sp: Span, bytes: Vec) -> P { + self.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(bytes))) + } + /// `[expr1, expr2, ...]` pub fn expr_array(&self, sp: Span, exprs: Vec>) -> P { self.expr(sp, ast::ExprKind::Array(exprs)) @@ -357,10 +371,6 @@ impl<'a> ExtCtxt<'a> { self.expr_addr_of(sp, self.expr_array(sp, exprs)) } - pub fn expr_str(&self, sp: Span, s: Symbol) -> P { - self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked)) - } - pub fn expr_cast(&self, sp: Span, expr: P, ty: P) -> P { self.expr(sp, ast::ExprKind::Cast(expr, ty)) } @@ -434,17 +444,16 @@ impl<'a> ExtCtxt<'a> { self.pat(span, PatKind::Lit(expr)) } pub fn pat_ident(&self, span: Span, ident: Ident) -> P { - let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Not); - self.pat_ident_binding_mode(span, ident, binding_mode) + self.pat_ident_binding_mode(span, ident, ast::BindingAnnotation::NONE) } pub fn pat_ident_binding_mode( &self, span: Span, ident: Ident, - bm: ast::BindingMode, + ann: ast::BindingAnnotation, ) -> P { - let pat = PatKind::Ident(bm, ident.with_span_pos(span), None); + let pat = PatKind::Ident(ann, ident.with_span_pos(span), None); self.pat(span, pat) } pub fn pat_path(&self, span: Span, path: ast::Path) -> P { @@ -564,7 +573,7 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, name: Ident, - attrs: Vec, + attrs: ast::AttrVec, kind: ast::ItemKind, ) -> P { // FIXME: Would be nice if our generated code didn't violate @@ -592,7 +601,7 @@ impl<'a> ExtCtxt<'a> { mutbl: ast::Mutability, expr: P, ) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) + self.item(span, name, AttrVec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) } pub fn item_const( @@ -603,11 +612,11 @@ impl<'a> ExtCtxt<'a> { expr: P, ) -> P { let def = ast::Defaultness::Final; - self.item(span, name, Vec::new(), ast::ItemKind::Const(def, ty, Some(expr))) + self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr))) } pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { - attr::mk_attr_outer(mi) + attr::mk_attr_outer(&self.sess.parse_sess.attr_id_generator, mi) } pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 3e1acf438..8d4e36407 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -2,9 +2,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree}; use rustc_ast::tokenstream::{DelimSpan, Spacing}; -use rustc_ast::tokenstream::{LazyTokenStream, TokenTree}; +use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree}; use rustc_ast::NodeId; use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem}; use rustc_attr as attr; @@ -215,7 +215,7 @@ pub fn features( let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) { None => { // The entire crate is unconfigured. - krate.attrs = Vec::new(); + krate.attrs = ast::AttrVec::new(); krate.items = Vec::new(); Features::default() } @@ -259,27 +259,27 @@ impl<'a> StripUnconfigured<'a> { fn try_configure_tokens(&self, node: &mut T) { if self.config_tokens { if let Some(Some(tokens)) = node.tokens_mut() { - let attr_annotated_tokens = tokens.create_token_stream(); - *tokens = LazyTokenStream::new(self.configure_tokens(&attr_annotated_tokens)); + let attr_stream = tokens.to_attr_token_stream(); + *tokens = LazyAttrTokenStream::new(self.configure_tokens(&attr_stream)); } } } - fn configure_krate_attrs(&self, mut attrs: Vec) -> Option> { + fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); if self.in_cfg(&attrs) { Some(attrs) } else { None } } - /// Performs cfg-expansion on `stream`, producing a new `AttrAnnotatedTokenStream`. + /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`. /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method - fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { - fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool { - stream.0.iter().all(|(tree, _spacing)| match tree { - AttrAnnotatedTokenTree::Attributes(_) => false, - AttrAnnotatedTokenTree::Token(_) => true, - AttrAnnotatedTokenTree::Delimited(_, _, inner) => can_skip(inner), + fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream { + fn can_skip(stream: &AttrTokenStream) -> bool { + stream.0.iter().all(|tree| match tree { + AttrTokenTree::Attributes(_) => false, + AttrTokenTree::Token(..) => true, + AttrTokenTree::Delimited(_, _, inner) => can_skip(inner), }) } @@ -290,38 +290,36 @@ impl<'a> StripUnconfigured<'a> { let trees: Vec<_> = stream .0 .iter() - .flat_map(|(tree, spacing)| match tree.clone() { - AttrAnnotatedTokenTree::Attributes(mut data) => { - let mut attrs: Vec<_> = std::mem::take(&mut data.attrs).into(); - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - data.attrs = attrs.into(); + .flat_map(|tree| match tree.clone() { + AttrTokenTree::Attributes(mut data) => { + data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); if self.in_cfg(&data.attrs) { - data.tokens = LazyTokenStream::new( - self.configure_tokens(&data.tokens.create_token_stream()), + data.tokens = LazyAttrTokenStream::new( + self.configure_tokens(&data.tokens.to_attr_token_stream()), ); - Some((AttrAnnotatedTokenTree::Attributes(data), *spacing)).into_iter() + Some(AttrTokenTree::Attributes(data)).into_iter() } else { None.into_iter() } } - AttrAnnotatedTokenTree::Delimited(sp, delim, mut inner) => { + AttrTokenTree::Delimited(sp, delim, mut inner) => { inner = self.configure_tokens(&inner); - Some((AttrAnnotatedTokenTree::Delimited(sp, delim, inner), *spacing)) + Some(AttrTokenTree::Delimited(sp, delim, inner)) .into_iter() } - AttrAnnotatedTokenTree::Token(ref token) if let TokenKind::Interpolated(ref nt) = token.kind => { + AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => { panic!( "Nonterminal should have been flattened at {:?}: {:?}", token.span, nt ); } - AttrAnnotatedTokenTree::Token(token) => { - Some((AttrAnnotatedTokenTree::Token(token), *spacing)).into_iter() + AttrTokenTree::Token(token, spacing) => { + Some(AttrTokenTree::Token(token, spacing)).into_iter() } }) .collect(); - AttrAnnotatedTokenStream::new(trees) + AttrTokenStream::new(trees) } /// Parse and expand all `cfg_attr` attributes into a list of attributes @@ -390,7 +388,7 @@ impl<'a> StripUnconfigured<'a> { attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.tokens().to_tokenstream(); + let orig_tokens = attr.tokens(); // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We @@ -406,27 +404,33 @@ impl<'a> StripUnconfigured<'a> { }; let pound_span = pound_token.span; - let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)]; + let mut trees = vec![AttrTokenTree::Token(pound_token, Spacing::Alone)]; if attr.style == AttrStyle::Inner { // For inner attributes, we do the same thing for the `!` in `#![some_attr]` let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = orig_trees.next().unwrap() else { panic!("Bad tokens for attribute {:?}", attr); }; - trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone)); + trees.push(AttrTokenTree::Token(bang_token, Spacing::Alone)); } // We don't really have a good span to use for the synthesized `[]` // in `#[attr]`, so just use the span of the `#` token. - let bracket_group = AttrAnnotatedTokenTree::Delimited( + let bracket_group = AttrTokenTree::Delimited( DelimSpan::from_single(pound_span), Delimiter::Bracket, item.tokens .as_ref() .unwrap_or_else(|| panic!("Missing tokens for {:?}", item)) - .create_token_stream(), + .to_attr_token_stream(), + ); + trees.push(bracket_group); + let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees))); + let attr = attr::mk_attr_from_item( + &self.sess.parse_sess.attr_id_generator, + item, + tokens, + attr.style, + item_span, ); - trees.push((bracket_group, Spacing::Alone)); - let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees))); - let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span); if attr.has_name(sym::crate_type) { self.sess.parse_sess.buffer_lint( rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs new file mode 100644 index 000000000..0feae0deb --- /dev/null +++ b/compiler/rustc_expand/src/errors.rs @@ -0,0 +1,48 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::symbol::MacroRulesNormalizedIdent; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(expand::expr_repeat_no_syntax_vars)] +pub(crate) struct NoSyntaxVarsExprRepeat { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(expand::must_repeat_once)] +pub(crate) struct MustRepeatOnce { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(expand::count_repetition_misplaced)] +pub(crate) struct CountRepetitionMisplaced { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(expand::meta_var_expr_unrecognized_var)] +pub(crate) struct MetaVarExprUnrecognizedVar { + #[primary_span] + pub span: Span, + pub key: MacroRulesNormalizedIdent, +} + +#[derive(SessionDiagnostic)] +#[diag(expand::var_still_repeating)] +pub(crate) struct VarStillRepeating { + #[primary_span] + pub span: Span, + pub ident: MacroRulesNormalizedIdent, +} + +#[derive(SessionDiagnostic)] +#[diag(expand::meta_var_dif_seq_matchers)] +pub(crate) struct MetaVarsDifSeqMatchers { + #[primary_span] + pub span: Span, + pub msg: String, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 93eeca5b2..c2add852a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,7 +11,7 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, ExprKind, ForeignItemKind}; +use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, AttrVec, ExprKind, ForeignItemKind}; use rustc_ast::{HasAttrs, HasNodeId}; use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind}; use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}; @@ -306,7 +306,7 @@ pub struct Invocation { pub enum InvocationKind { Bang { - mac: ast::MacCall, + mac: P, span: Span, }, Attr { @@ -1001,7 +1001,7 @@ enum AddSemicolon { /// of functionality used by `InvocationCollector`. trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { type OutputTy = SmallVec<[Self; 1]>; - type AttrsTy: Deref = Vec; + type AttrsTy: Deref = ast::AttrVec; const KIND: AstFragmentKind; fn to_annotatable(self) -> Annotatable; fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; @@ -1017,7 +1017,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn is_mac_call(&self) -> bool { false } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { unreachable!() } fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {} @@ -1046,7 +1046,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1154,7 +1154,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1179,7 +1179,7 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1202,7 +1202,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1323,7 +1323,7 @@ impl InvocationCollectorNode for ast::Stmt { StmtKind::Local(..) | StmtKind::Empty => false, } } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { // We pull macro invocations (both attributes and fn-like macro calls) out of their // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { @@ -1333,7 +1333,7 @@ impl InvocationCollectorNode for ast::Stmt { } StmtKind::Item(item) => match item.into_inner() { ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { - (mac.args.need_semicolon(), mac, attrs.into()) + (mac.args.need_semicolon(), mac, attrs) } _ => unreachable!(), }, @@ -1387,10 +1387,10 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } } @@ -1411,10 +1411,10 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } } @@ -1439,7 +1439,7 @@ impl InvocationCollectorNode for P { fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1466,7 +1466,7 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) { let node = self.wrapped.into_inner(); match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1512,7 +1512,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) } - fn collect_bang(&mut self, mac: ast::MacCall, kind: AstFragmentKind) -> AstFragment { + fn collect_bang(&mut self, mac: P, kind: AstFragmentKind) -> AstFragment { // cache the macro call span so that it can be // easily adjusted for incremental compilation let span = mac.span(); @@ -1646,7 +1646,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { - attrs.splice(pos..pos, self.cfg().expand_cfg_attr(attr, false)); + // Repeated `insert` calls is inefficient, but the number of + // insertions is almost always 0 or 1 in practice. + for cfg in self.cfg().expand_cfg_attr(attr, false).into_iter().rev() { + attrs.insert(pos, cfg) + } }); } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 9d0232822..ffc9abe64 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -3,7 +3,7 @@ #![feature(associated_type_defaults)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(macro_metavar_expr)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] @@ -15,6 +15,9 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + extern crate proc_macro as pm; mod placeholders; @@ -26,6 +29,7 @@ pub mod base; pub mod build; #[macro_use] pub mod config; +pub mod errors; pub mod expand; pub mod module; pub mod proc_macro; diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 4fa91dfea..c8bdc3931 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -430,7 +430,7 @@ impl TtParser { } } MatcherLoc::Delimited => { - // Entering the delimeter is trivial. + // Entering the delimiter is trivial. mp.idx += 1; self.cur_mps.push(mp); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f7e1575af..7764ffd24 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -32,7 +32,6 @@ use rustc_span::Span; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::{mem, slice}; -use tracing::debug; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -608,11 +607,7 @@ enum ExplainDocComment { }, } -fn annotate_doc_comment( - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - sm: &SourceMap, - span: Span, -) { +fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { err.subdiagnostic(ExplainDocComment::Outer { span }); @@ -980,7 +975,7 @@ impl<'tt> TokenSet<'tt> { self.maybe_empty = false; } - // Adds `tok` to the set for `self`, marking sequence as non-empy. + // Adds `tok` to the set for `self`, marking sequence as non-empty. fn add_one(&mut self, tt: TtHandle<'tt>) { if !self.tokens.contains(&tt) { self.tokens.push(tt); diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index fc808401a..99fe47454 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -112,7 +112,7 @@ fn parse_depth<'sess>( "meta-variable expression depth must be a literal" )); }; - if let Ok(lit_kind) = LitKind::from_lit_token(*lit) + if let Ok(lit_kind) = LitKind::from_token_lit(*lit) && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind && let Ok(n_usize) = usize::try_from(n_u128) { diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index e47ea83ac..bec6d1a2d 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,4 +1,8 @@ use crate::base::ExtCtxt; +use crate::errors::{ + CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce, + NoSyntaxVarsExprRepeat, VarStillRepeating, +}; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch}; use crate::mbe::{self, MetaVarExpr}; use rustc_ast::mut_visit::{self, MutVisitor}; @@ -165,11 +169,7 @@ pub(super) fn transcribe<'a>( seq @ mbe::TokenTree::Sequence(_, delimited) => { match lockstep_iter_size(&seq, interp, &repeats) { LockstepIterSize::Unconstrained => { - return Err(cx.struct_span_err( - seq.span(), /* blame macro writer */ - "attempted to repeat an expression containing no syntax variables \ - matched as repeating at this depth", - )); + return Err(cx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() })); } LockstepIterSize::Contradiction(msg) => { @@ -177,7 +177,7 @@ pub(super) fn transcribe<'a>( // happens when two meta-variables are used in the same repetition in a // sequence, but they come from different sequence matchers and repeat // different amounts. - return Err(cx.struct_span_err(seq.span(), &msg)); + return Err(cx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg })); } LockstepIterSize::Constraint(len, _) => { @@ -193,10 +193,7 @@ pub(super) fn transcribe<'a>( // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. - return Err(cx.struct_span_err( - sp.entire(), - "this must repeat at least once", - )); + return Err(cx.create_err(MustRepeatOnce { span: sp.entire() })); } } else { // 0 is the initial counter (we have done 0 repetitions so far). `len` @@ -239,10 +236,7 @@ pub(super) fn transcribe<'a>( } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. - return Err(cx.struct_span_err( - sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", ident), - )); + return Err(cx.create_err(VarStillRepeating { span: sp, ident })); } } } else { @@ -448,10 +442,7 @@ fn count_repetitions<'a>( match matched { MatchedTokenTree(_) | MatchedNonterminal(_) => { if declared_lhs_depth == 0 { - return Err(cx.struct_span_err( - sp.entire(), - "`count` can not be placed inside the inner-most repetition", - )); + return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() })); } match depth_opt { None => Ok(1), @@ -499,12 +490,7 @@ where { let span = ident.span; let key = MacroRulesNormalizedIdent::new(ident); - interp.get(&key).ok_or_else(|| { - cx.struct_span_err( - span, - &format!("variable `{}` is not recognized in meta-variable expression", key), - ) - }) + interp.get(&key).ok_or_else(|| cx.create_err(MetaVarExprUnrecognizedVar { span, key })) } /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 0315d1163..9002a24e4 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,6 +1,6 @@ use crate::base::ModuleData; use rustc_ast::ptr::P; -use rustc_ast::{token, Attribute, Inline, Item, ModSpans}; +use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; use rustc_parse::new_parser_from_file; use rustc_parse::validate_attr; @@ -48,7 +48,7 @@ pub(crate) fn parse_external_mod( span: Span, // The span to blame on errors. module: &ModuleData, mut dir_ownership: DirOwnership, - attrs: &mut Vec, + attrs: &mut AttrVec, ) -> ParsedExternalMod { // We bail on the first error, but that error does not cause a fatal error... (1) let result: Result<_, ModError<'_>> = try { @@ -63,9 +63,9 @@ pub(crate) fn parse_external_mod( // Actually parse the external file as a module. let mut parser = new_parser_from_file(&sess.parse_sess, &mp.file_path, Some(span)); - let (mut inner_attrs, items, inner_span) = + let (inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?; - attrs.append(&mut inner_attrs); + attrs.extend(inner_attrs); (items, inner_span, mp.file_path) }; // (1) ...instead, we return a dummy module. diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 0d5d6ee07..3b0d5ddb9 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -15,16 +15,16 @@ pub fn placeholder( id: ast::NodeId, vis: Option, ) -> AstFragment { - fn mac_placeholder() -> ast::MacCall { - ast::MacCall { + fn mac_placeholder() -> P { + P(ast::MacCall { path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None }, args: P(ast::MacArgs::Empty), prior_type_ascription: None, - } + }) } let ident = Ident::empty(); - let attrs = Vec::new(); + let attrs = ast::AttrVec::new(); let vis = vis.unwrap_or(ast::Visibility { span: DUMMY_SP, kind: ast::VisibilityKind::Inherited, diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 7d9a4aed0..59a7b668a 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -6,7 +6,7 @@ use rustc_ast::tokenstream::{self, Spacing::*, TokenStream}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Diagnostic, MultiSpan, PResult}; +use rustc_errors::{MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; @@ -15,7 +15,7 @@ use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; use pm::bridge::{ - server, DelimSpan, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, + server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, }; use pm::{Delimiter, Level, LineColumn}; use std::ops::Bound; @@ -368,8 +368,6 @@ impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type SourceFile = Lrc; - type MultiSpan = Vec; - type Diagnostic = Diagnostic; type Span = Span; type Symbol = Symbol; } @@ -436,6 +434,21 @@ impl server::FreeFunctions for Rustc<'_, '_> { span: self.call_site, }) } + + fn emit_diagnostic(&mut self, diagnostic: Diagnostic) { + let mut diag = + rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); + diag.set_span(MultiSpan::from_spans(diagnostic.spans)); + for child in diagnostic.children { + diag.sub( + child.level.to_internal(), + child.message, + MultiSpan::from_spans(child.spans), + None, + ); + } + self.sess().span_diagnostic.emit_diagnostic(&mut diag); + } } impl server::TokenStream for Rustc<'_, '_> { @@ -486,20 +499,26 @@ impl server::TokenStream for Rustc<'_, '_> { // We don't use `TokenStream::from_ast` as the tokenstream currently cannot // be recovered in the general case. match &expr.kind { - ast::ExprKind::Lit(l) if l.token.kind == token::Bool => Ok( - tokenstream::TokenStream::token_alone(token::Ident(l.token.symbol, false), l.span), - ), + ast::ExprKind::Lit(l) if l.token_lit.kind == token::Bool => { + Ok(tokenstream::TokenStream::token_alone( + token::Ident(l.token_lit.symbol, false), + l.span, + )) + } ast::ExprKind::Lit(l) => { - Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token), l.span)) + Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token_lit), l.span)) } ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind { - ast::ExprKind::Lit(l) => match l.token { + ast::ExprKind::Lit(l) => match l.token_lit { token::Lit { kind: token::Integer | token::Float, .. } => { Ok(Self::TokenStream::from_iter([ // FIXME: The span of the `-` token is lost when // parsing, so we cannot faithfully recover it here. tokenstream::TokenTree::token_alone(token::BinOp(token::Minus), e.span), - tokenstream::TokenTree::token_alone(token::Literal(l.token), l.span), + tokenstream::TokenTree::token_alone( + token::Literal(l.token_lit), + l.span, + ), ])) } _ => Err(()), @@ -577,38 +596,6 @@ impl server::SourceFile for Rustc<'_, '_> { } } -impl server::MultiSpan for Rustc<'_, '_> { - fn new(&mut self) -> Self::MultiSpan { - vec![] - } - - fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) { - spans.push(span) - } -} - -impl server::Diagnostic for Rustc<'_, '_> { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level.to_internal(), msg); - diag.set_span(MultiSpan::from_spans(spans)); - diag - } - - fn sub( - &mut self, - diag: &mut Self::Diagnostic, - level: Level, - msg: &str, - spans: Self::MultiSpan, - ) { - diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None); - } - - fn emit(&mut self, mut diag: Self::Diagnostic) { - self.sess().span_diagnostic.emit_diagnostic(&mut diag); - } -} - impl server::Span for Rustc<'_, '_> { fn debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 099c40b21..8efb7ccc1 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -161,6 +161,8 @@ declare_features! ( (accepted, fn_must_use, "1.27.0", Some(43302), None), /// Allows capturing variables in scope using format_args! (accepted, format_args_capture, "1.58.0", Some(67984), None), + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + (accepted, generic_associated_types, "1.65.0", Some(44265), None), /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). (accepted, generic_param_attrs, "1.27.0", Some(48848), None), /// Allows the `#[global_allocator]` attribute. @@ -186,6 +188,10 @@ declare_features! ( /// Allows some increased flexibility in the name resolution rules, /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120), None), + /// Allows `'a: { break 'a; }`. + (accepted, label_break_value, "1.65.0", Some(48594), None), + /// Allows `let...else` statements. + (accepted, let_else, "1.65.0", Some(87335), None), /// Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339), None), /// Allows use of `?` as the Kleene "at most one" operator in macros. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ef4a17564..3aecfba5f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -221,6 +221,8 @@ declare_features! ( (active, rustc_private, "1.0.0", Some(27812), None), /// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`. (active, rustdoc_internals, "1.58.0", Some(90418), None), + /// Allows using the `rustdoc::missing_doc_code_examples` lint + (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None), /// Allows using `#[start]` on a function indicating that it is the program entrypoint. (active, start, "1.0.0", Some(29633), None), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. @@ -336,6 +338,8 @@ declare_features! ( (active, closure_track_caller, "1.57.0", Some(87417), None), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + /// Allows use of the `#[collapse_debuginfo]` attribute. + (active, collapse_debuginfo, "1.65.0", Some(100758), None), /// Allows `async {}` expressions in const contexts. (active, const_async_blocks, "1.53.0", Some(85368), None), // Allows limiting the evaluation steps of const expressions @@ -380,6 +384,8 @@ declare_features! ( (active, doc_cfg_hide, "1.57.0", Some(43781), None), /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows `dyn* Trait` objects. + (incomplete, dyn_star, "1.65.0", Some(91611), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -394,12 +400,12 @@ declare_features! ( (active, ffi_returns_twice, "1.34.0", Some(58314), None), /// Allows using `#[repr(align(...))]` on function items (active, fn_align, "1.53.0", Some(82232), None), + /// Allows generators to be cloned. + (active, generator_clone, "1.65.0", Some(95360), None), /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), /// Infer generic args for both consts and types. (active, generic_arg_infer, "1.55.0", Some(85077), None), - /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), /// An extension to the `generic_associated_types` feature, allowing incomplete features. (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers @@ -420,14 +426,10 @@ declare_features! ( (active, intra_doc_pointers, "1.51.0", Some(80896), None), /// Allows `#[instruction_set(_)]` attribute (active, isa_attribute, "1.48.0", Some(74727), None), - /// Allows `'a: { break 'a; }`. - (active, label_break_value, "1.28.0", Some(48594), None), // Allows setting the threshold for the `large_assignments` lint. (active, large_assignments, "1.52.0", Some(83518), None), /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), - /// Allows `let...else` statements. - (active, let_else, "1.56.0", Some(87335), None), /// Allows `#[link(..., cfg(..))]`. (active, link_cfg, "1.14.0", Some(37406), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. @@ -480,17 +482,17 @@ declare_features! ( /// Allows macro attributes on expressions, statements and non-inline modules. (active, proc_macro_hygiene, "1.30.0", Some(54727), None), /// Allows the use of raw-dylibs (RFC 2627). - (incomplete, raw_dylib, "1.40.0", Some(58713), None), + (active, raw_dylib, "1.65.0", Some(58713), None), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (active, raw_ref_op, "1.41.0", Some(64490), None), - /// Allows using the `#[register_attr]` attribute. - (active, register_attr, "1.41.0", Some(66080), None), /// Allows using the `#[register_tool]` attribute. (active, register_tool, "1.41.0", Some(66079), None), /// Allows the `#[repr(i128)]` attribute for enums. (incomplete, repr128, "1.16.0", Some(56071), None), /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), + /// Allows return-position `impl Trait` in traits. + (incomplete, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None), /// Allows `extern "rust-cold"`. (active, rust_cold_cc, "1.63.0", Some(97544), None), /// Allows the use of SIMD types in functions declared in `extern` blocks. @@ -523,6 +525,8 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (active, type_changing_struct_update, "1.58.0", Some(86555), None), + /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE. + (active, unix_sigpipe, "1.65.0", Some(97889), None), /// Allows unsized fn parameters. (active, unsized_fn_params, "1.49.0", Some(48055), None), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0e73d8fd7..b50c972e6 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -277,7 +277,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing), ungated!( should_panic, Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), FutureWarnFollowing, + template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing, ), // FIXME(Centril): This can be used on stable but shouldn't. ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing), @@ -335,7 +335,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ABI, linking, symbols, and FFI ungated!( link, Normal, - template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#), DuplicatesOk, ), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), @@ -345,6 +345,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), + ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding), // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), @@ -359,6 +360,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Entry point: + gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)), ungated!(start, Normal, template!(Word), WarnFollowing), ungated!(no_start, CrateLevel, template!(Word), WarnFollowing), ungated!(no_main, CrateLevel, template!(Word), WarnFollowing), @@ -405,10 +407,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Linking: gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)), - gated!( - link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib, - experimental!(link_ordinal) - ), // Plugins: BuiltinAttribute { @@ -458,10 +456,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)), gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)), - gated!( - register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), DuplicatesOk, - experimental!(register_attr), - ), gated!( register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk, experimental!(register_tool), @@ -484,6 +478,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(deprecated_safe), ), + // `#[collapse_debuginfo]` + gated!( + collapse_debuginfo, Normal, template!(Word), WarnFollowing, + experimental!(collapse_debuginfo) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), + ungated!( + rustc_default_body_unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk + ), gated!( allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, "allow_internal_unstable side-steps feature gating and stability checks", @@ -758,6 +762,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Testing: // ========================================================================== + rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), @@ -821,6 +826,14 @@ pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } +pub fn is_valid_for_get_attr(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates { + WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing + | FutureWarnPreceding => true, + DuplicatesOk | WarnFollowingWordOnly => false, + }) +} + pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index efb830527..bdaa0ee88 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -12,6 +12,8 @@ //! symbol to the `accepted` or `removed` modules respectively. #![feature(once_cell)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] mod accepted; mod active; @@ -149,7 +151,7 @@ pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, - AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, - BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, + GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 2ddaf9201..79a12801d 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -163,6 +163,9 @@ declare_features! ( (removed, quad_precision_float, "1.0.0", None, None, None), (removed, quote, "1.33.0", Some(29601), None, None), (removed, reflect, "1.0.0", Some(27749), None, None), + /// Allows using the `#[register_attr]` attribute. + (removed, register_attr, "1.65.0", Some(66080), None, + Some("removed in favor of `#![register_tool]`")), /// Allows using the macros: /// + `__diagnostic_used` /// + `__register_diagnostic` diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 87e97c746..63998bb6b 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,3 +1,6 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::ffi::CString; use std::fs; use std::io; diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 6eaff5c2f..3c1bb5532 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -273,6 +273,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use LabelText::*; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index be5b7eccb..e7c26bd72 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -45,8 +45,6 @@ pub enum NonMacroAttrKind { /// Single-segment custom attribute registered by a derive macro /// but used before that derive macro was expanded (deprecated). DeriveHelperCompat, - /// Single-segment custom attribute registered with `#[register_attr]`. - Registered, } /// What kind of definition something is; e.g., `mod` vs `struct`. @@ -111,6 +109,8 @@ pub enum DefKind { InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, + /// A return-position `impl Trait` in a trait definition + ImplTraitPlaceholder, Field, /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, @@ -140,6 +140,7 @@ impl DefKind { panic!("impossible struct constructor") } DefKind::OpaqueTy => "opaque type", + DefKind::ImplTraitPlaceholder => "opaque type in trait", DefKind::TyAlias => "type alias", DefKind::TraitAlias => "trait alias", DefKind::AssocTy => "associated type", @@ -219,7 +220,8 @@ impl DefKind { | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm - | DefKind::Impl => None, + | DefKind::Impl + | DefKind::ImplTraitPlaceholder => None, } } @@ -256,6 +258,7 @@ impl DefKind { | DefKind::Use | DefKind::ForeignMod | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Field | DefKind::TyParam @@ -310,6 +313,7 @@ pub enum Res { /// /// **Belongs to the type namespace.** PrimTy(hir::PrimTy), + /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and /// optionally with the [`DefId`] of the item introducing the `Self` type alias. /// @@ -357,7 +361,8 @@ pub enum Res { /// const fn baz() -> usize { 10 } /// ``` /// We do however allow `Self` in repeat expression even if it is generic to not break code - /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint: + /// which already works on stable while causing the `const_evaluatable_unchecked` future compat + /// lint: /// ``` /// fn foo() { /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; @@ -372,6 +377,7 @@ pub enum Res { /// from mentioning generics (i.e. when used in an anonymous constant). alias_to: Option<(DefId, bool)>, }, + /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`. /// /// **Belongs to the type namespace.** @@ -385,6 +391,7 @@ pub enum Res { /// /// *See also [`Res::SelfTy`].* SelfCtor(DefId), + /// A local variable or function parameter. /// /// **Belongs to the value namespace.** @@ -455,7 +462,7 @@ impl PartialRes { /// Different kinds of symbols can coexist even if they share the same textual name. /// Therefore, they each have a separate universe (known as a "namespace"). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Namespace { /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s /// (and, by extension, crates). @@ -564,15 +571,11 @@ impl NonMacroAttrKind { NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => { "derive helper attribute" } - NonMacroAttrKind::Registered => "explicitly registered attribute", } } pub fn article(self) -> &'static str { - match self { - NonMacroAttrKind::Registered => "an", - _ => "a", - } + "a" } /// Users of some attributes cannot mark them as used, so they are considered always used. @@ -581,7 +584,7 @@ impl NonMacroAttrKind { NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => true, - NonMacroAttrKind::Builtin(..) | NonMacroAttrKind::Registered => false, + NonMacroAttrKind::Builtin(..) => false, } } } diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c2c551e78..d85ac960f 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -15,7 +15,6 @@ use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::{self, Write}; use std::hash::Hash; -use tracing::debug; /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` diff --git a/compiler/rustc_hir/src/errors.rs b/compiler/rustc_hir/src/errors.rs new file mode 100644 index 000000000..e593ed104 --- /dev/null +++ b/compiler/rustc_hir/src/errors.rs @@ -0,0 +1,10 @@ +use crate::LangItem; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] +pub struct LangItemError(pub LangItem); + +impl ToString for LangItemError { + fn to_string(&self) -> String { + format!("requires `{}` lang_item", self.0.name()) + } +} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 617433a98..a8436ea64 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use crate::LangItem; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy}; -pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; +pub use rustc_ast::{BindingAnnotation, BorrowKind, ByRef, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fingerprint::Fingerprint; @@ -139,11 +139,10 @@ impl LifetimeName { match self { LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true, - // It might seem surprising that `Fresh` counts as - // *not* elided -- but this is because, as far as the code - // in the compiler is concerned -- `Fresh` variants act - // equivalently to "some fresh name". They correspond to - // early-bound regions on an impl, in other words. + // It might seem surprising that `Fresh` counts as not *elided* + // -- but this is because, as far as the code in the compiler is + // concerned -- `Fresh` variants act equivalently to "some fresh name". + // They correspond to early-bound regions on an impl, in other words. LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false, } } @@ -202,13 +201,8 @@ impl Path<'_> { pub struct PathSegment<'hir> { /// The identifier portion of this path segment. pub ident: Ident, - // `id` and `res` are optional. We currently only use these in save-analysis, - // any path segments without these will not have save-analysis info and - // therefore will not have 'jump to def' in IDEs, but otherwise will not be - // affected. (In general, we don't bother to get the defs for synthesized - // segments, only for segments which have come from the AST). - pub hir_id: Option, - pub res: Option, + pub hir_id: HirId, + pub res: Res, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -226,12 +220,12 @@ pub struct PathSegment<'hir> { impl<'hir> PathSegment<'hir> { /// Converts an identifier to the corresponding segment. - pub fn from_ident(ident: Ident) -> PathSegment<'hir> { - PathSegment { ident, hir_id: None, res: None, infer_args: true, args: None } + pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { + PathSegment { ident, hir_id, res, infer_args: true, args: None } } pub fn invalid() -> Self { - Self::from_ident(Ident::empty()) + Self::new(Ident::empty(), HirId::INVALID, Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { @@ -264,8 +258,8 @@ impl InferArg { #[derive(Debug, HashStable_Generic)] pub enum GenericArg<'hir> { - Lifetime(Lifetime), - Type(Ty<'hir>), + Lifetime(&'hir Lifetime), + Type(&'hir Ty<'hir>), Const(ConstArg), Infer(InferArg), } @@ -280,7 +274,7 @@ impl GenericArg<'_> { } } - pub fn id(&self) -> HirId { + pub fn hir_id(&self) -> HirId { match self { GenericArg::Lifetime(l) => l.hir_id, GenericArg::Type(t) => t.hir_id, @@ -305,9 +299,9 @@ impl GenericArg<'_> { pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime, - GenericArg::Type(_) => ast::ParamKindOrd::Type, - GenericArg::Const(_) => ast::ParamKindOrd::Const, - GenericArg::Infer(_) => ast::ParamKindOrd::Infer, + GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => { + ast::ParamKindOrd::TypeOrConst + } } } @@ -435,7 +429,7 @@ pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), - Outlives(Lifetime), + Outlives(&'hir Lifetime), } impl GenericBound<'_> { @@ -581,8 +575,7 @@ impl<'hir> Generics<'hir> { if self.has_where_clause_predicates { self.predicates .iter() - .filter(|p| p.in_where_clause()) - .last() + .rfind(|&p| p.in_where_clause()) .map_or(end, |p| p.span()) .shrink_to_hi() .to(end) @@ -761,7 +754,7 @@ impl<'hir> WhereBoundPredicate<'hir> { pub struct WhereRegionPredicate<'hir> { pub span: Span, pub in_where_clause: bool, - pub lifetime: Lifetime, + pub lifetime: &'hir Lifetime, pub bounds: GenericBounds<'hir>, } @@ -778,7 +771,6 @@ impl<'hir> WhereRegionPredicate<'hir> { /// An equality predicate (e.g., `T = int`); currently unsupported. #[derive(Debug, HashStable_Generic)] pub struct WhereEqPredicate<'hir> { - pub hir_id: HirId, pub span: Span, pub lhs_ty: &'hir Ty<'hir>, pub rhs_ty: &'hir Ty<'hir>, @@ -841,7 +833,16 @@ impl<'tcx> OwnerNodes<'tcx> { impl fmt::Debug for OwnerNodes<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OwnerNodes") + // Do not print all the pointers to all the nodes, as it would be unreadable. .field("node", &self.nodes[ItemLocalId::from_u32(0)]) + .field( + "parents", + &self + .nodes + .iter_enumerated() + .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent))) + .collect::>(), + ) .field("bodies", &self.bodies) .field("local_id_to_def_id", &self.local_id_to_def_id) .field("hash_without_bodies", &self.hash_without_bodies) @@ -1050,30 +1051,6 @@ pub struct PatField<'hir> { pub span: Span, } -/// Explicit binding annotations given in the HIR for a binding. Note -/// that this is not the final binding *mode* that we infer after type -/// inference. -#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)] -pub enum BindingAnnotation { - /// No binding annotation given: this means that the final binding mode - /// will depend on whether we have skipped through a `&` reference - /// when matching. For example, the `x` in `Some(x)` will have binding - /// mode `None`; if you do `let Some(x) = &Some(22)`, it will - /// ultimately be inferred to be by-reference. - /// - /// Note that implicit reference skipping is not implemented yet (#42640). - Unannotated, - - /// Annotated with `mut x` -- could be either ref or not, similar to `None`. - Mutable, - - /// Annotated as `ref`, like `ref x` - Ref, - - /// Annotated as `ref mut x`. - RefMut, -} - #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)] pub enum RangeEnd { Included, @@ -1089,6 +1066,35 @@ impl fmt::Display for RangeEnd { } } +// Equivalent to `Option`. That type takes up 16 bytes on 64-bit, but +// this type only takes up 4 bytes, at the cost of being restricted to a +// maximum value of `u32::MAX - 1`. In practice, this is more than enough. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)] +pub struct DotDotPos(u32); + +impl DotDotPos { + // Panics if n >= u32::MAX. + pub fn new(n: Option) -> Self { + match n { + Some(n) => { + assert!(n < u32::MAX as usize); + Self(n as u32) + } + None => Self(u32::MAX), + } + } + + pub fn as_opt_usize(&self) -> Option { + if self.0 == u32::MAX { None } else { Some(self.0 as usize) } + } +} + +impl fmt::Debug for DotDotPos { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_opt_usize().fmt(f) + } +} + #[derive(Debug, HashStable_Generic)] pub enum PatKind<'hir> { /// Represents a wildcard pattern (i.e., `_`). @@ -1105,9 +1111,9 @@ pub enum PatKind<'hir> { Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment is present, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. /// `0 <= position <= subpats.len()` - TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option), + TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. @@ -1119,7 +1125,7 @@ pub enum PatKind<'hir> { /// A tuple pattern (e.g., `(a, b)`). /// If the `..` pattern fragment is present, then `Option` denotes its position. /// `0 <= position <= subpats.len()` - Tuple(&'hir [Pat<'hir>], Option), + Tuple(&'hir [Pat<'hir>], DotDotPos), /// A `box` pattern. Box(&'hir Pat<'hir>), @@ -1322,7 +1328,7 @@ pub enum StmtKind<'hir> { Semi(&'hir Expr<'hir>), } -/// Represents a `let` statement (i.e., `let : = ;`). +/// Represents a `let` statement (i.e., `let : = ;`). #[derive(Debug, HashStable_Generic)] pub struct Local<'hir> { pub pat: &'hir Pat<'hir>, @@ -1439,7 +1445,7 @@ pub struct BodyId { #[derive(Debug, HashStable_Generic)] pub struct Body<'hir> { pub params: &'hir [Param<'hir>], - pub value: Expr<'hir>, + pub value: &'hir Expr<'hir>, pub generator_kind: Option, } @@ -1626,7 +1632,7 @@ pub struct AnonConst { } /// An expression. -#[derive(Debug)] +#[derive(Debug, HashStable_Generic)] pub struct Expr<'hir> { pub hir_id: HirId, pub kind: ExprKind<'hir>, @@ -1882,11 +1888,11 @@ pub enum ExprKind<'hir> { /// /// The `PathSegment` represents the method name and its generic arguments /// (within the angle brackets). - /// The first element of the `&[Expr]` is the expression that evaluates + /// The `&Expr` is the expression that evaluates /// to the object on which the method is being called on (the receiver), - /// and the remaining elements are the rest of the arguments. + /// and the `&[Expr]` is the rest of the arguments. /// Thus, `x.foo::(a, b, c, d)` is represented as - /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`. + /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`. /// The final `Span` represents the span of the function and arguments /// (e.g. `foo::(a, b, c, d)` in `x.foo::(a, b, c, d)` /// @@ -1894,7 +1900,7 @@ pub enum ExprKind<'hir> { /// the `hir_id` of the `MethodCall` node itself. /// /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id - MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span), + MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), /// A binary operation (e.g., `a + b`, `a * b`). @@ -2380,7 +2386,7 @@ impl TypeBinding<'_> { } } -#[derive(Debug)] +#[derive(Debug, HashStable_Generic)] pub struct Ty<'hir> { pub hir_id: HirId, pub kind: TyKind<'hir>, @@ -2402,6 +2408,14 @@ impl<'hir> Ty<'hir> { _ => None, } } + + pub fn peel_refs(&self) -> &Self { + let mut final_ty = self; + while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind { + final_ty = &ty; + } + final_ty + } } /// Not represented directly in the AST; referred to by name through a `ty_path`. @@ -2506,6 +2520,7 @@ pub struct OpaqueTy<'hir> { pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, + pub in_trait: bool, } /// From whence the opaque type came. @@ -2529,7 +2544,7 @@ pub enum TyKind<'hir> { /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). - Rptr(Lifetime, MutTy<'hir>), + Rptr(&'hir Lifetime, MutTy<'hir>), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(&'hir BareFnTy<'hir>), /// The never type (`!`). @@ -2545,10 +2560,12 @@ pub enum TyKind<'hir> { /// /// The generic argument list contains the lifetimes (and in the future /// possibly parameters) that are actually bound on the `impl Trait`. - OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), + /// + /// The last parameter specifies whether this opaque appears in a trait definition. + OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime, TraitObjectSyntax), + TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), /// Unused for now. Typeof(AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been @@ -2562,23 +2579,23 @@ pub enum TyKind<'hir> { pub enum InlineAsmOperand<'hir> { In { reg: InlineAsmRegOrRegClass, - expr: Expr<'hir>, + expr: &'hir Expr<'hir>, }, Out { reg: InlineAsmRegOrRegClass, late: bool, - expr: Option>, + expr: Option<&'hir Expr<'hir>>, }, InOut { reg: InlineAsmRegOrRegClass, late: bool, - expr: Expr<'hir>, + expr: &'hir Expr<'hir>, }, SplitInOut { reg: InlineAsmRegOrRegClass, late: bool, - in_expr: Expr<'hir>, - out_expr: Option>, + in_expr: &'hir Expr<'hir>, + out_expr: Option<&'hir Expr<'hir>>, }, Const { anon_const: AnonConst, @@ -2643,7 +2660,7 @@ pub struct FnDecl<'hir> { } /// Represents what type of implicit self a function has, if any. -#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum ImplicitSelfKind { /// Represents a `fn x(self);`. Imm, @@ -2992,7 +3009,7 @@ pub enum ItemKind<'hir> { /// A MBE macro definition (`macro_rules!` or `macro`). Macro(ast::MacroDef, MacroKind), /// A module. - Mod(Mod<'hir>), + Mod(&'hir Mod<'hir>), /// An external module, e.g. `extern { .. }`. ForeignMod { abi: Abi, items: &'hir [ForeignItemRef] }, /// Module-level inline assembly (from `global_asm!`). @@ -3217,7 +3234,7 @@ impl<'hir> OwnerNode<'hir> { } } - pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> { + pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> { match self { OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) @@ -3332,12 +3349,14 @@ pub enum Node<'hir> { Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), Expr(&'hir Expr<'hir>), + ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), Ty(&'hir Ty<'hir>), TypeBinding(&'hir TypeBinding<'hir>), TraitRef(&'hir TraitRef<'hir>), Pat(&'hir Pat<'hir>), + PatField(&'hir PatField<'hir>), Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), Local(&'hir Local<'hir>), @@ -3388,6 +3407,8 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) + | Node::PatField(..) + | Node::ExprField(..) | Node::Arm(..) | Node::Local(..) | Node::Crate(..) @@ -3397,19 +3418,20 @@ impl<'hir> Node<'hir> { } } - pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> { + pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), - Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { + Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { Some(fn_decl) } _ => None, } } - pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> { + pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) @@ -3491,16 +3513,37 @@ impl<'hir> Node<'hir> { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Block<'static>, 48); - rustc_data_structures::static_assert_size!(Expr<'static>, 56); - rustc_data_structures::static_assert_size!(ForeignItem<'static>, 72); - rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); - rustc_data_structures::static_assert_size!(Generics<'static>, 56); - rustc_data_structures::static_assert_size!(ImplItem<'static>, 88); - rustc_data_structures::static_assert_size!(Impl<'static>, 80); - rustc_data_structures::static_assert_size!(Item<'static>, 80); - rustc_data_structures::static_assert_size!(Pat<'static>, 88); - rustc_data_structures::static_assert_size!(QPath<'static>, 24); - rustc_data_structures::static_assert_size!(TraitItem<'static>, 96); - rustc_data_structures::static_assert_size!(Ty<'static>, 72); + static_assert_size!(Block<'_>, 48); + static_assert_size!(Body<'_>, 32); + static_assert_size!(Expr<'_>, 64); + static_assert_size!(ExprKind<'_>, 48); + static_assert_size!(FnDecl<'_>, 40); + static_assert_size!(ForeignItem<'_>, 72); + static_assert_size!(ForeignItemKind<'_>, 40); + #[cfg(not(bootstrap))] + static_assert_size!(GenericArg<'_>, 24); + static_assert_size!(GenericBound<'_>, 48); + static_assert_size!(Generics<'_>, 56); + static_assert_size!(Impl<'_>, 80); + #[cfg(not(bootstrap))] + static_assert_size!(ImplItem<'_>, 80); + #[cfg(not(bootstrap))] + static_assert_size!(ImplItemKind<'_>, 32); + static_assert_size!(Item<'_>, 80); + static_assert_size!(ItemKind<'_>, 48); + static_assert_size!(Local<'_>, 64); + static_assert_size!(Param<'_>, 32); + static_assert_size!(Pat<'_>, 72); + static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Path<'_>, 48); + static_assert_size!(PathSegment<'_>, 56); + static_assert_size!(QPath<'_>, 24); + static_assert_size!(Stmt<'_>, 32); + static_assert_size!(StmtKind<'_>, 16); + #[cfg(not(bootstrap))] + static_assert_size!(TraitItem<'_>, 88); + #[cfg(not(bootstrap))] + static_assert_size!(TraitItemKind<'_>, 48); + static_assert_size!(Ty<'_>, 48); + static_assert_size!(TyKind<'_>, 32); } diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 346ac9e96..84b0740c7 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -20,6 +20,9 @@ pub struct HirId { } impl HirId { + /// Signal local id which should never be used. + pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID }; + #[inline] pub fn expect_owner(self) -> LocalDefId { assert_eq!(self.local_id.index(), 0); @@ -64,8 +67,13 @@ impl PartialOrd for HirId { } } -rustc_data_structures::define_id_collections!(HirIdMap, HirIdSet, HirId); -rustc_data_structures::define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId); +rustc_data_structures::define_stable_id_collections!(HirIdMap, HirIdSet, HirIdMapEntry, HirId); +rustc_data_structures::define_id_collections!( + ItemLocalMap, + ItemLocalSet, + ItemLocalMapEntry, + ItemLocalId +); rustc_index::newtype_index! { /// An `ItemLocalId` uniquely identifies something within a given "item-like"; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e676acebe..8f5f314ec 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -298,7 +298,7 @@ pub trait Visitor<'v>: Sized { fn visit_id(&mut self, _hir_id: HirId) { // Nothing to do. } - fn visit_name(&mut self, _span: Span, _name: Symbol) { + fn visit_name(&mut self, _name: Symbol) { // Nothing to do. } fn visit_ident(&mut self, ident: Ident) { @@ -325,6 +325,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } + fn visit_pat_field(&mut self, f: &'v PatField<'v>) { + walk_pat_field(self, f) + } fn visit_array_length(&mut self, len: &'v ArrayLen) { walk_array_len(self, len) } @@ -337,6 +340,9 @@ pub trait Visitor<'v>: Sized { fn visit_let_expr(&mut self, lex: &'v Let<'v>) { walk_let_expr(self, lex) } + fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { + walk_expr_field(self, field) + } fn visit_ty(&mut self, t: &'v Ty<'v>) { walk_ty(self, t) } @@ -355,8 +361,8 @@ pub trait Visitor<'v>: Sized { fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) { walk_fn_decl(self, fd) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, s: Span, id: HirId) { - walk_fn(self, fk, fd, b, s, id) + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) { + walk_fn(self, fk, fd, b, id) } fn visit_use(&mut self, path: &'v Path<'v>, hir_id: HirId) { walk_use(self, path, hir_id) @@ -382,33 +388,20 @@ pub trait Visitor<'v>: Sized { fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) { walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) { - walk_poly_trait_ref(self, t, m) - } - fn visit_variant_data( - &mut self, - s: &'v VariantData<'v>, - _: Symbol, - _: &'v Generics<'v>, - _parent_id: HirId, - _: Span, - ) { + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) { + walk_poly_trait_ref(self, t) + } + fn visit_variant_data(&mut self, s: &'v VariantData<'v>) { walk_struct_def(self, s) } fn visit_field_def(&mut self, s: &'v FieldDef<'v>) { walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &'v EnumDef<'v>, - generics: &'v Generics<'v>, - item_id: HirId, - _: Span, - ) { - walk_enum_def(self, enum_definition, generics, item_id) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) { + walk_enum_def(self, enum_definition, item_id) } - fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'v Variant<'v>) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'v Label) { walk_label(self, label) @@ -427,17 +420,18 @@ pub trait Visitor<'v>: Sized { fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { walk_lifetime(self, lifetime) } - fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, span: Span) { - walk_qpath(self, qpath, id, span) + // The span is that of the surrounding type/pattern/expr/whatever. + fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) { + walk_qpath(self, qpath, id) } fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { walk_path(self, path) } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment<'v>) { - walk_path_segment(self, path_span, path_segment) + fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) { + walk_path_segment(self, path_segment) } - fn visit_generic_args(&mut self, path_span: Span, generic_args: &'v GenericArgs<'v>) { - walk_generic_args(self, path_span, generic_args) + fn visit_generic_args(&mut self, generic_args: &'v GenericArgs<'v>) { + walk_generic_args(self, generic_args) } fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) { walk_assoc_type_binding(self, type_binding) @@ -479,7 +473,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { } pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) { - visitor.visit_name(ident.span, ident.name); + visitor.visit_name(ident.name); } pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) { @@ -501,11 +495,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime } } -pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( - visitor: &mut V, - trait_ref: &'v PolyTraitRef<'v>, - _modifier: TraitBoundModifier, -) { +pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) { walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params); visitor.visit_trait_ref(&trait_ref.trait_ref); } @@ -526,7 +516,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { ItemKind::ExternCrate(orig_name) => { visitor.visit_id(item.hir_id()); if let Some(orig_name) = orig_name { - visitor.visit_name(item.span, orig_name); + visitor.visit_name(orig_name); } } ItemKind::Use(ref path, _) => { @@ -572,7 +562,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { ItemKind::Enum(ref enum_definition, ref generics) => { visitor.visit_generics(generics); // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. - visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span) + visitor.visit_enum_def(enum_definition, item.hir_id()) } ItemKind::Impl(Impl { unsafety: _, @@ -595,13 +585,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_id(item.hir_id()); - visitor.visit_variant_data( - struct_definition, - item.ident.name, - generics, - item.hir_id(), - item.span, - ); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { visitor.visit_id(item.hir_id()); @@ -649,28 +633,16 @@ pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, - generics: &'v Generics<'v>, item_id: HirId, ) { visitor.visit_id(item_id); - walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id); + walk_list!(visitor, visit_variant, enum_definition.variants); } -pub fn walk_variant<'v, V: Visitor<'v>>( - visitor: &mut V, - variant: &'v Variant<'v>, - generics: &'v Generics<'v>, - parent_item_id: HirId, -) { +pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) { visitor.visit_ident(variant.ident); visitor.visit_id(variant.id); - visitor.visit_variant_data( - &variant.data, - variant.ident.name, - generics, - parent_item_id, - variant.span, - ); + visitor.visit_variant_data(&variant.data); walk_list!(visitor, visit_anon_const, &variant.disr_expr); } @@ -695,7 +667,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { TyKind::Path(ref qpath) => { visitor.visit_qpath(qpath, typ.hir_id, typ.span); } - TyKind::OpaqueDef(item_id, lifetimes) => { + TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { visitor.visit_nested_item(item_id); walk_list!(visitor, visit_generic_arg, lifetimes); } @@ -705,7 +677,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { for bound in bounds { - visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None); + visitor.visit_poly_trait_ref(bound); } visitor.visit_lifetime(lifetime); } @@ -718,12 +690,7 @@ pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) { visitor.visit_id(inf.hir_id); } -pub fn walk_qpath<'v, V: Visitor<'v>>( - visitor: &mut V, - qpath: &'v QPath<'v>, - id: HirId, - span: Span, -) { +pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) { match *qpath { QPath::Resolved(ref maybe_qself, ref path) => { walk_list!(visitor, visit_ty, maybe_qself); @@ -731,7 +698,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( } QPath::TypeRelative(ref qself, ref segment) => { visitor.visit_ty(qself); - visitor.visit_path_segment(span, segment); + visitor.visit_path_segment(segment); } QPath::LangItem(..) => {} } @@ -739,27 +706,19 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) { for segment in path.segments { - visitor.visit_path_segment(path.span, segment); + visitor.visit_path_segment(segment); } } -pub fn walk_path_segment<'v, V: Visitor<'v>>( - visitor: &mut V, - path_span: Span, - segment: &'v PathSegment<'v>, -) { +pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) { visitor.visit_ident(segment.ident); - walk_list!(visitor, visit_id, segment.hir_id); + visitor.visit_id(segment.hir_id); if let Some(ref args) = segment.args { - visitor.visit_generic_args(path_span, args); + visitor.visit_generic_args(args); } } -pub fn walk_generic_args<'v, V: Visitor<'v>>( - visitor: &mut V, - _path_span: Span, - generic_args: &'v GenericArgs<'v>, -) { +pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) { walk_list!(visitor, visit_generic_arg, generic_args.args); walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings); } @@ -770,7 +729,7 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>( ) { visitor.visit_id(type_binding.hir_id); visitor.visit_ident(type_binding.ident); - visitor.visit_generic_args(type_binding.span, type_binding.gen_args); + visitor.visit_generic_args(type_binding.gen_args); match type_binding.kind { TypeBindingKind::Equality { ref term } => match term { Term::Ty(ref ty) => visitor.visit_ty(ty), @@ -792,11 +751,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { } PatKind::Struct(ref qpath, fields, _) => { visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); - for field in fields { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) - } + walk_list!(visitor, visit_pat_field, fields); } PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats), PatKind::Tuple(tuple_elements, _) => { @@ -823,6 +778,12 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { } } +pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) { + visitor.visit_id(field.hir_id); + visitor.visit_ident(field.ident); + visitor.visit_pat(&field.pat) +} + pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) { visitor.visit_id(foreign_item.hir_id()); visitor.visit_ident(foreign_item.ident); @@ -842,12 +803,12 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) { match *bound { - GenericBound::Trait(ref typ, modifier) => { - visitor.visit_poly_trait_ref(typ, modifier); + GenericBound::Trait(ref typ, _modifier) => { + visitor.visit_poly_trait_ref(typ); } - GenericBound::LangItemTrait(_, span, hir_id, args) => { + GenericBound::LangItemTrait(_, _span, hir_id, args) => { visitor.visit_id(hir_id); - visitor.visit_generic_args(span, args); + visitor.visit_generic_args(args); } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), } @@ -899,10 +860,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>( visitor.visit_lifetime(lifetime); walk_list!(visitor, visit_param_bound, bounds); } - WherePredicate::EqPredicate(WhereEqPredicate { - hir_id, ref lhs_ty, ref rhs_ty, .. - }) => { - visitor.visit_id(hir_id); + WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { visitor.visit_ty(lhs_ty); visitor.visit_ty(rhs_ty); } @@ -936,7 +894,6 @@ pub fn walk_fn<'v, V: Visitor<'v>>( function_kind: FnKind<'v>, function_declaration: &'v FnDecl<'v>, body_id: BodyId, - _span: Span, id: HirId, ) { visitor.visit_id(id); @@ -1090,6 +1047,12 @@ pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) walk_list!(visitor, visit_ty, let_expr.ty); } +pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { + visitor.visit_id(field.hir_id); + visitor.visit_ident(field.ident); + visitor.visit_expr(&field.expr) +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { visitor.visit_id(expression.hir_id); match expression.kind { @@ -1104,11 +1067,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } ExprKind::Struct(ref qpath, fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.hir_id, expression.span); - for field in fields { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_expr_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(subexpressions) => { @@ -1118,8 +1077,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, arguments, _) => { - visitor.visit_path_segment(expression.span, segment); + ExprKind::MethodCall(ref segment, receiver, arguments, _) => { + visitor.visit_path_segment(segment); + visitor.visit_expr(receiver); walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c337be12a..ca615a491 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -8,6 +8,7 @@ //! * Functions called by the compiler itself. use crate::def_id::DefId; +use crate::errors::LangItemError; use crate::{MethodKind, Target}; use rustc_ast as ast; @@ -115,9 +116,9 @@ macro_rules! language_item_table { /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. /// If it wasn't bound, e.g. due to a missing `#[lang = ""]`, - /// returns an error message as a string. - pub fn require(&self, it: LangItem) -> Result { - self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) + /// returns an error encapsulating the `LangItem`. + pub fn require(&self, it: LangItem) -> Result { + self.items[it as usize].ok_or_else(|| LangItemError(it)) } /// Returns the [`DefId`]s of all lang items in a group. @@ -192,7 +193,8 @@ language_item_table! { DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); // language items relating to transmutability - TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6); + TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); + TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3); Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); @@ -236,7 +238,6 @@ language_item_table! { Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None; Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1); - GeneratorReturn, sym::generator_return, generator_return, Target::AssocTy, GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; @@ -267,8 +268,6 @@ language_item_table! { DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; - ConstEvalSelect, sym::const_eval_select, const_eval_select, Target::Fn, GenericRequirement::Exact(4); - ConstConstEvalSelect, sym::const_eval_select_ct,const_eval_select_ct, Target::Fn, GenericRequirement::Exact(4); Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); @@ -290,6 +289,8 @@ language_item_table! { Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None; + Tuple, sym::tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0); + SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; // Language items from AST lowering diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 0f9e6fa7b..946da9265 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -5,16 +5,21 @@ #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_btree_new)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + #[macro_use] extern crate rustc_data_structures; @@ -25,6 +30,7 @@ pub mod def; pub mod def_path_hash_map; pub mod definitions; pub mod diagnostic_items; +pub mod errors; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 93112199b..0c1819bb0 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -1,6 +1,6 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; -use crate::hir::{self, HirId, PatKind}; +use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind}; use rustc_data_structures::fx::FxHashSet; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; @@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator { fn enumerate_and_adjust( self, expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> EnumerateAndAdjust where Self: Sized; @@ -45,7 +45,7 @@ impl EnumerateAndAdjustIterator for T { fn enumerate_and_adjust( self, expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> EnumerateAndAdjust where Self: Sized, @@ -53,7 +53,7 @@ impl EnumerateAndAdjustIterator for T { let actual_len = self.len(); EnumerateAndAdjust { enumerate: self.enumerate(), - gap_pos: gap_pos.unwrap_or(expected_len), + gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len), gap_len: expected_len - actual_len, } } @@ -93,12 +93,7 @@ impl hir::Pat<'_> { pub fn simple_ident(&self) -> Option { match self.kind { - PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - _, - ident, - None, - ) => Some(ident), + PatKind::Binding(BindingAnnotation(ByRef::No, _), _, ident, None) => Some(ident), _ => None, } } @@ -135,11 +130,11 @@ impl hir::Pat<'_> { pub fn contains_explicit_ref_binding(&self) -> Option { let mut result = None; self.each_binding(|annotation, _, _, _| match annotation { - hir::BindingAnnotation::Ref => match result { + hir::BindingAnnotation::REF => match result { None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not), _ => {} }, - hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut), + hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut), _ => {} }); result diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 8ccd59e8e..5b9c42686 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - AttributeMap, BodyId, Crate, Expr, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, - Ty, + AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -14,8 +13,6 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_target::HashStableContext { fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); - fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher); - fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); } impl ToStableHashKey for HirId { @@ -96,18 +93,6 @@ impl HashStable for BodyId { // want to pick up on a reference changing its target, so we hash the NodeIds // in "DefPath Mode". -impl HashStable for Expr<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_hir_expr(self, hasher) - } -} - -impl HashStable for Ty<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_hir_ty(self, hasher) - } -} - impl<'tcx, HirCtx: crate::HashStableContext> HashStable for OwnerNodes<'tcx> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `nodes` and `bodies` fields since these refer to information included in diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 6236dea10..5917d5e34 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -36,6 +36,7 @@ pub enum Target { GlobalAsm, TyAlias, OpaqueTy, + ImplTraitPlaceholder, Enum, Variant, Struct, @@ -56,6 +57,8 @@ pub enum Target { GenericParam(GenericParamKind), MacroDef, Param, + PatField, + ExprField, } impl Display for Target { @@ -77,7 +80,13 @@ impl Target { ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, - ItemKind::OpaqueTy(..) => Target::OpaqueTy, + ItemKind::OpaqueTy(ref opaque) => { + if opaque.in_trait { + Target::ImplTraitPlaceholder + } else { + Target::OpaqueTy + } + } ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, ItemKind::Union(..) => Target::Union, @@ -101,6 +110,7 @@ impl Target { DefKind::GlobalAsm => Target::GlobalAsm, DefKind::TyAlias => Target::TyAlias, DefKind::OpaqueTy => Target::OpaqueTy, + DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, DefKind::Union => Target::Union, @@ -155,6 +165,7 @@ impl Target { Target::GlobalAsm => "global asm", Target::TyAlias => "type alias", Target::OpaqueTy => "opaque type", + Target::ImplTraitPlaceholder => "opaque type in trait", Target::Enum => "enum", Target::Variant => "enum variant", Target::Struct => "struct", @@ -183,6 +194,8 @@ impl Target { }, Target::MacroDef => "macro def", Target::Param => "function param", + Target::PatField => "pattern field", + Target::ExprField => "struct field", } } } diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b6a85c047..da9c9c121 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -18,6 +18,12 @@ pub static WEAK_ITEMS_REFS: LazyLock> = LazyLock::n map }); +pub static WEAK_ITEMS_SYMBOLS: LazyLock> = LazyLock::new(|| { + let mut map = FxIndexMap::default(); + $(map.insert(LangItem::$item, sym::$sym);)* + map +}); + pub fn link_name(attrs: &[ast::Attribute]) -> Option { lang_items::extract(attrs).and_then(|(name, _)| { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e0179bd3e..35a58296e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1,4 +1,6 @@ #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use rustc_ast as ast; use rustc_ast::util::parser::{self, AssocOp, Fixity}; @@ -7,7 +9,9 @@ use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; use rustc_hir::LifetimeParamKind; -use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term}; +use rustc_hir::{ + BindingAnnotation, ByRef, GenericArg, GenericParam, GenericParamKind, Mutability, Node, Term, +}; use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol}; @@ -83,12 +87,14 @@ impl<'a> State<'a> { Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), Node::Expr(a) => self.print_expr(a), + Node::ExprField(a) => self.print_expr_field(&a), Node::Stmt(a) => self.print_stmt(a), Node::PathSegment(a) => self.print_path_segment(a), Node::Ty(a) => self.print_type(a), Node::TypeBinding(a) => self.print_type_binding(a), Node::TraitRef(a) => self.print_trait_ref(a), Node::Pat(a) => self.print_pat(a), + Node::PatField(a) => self.print_patfield(&a), Node::Arm(a) => self.print_arm(a), Node::Infer(_) => self.word("_"), Node::Block(a) => { @@ -911,6 +917,10 @@ impl<'a> State<'a> { if let Some(els) = els { self.nbsp(); self.word_space("else"); + // 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(els); } @@ -1123,20 +1133,7 @@ impl<'a> State<'a> { ) { self.print_qpath(qpath, true); self.word("{"); - self.commasep_cmnt( - Consistent, - fields, - |s, field| { - s.ibox(INDENT_UNIT); - if !field.is_shorthand { - s.print_ident(field.ident); - s.word_space(":"); - } - s.print_expr(field.expr); - s.end() - }, - |f| f.span, - ); + self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span); if let Some(expr) = wth { self.ibox(INDENT_UNIT); if !fields.is_empty() { @@ -1153,6 +1150,20 @@ impl<'a> State<'a> { self.word("}"); } + fn print_expr_field(&mut self, field: &hir::ExprField<'_>) { + if self.attrs(field.hir_id).is_empty() { + self.space(); + } + self.cbox(INDENT_UNIT); + self.print_outer_attributes(&self.attrs(field.hir_id)); + if !field.is_shorthand { + self.print_ident(field.ident); + self.word_space(":"); + } + self.print_expr(&field.expr); + self.end() + } + fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) { self.popen(); self.commasep_exprs(Inconsistent, exprs); @@ -1172,15 +1183,20 @@ impl<'a> State<'a> { self.print_call_post(args) } - fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) { - let base_args = &args[1..]; - self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); + fn print_expr_method_call( + &mut self, + segment: &hir::PathSegment<'_>, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], + ) { + let base_args = args; + self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX); self.word("."); self.print_ident(segment.ident); let generic_args = segment.args(); if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() { - self.print_generic_args(generic_args, segment.infer_args, true); + self.print_generic_args(generic_args, true); } self.print_call_post(base_args) @@ -1240,7 +1256,7 @@ impl<'a> State<'a> { fn print_literal(&mut self, lit: &hir::Lit) { self.maybe_print_comment(lit.span.lo()); - self.word(lit.node.to_lit_token().to_string()) + self.word(lit.node.to_token_lit().to_string()) } fn print_inline_asm(&mut self, asm: &hir::InlineAsm<'_>) { @@ -1385,8 +1401,8 @@ impl<'a> State<'a> { hir::ExprKind::Call(func, args) => { self.print_expr_call(func, args); } - hir::ExprKind::MethodCall(segment, args, _) => { - self.print_expr_method_call(segment, args); + hir::ExprKind::MethodCall(segment, receiver, args, _) => { + self.print_expr_method_call(segment, receiver, args); } hir::ExprKind::Binary(op, lhs, rhs) => { self.print_expr_binary(op, lhs, rhs); @@ -1583,7 +1599,7 @@ impl<'a> State<'a> { } if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args(segment.args(), segment.infer_args, colons_before_params); + self.print_generic_args(segment.args(), colons_before_params); } } } @@ -1591,7 +1607,7 @@ impl<'a> State<'a> { pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args(segment.args(), segment.infer_args, false); + self.print_generic_args(segment.args(), false); } } @@ -1610,11 +1626,7 @@ impl<'a> State<'a> { } if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args( - segment.args(), - segment.infer_args, - colons_before_params, - ); + self.print_generic_args(segment.args(), colons_before_params); } } @@ -1622,11 +1634,7 @@ impl<'a> State<'a> { self.word("::"); let item_segment = path.segments.last().unwrap(); self.print_ident(item_segment.ident); - self.print_generic_args( - item_segment.args(), - item_segment.infer_args, - colons_before_params, - ) + self.print_generic_args(item_segment.args(), colons_before_params) } hir::QPath::TypeRelative(qself, item_segment) => { // If we've got a compound-qualified-path, let's push an additional pair of angle @@ -1642,11 +1650,7 @@ impl<'a> State<'a> { self.word("::"); self.print_ident(item_segment.ident); - self.print_generic_args( - item_segment.args(), - item_segment.infer_args, - colons_before_params, - ) + self.print_generic_args(item_segment.args(), colons_before_params) } hir::QPath::LangItem(lang_item, span, _) => { self.word("#[lang = \""); @@ -1659,7 +1663,6 @@ impl<'a> State<'a> { fn print_generic_args( &mut self, generic_args: &hir::GenericArgs<'_>, - infer_args: bool, colons_before_params: bool, ) { if generic_args.parenthesized { @@ -1706,13 +1709,6 @@ impl<'a> State<'a> { ); } - // FIXME(eddyb): this would leak into error messages (e.g., - // "non-exhaustive patterns: `Some::<..>(_)` not covered"). - if infer_args && false { - start_or_comma(self); - self.word(".."); - } - for binding in generic_args.bindings { start_or_comma(self); self.print_type_binding(binding); @@ -1726,7 +1722,7 @@ impl<'a> State<'a> { pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { self.print_ident(binding.ident); - self.print_generic_args(binding.gen_args, false, false); + self.print_generic_args(binding.gen_args, false); self.space(); match binding.kind { hir::TypeBindingKind::Equality { ref term } => { @@ -1749,20 +1745,12 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.kind { PatKind::Wild => self.word("_"), - PatKind::Binding(binding_mode, _, ident, sub) => { - match binding_mode { - hir::BindingAnnotation::Ref => { - self.word_nbsp("ref"); - self.print_mutability(hir::Mutability::Not, false); - } - hir::BindingAnnotation::RefMut => { - self.word_nbsp("ref"); - self.print_mutability(hir::Mutability::Mut, false); - } - hir::BindingAnnotation::Unannotated => {} - hir::BindingAnnotation::Mutable => { - self.word_nbsp("mut"); - } + PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => { + if by_ref == ByRef::Yes { + self.word_nbsp("ref"); + } + if mutbl == Mutability::Mut { + self.word_nbsp("mut"); } self.print_ident(ident); if let Some(p) = sub { @@ -1773,7 +1761,8 @@ impl<'a> State<'a> { PatKind::TupleStruct(ref qpath, elts, ddpos) => { self.print_qpath(qpath, true); self.popen(); - if let Some(ddpos) = ddpos { + if let Some(ddpos) = ddpos.as_opt_usize() { + let ddpos = ddpos as usize; self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); @@ -1799,20 +1788,7 @@ impl<'a> State<'a> { 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, - ); + self.commasep_cmnt(Consistent, &fields, |s, f| s.print_patfield(f), |f| f.pat.span); if etc { if !fields.is_empty() { self.word_space(","); @@ -1829,7 +1805,7 @@ impl<'a> State<'a> { } PatKind::Tuple(elts, ddpos) => { self.popen(); - if let Some(ddpos) = ddpos { + if let Some(ddpos) = ddpos.as_opt_usize() { self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); @@ -1907,6 +1883,20 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } + pub fn print_patfield(&mut self, field: &hir::PatField<'_>) { + if self.attrs(field.hir_id).is_empty() { + self.space(); + } + self.cbox(INDENT_UNIT); + self.print_outer_attributes(&self.attrs(field.hir_id)); + if !field.is_shorthand { + self.print_ident(field.ident); + self.word_nbsp(":"); + } + self.print_pat(field.pat); + self.end(); + } + pub fn print_param(&mut self, arg: &hir::Param<'_>) { self.print_outer_attributes(self.attrs(arg.hir_id)); self.print_pat(arg.pat); @@ -2403,9 +2393,9 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool { contains_exterior_struct_lit(x) } - hir::ExprKind::MethodCall(.., exprs, _) => { + hir::ExprKind::MethodCall(_, receiver, ..) => { // `X { y: 1 }.bar(...)` - contains_exterior_struct_lit(&exprs[0]) + contains_exterior_struct_lit(receiver) } _ => false, diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 1e88e8091..2c9e21f76 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,7 +2,7 @@ #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 33c3c536f..a00d7bd68 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,7 +1,9 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![feature(allow_internal_unstable)] #![feature(bench_black_box)] #![feature(extend_one)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(new_uninit)] #![feature(step_trait)] diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 30ff36421..4172ce3bb 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -172,7 +172,9 @@ impl IndexVec { } #[inline] - pub fn indices(&self) -> impl DoubleEndedIterator + ExactSizeIterator + 'static { + pub fn indices( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + Clone + 'static { (0..self.len()).map(|n| I::new(n)) } diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 02ac83a5e..aced787d6 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs new file mode 100644 index 000000000..d232a1864 --- /dev/null +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -0,0 +1,499 @@ +use hir::GenericParamKind; +use rustc_errors::{ + fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan, +}; +use rustc_hir as hir; +use rustc_hir::{FnRetTy, Ty}; +use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::{Region, TyCtxt}; +use rustc_span::symbol::kw; +use rustc_span::{symbol::Ident, BytePos, Span}; + +use crate::infer::error_reporting::{ + need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, + ObligationCauseAsDiagArg, +}; + +pub mod note_and_explain; + +#[derive(SessionDiagnostic)] +#[diag(infer::opaque_hidden_type)] +pub struct OpaqueHiddenTypeDiag { + #[primary_span] + #[label] + pub span: Span, + #[note(infer::opaque_type)] + pub opaque_type: Span, + #[note(infer::hidden_type)] + pub hidden_type: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0282")] +pub struct AnnotationRequired<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +// Copy of `AnnotationRequired` for E0283 +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0283")] +pub struct AmbigousImpl<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +// Copy of `AnnotationRequired` for E0284 +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0284")] +pub struct AmbigousReturn<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::need_type_info_in_generator, code = "E0698")] +pub struct NeedTypeInfoInGenerator<'a> { + #[primary_span] + pub span: Span, + pub generator_kind: GeneratorKindAsDiagArg, + #[subdiagnostic] + pub bad_label: InferenceBadError<'a>, +} + +// Used when a better one isn't available +#[derive(SessionSubdiagnostic)] +#[label(infer::label_bad)] +pub struct InferenceBadError<'a> { + #[primary_span] + pub span: Span, + pub bad_kind: &'static str, + pub prefix_kind: UnderspecifiedArgKind, + pub has_parent: bool, + pub prefix: &'a str, + pub parent_prefix: &'a str, + pub parent_name: String, + pub name: String, +} + +#[derive(SessionSubdiagnostic)] +pub enum SourceKindSubdiag<'a> { + #[suggestion_verbose( + infer::source_kind_subdiag_let, + code = ": {type_name}", + applicability = "has-placeholders" + )] + LetLike { + #[primary_span] + span: Span, + name: String, + type_name: String, + kind: &'static str, + x_kind: &'static str, + prefix_kind: UnderspecifiedArgKind, + prefix: &'a str, + arg_name: String, + }, + #[label(infer::source_kind_subdiag_generic_label)] + GenericLabel { + #[primary_span] + span: Span, + is_type: bool, + param_name: String, + parent_exists: bool, + parent_prefix: String, + parent_name: String, + }, + #[suggestion_verbose( + infer::source_kind_subdiag_generic_suggestion, + code = "::<{args}>", + applicability = "has-placeholders" + )] + GenericSuggestion { + #[primary_span] + span: Span, + arg_count: usize, + args: String, + }, +} + +#[derive(SessionSubdiagnostic)] +pub enum SourceKindMultiSuggestion<'a> { + #[multipart_suggestion_verbose( + infer::source_kind_fully_qualified, + applicability = "has-placeholders" + )] + FullyQualified { + #[suggestion_part(code = "{def_path}({adjustment}")] + span_lo: Span, + #[suggestion_part(code = "{successor_pos}")] + span_hi: Span, + def_path: String, + adjustment: &'a str, + successor_pos: &'a str, + }, + #[multipart_suggestion_verbose( + infer::source_kind_closure_return, + applicability = "has-placeholders" + )] + ClosureReturn { + #[suggestion_part(code = "{start_span_code}")] + start_span: Span, + start_span_code: String, + #[suggestion_part(code = " }}")] + end_span: Option, + }, +} + +impl<'a> SourceKindMultiSuggestion<'a> { + pub fn new_fully_qualified( + span: Span, + def_path: String, + adjustment: &'a str, + successor: (&'a str, BytePos), + ) -> Self { + Self::FullyQualified { + span_lo: span.shrink_to_lo(), + span_hi: span.shrink_to_hi().with_hi(successor.1), + def_path, + adjustment, + successor_pos: successor.0, + } + } + + pub fn new_closure_return( + ty_info: String, + data: &'a FnRetTy<'a>, + should_wrap_expr: Option, + ) -> Self { + let (arrow, post) = match data { + FnRetTy::DefaultReturn(_) => ("-> ", " "), + _ => ("", ""), + }; + let (start_span, start_span_code, end_span) = match should_wrap_expr { + Some(end_span) => { + (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span)) + } + None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None), + }; + Self::ClosureReturn { start_span, start_span_code, end_span } + } +} + +pub enum RegionOriginNote<'a> { + Plain { + span: Span, + msg: DiagnosticMessage, + }, + WithName { + span: Span, + msg: DiagnosticMessage, + name: &'a str, + continues: bool, + }, + WithRequirement { + span: Span, + requirement: ObligationCauseAsDiagArg<'a>, + expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>, + }, +} + +impl AddSubdiagnostic for RegionOriginNote<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut label_or_note = |span, msg: DiagnosticMessage| { + let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); + let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); + let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); + if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { + diag.span_label(span, msg); + } else if span_is_primary && expanded_sub_count == 0 { + diag.note(msg); + } else { + diag.span_note(span, msg); + } + }; + match self { + RegionOriginNote::Plain { span, msg } => { + label_or_note(span, msg); + } + RegionOriginNote::WithName { span, msg, name, continues } => { + label_or_note(span, msg); + diag.set_arg("name", name); + diag.set_arg("continues", continues); + } + RegionOriginNote::WithRequirement { + span, + requirement, + expected_found: Some((expected, found)), + } => { + label_or_note(span, fluent::infer::subtype); + diag.set_arg("requirement", requirement); + + diag.note_expected_found(&"", expected, &"", found); + } + RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. + label_or_note(span, fluent::infer::subtype_2); + diag.set_arg("requirement", requirement); + } + }; + } +} + +pub enum LifetimeMismatchLabels { + InRet { + param_span: Span, + ret_span: Span, + span: Span, + label_var1: Option, + }, + Normal { + hir_equal: bool, + ty_sup: Span, + ty_sub: Span, + span: Span, + sup: Option, + sub: Option, + }, +} + +impl AddSubdiagnostic for LifetimeMismatchLabels { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { + diag.span_label(param_span, fluent::infer::declared_different); + diag.span_label(ret_span, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_returned); + diag.set_arg("label_var1_exists", label_var1.is_some()); + diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + } + LifetimeMismatchLabels::Normal { + hir_equal, + ty_sup, + ty_sub, + span, + sup: label_var1, + sub: label_var2, + } => { + if hir_equal { + diag.span_label(ty_sup, fluent::infer::declared_multiple); + diag.span_label(ty_sub, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_lifetime_flow); + } else { + diag.span_label(ty_sup, fluent::infer::types_declared_different); + diag.span_label(ty_sub, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_flows); + diag.set_arg("label_var1_exists", label_var1.is_some()); + diag.set_arg( + "label_var1", + label_var1.map(|x| x.to_string()).unwrap_or_default(), + ); + diag.set_arg("label_var2_exists", label_var2.is_some()); + diag.set_arg( + "label_var2", + label_var2.map(|x| x.to_string()).unwrap_or_default(), + ); + } + } + } + } +} + +pub struct AddLifetimeParamsSuggestion<'a> { + pub tcx: TyCtxt<'a>, + pub sub: Region<'a>, + pub ty_sup: &'a Ty<'a>, + pub ty_sub: &'a Ty<'a>, + pub add_note: bool, +} + +impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut mk_suggestion = || { + let ( + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, + ) = (self.ty_sub, self.ty_sup) else { + return false; + }; + + if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { + return false; + }; + + let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else { + return false; + }; + + let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); + + let node = self.tcx.hir().get(hir_id); + let is_impl = matches!(&node, hir::Node::ImplItem(_)); + let generics = match node { + hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(_, ref generics, ..), + .. + }) + | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, + _ => return false, + }; + + let suggestion_param_name = generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + let introduce_new = suggestion_param_name.is_none(); + let suggestion_param_name = + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); + + debug!(?lifetime_sup.span); + debug!(?lifetime_sub.span); + let make_suggestion = |span: rustc_span::Span| { + if span.is_empty() { + (span, format!("{}, ", suggestion_param_name)) + } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref() + { + (span.shrink_to_hi(), format!("{} ", suggestion_param_name)) + } else { + (span, suggestion_param_name.clone()) + } + }; + let mut suggestions = + vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)]; + + if introduce_new { + let new_param_suggestion = if let Some(first) = + generics.params.iter().find(|p| !p.name.ident().span.is_empty()) + { + (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) + } else { + (generics.span, format!("<{}>", suggestion_param_name)) + }; + + suggestions.push(new_param_suggestion); + } + + diag.multipart_suggestion( + fluent::infer::lifetime_param_suggestion, + suggestions, + Applicability::MaybeIncorrect, + ); + diag.set_arg("is_impl", is_impl); + true + }; + if mk_suggestion() && self.add_note { + diag.note(fluent::infer::lifetime_param_suggestion_elided); + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(infer::lifetime_mismatch, code = "E0623")] +pub struct LifetimeMismatch<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub labels: LifetimeMismatchLabels, + #[subdiagnostic] + pub suggestion: AddLifetimeParamsSuggestion<'a>, +} + +pub struct IntroducesStaticBecauseUnmetLifetimeReq { + pub unmet_requirements: MultiSpan, + pub binding_span: Span, +} + +impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { + fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + self.unmet_requirements + .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); + diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req); + } +} + +pub struct ImplNote { + pub impl_span: Option, +} + +impl AddSubdiagnostic for ImplNote { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self.impl_span { + Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), + None => diag.note(fluent::infer::msl_impl_note), + }; + } +} + +pub enum TraitSubdiag { + Note { span: Span }, + Sugg { span: Span }, +} + +// FIXME(#100717) used in `Vec` so requires eager translation/list support +impl AddSubdiagnostic for TraitSubdiag { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + TraitSubdiag::Note { span } => { + diag.span_note(span, "this has an implicit `'static` lifetime requirement"); + } + TraitSubdiag::Sugg { span } => { + diag.span_suggestion_verbose( + span, + "consider relaxing the implicit `'static` requirement", + " + '_".to_owned(), + rustc_errors::Applicability::MaybeIncorrect, + ); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(infer::mismatched_static_lifetime)] +pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, + #[subdiagnostic] + pub expl: Option>, + #[subdiagnostic] + pub impl_note: ImplNote, + #[subdiagnostic] + pub trait_subdiags: Vec, +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs new file mode 100644 index 000000000..7e051835b --- /dev/null +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -0,0 +1,172 @@ +use crate::infer::error_reporting::nice_region_error::find_anon_type; +use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{symbol::kw, Span}; + +#[derive(Default)] +struct DescriptionCtx<'a> { + span: Option, + kind: &'a str, + arg: String, + num_arg: u32, +} + +impl<'a> DescriptionCtx<'a> { + fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option, + ) -> Option { + let mut me = DescriptionCtx::default(); + me.span = alt_span; + match *region { + ty::ReEarlyBound(_) | ty::ReFree(_) => { + return Self::from_early_bound_and_free_regions(tcx, region); + } + ty::ReStatic => { + me.kind = "restatic"; + } + + ty::RePlaceholder(_) => return None, + + // FIXME(#13998) RePlaceholder should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound though. + ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { + me.kind = "revar"; + me.arg = format!("{:?}", region); + } + }; + Some(me) + } + + fn from_early_bound_and_free_regions<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ) -> Option { + let mut me = DescriptionCtx::default(); + let scope = region.free_region_binding_scope(tcx).expect_local(); + match *region { + ty::ReEarlyBound(ref br) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + sp = param.span; + } + if br.has_name() { + me.kind = "as_defined"; + me.arg = br.name.to_string(); + } else { + me.kind = "as_defined_anon"; + }; + me.span = Some(sp) + } + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + { + me.kind = "defined_here"; + me.span = Some(ty.span); + } else { + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + sp = param.span; + } + if name == kw::UnderscoreLifetime { + me.kind = "as_defined_anon"; + } else { + me.kind = "as_defined"; + me.arg = name.to_string(); + }; + me.span = Some(sp); + } + ty::BrAnon(idx) => { + me.kind = "anon_num_here"; + me.num_arg = idx+1; + me.span = Some(tcx.def_span(scope)); + }, + _ => { + me.kind = "defined_here_reg"; + me.arg = region.to_string(); + me.span = Some(tcx.def_span(scope)); + }, + } + } + } + _ => bug!(), + } + Some(me) + } + + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + diag.set_arg("desc_kind", self.kind); + diag.set_arg("desc_arg", self.arg); + diag.set_arg("desc_num_arg", self.num_arg); + } +} + +pub enum PrefixKind { + Empty, +} + +pub enum SuffixKind { + Continues, +} + +impl IntoDiagnosticArg for PrefixKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { + Self::Empty => "empty", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) + } +} + +impl IntoDiagnosticArg for SuffixKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { + Self::Continues => "continues", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) + } +} + +pub struct RegionExplanation<'a> { + desc: DescriptionCtx<'a>, + prefix: PrefixKind, + suffix: SuffixKind, +} + +impl RegionExplanation<'_> { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option, + prefix: PrefixKind, + suffix: SuffixKind, + ) -> Option { + Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix }) + } +} + +impl AddSubdiagnostic for RegionExplanation<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + if let Some(span) = self.desc.span { + diag.span_note(span, fluent::infer::region_explanation); + } else { + diag.note(fluent::infer::region_explanation); + } + self.desc.add_to(diag); + diag.set_arg("pref_kind", self.prefix); + diag.set_arg("suff_kind", self.suffix); + } +} diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 130214a65..00e238648 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -74,10 +74,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { evaluation_cache: self.evaluation_cache.clone(), reported_trait_errors: self.reported_trait_errors.clone(), reported_closure_mismatch: self.reported_closure_mismatch.clone(), - tainted_by_errors_flag: self.tainted_by_errors_flag.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), err_count_on_creation: self.err_count_on_creation, in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), + normalize_fn_sig_for_diagnostic: self + .normalize_fn_sig_for_diagnostic + .as_ref() + .map(|f| f.clone()), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ca7862c9d..9488d0a6c 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -180,11 +180,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { match *r { - ty::ReFree(_) - | ty::ReErased - | ty::ReStatic - | ty::ReEmpty(ty::UniverseIndex::ROOT) - | ty::ReEarlyBound(..) => r, + ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r, ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) }, @@ -199,10 +195,6 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { ) } - ty::ReEmpty(ui) => { - bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME - } - _ => { // Other than `'static` or `'empty`, the query // response should be executing in a fully @@ -372,7 +364,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { debug!( "canonical: region var found with vid {:?}, \ opportunistically resolved to {:?}", - vid, r + vid, resolved_vid ); let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid)); self.canonicalize_mode.canonicalize_free_region(self, r) @@ -381,7 +373,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ty::ReStatic | ty::ReEarlyBound(..) | ty::ReFree(_) - | ty::ReEmpty(_) | ty::RePlaceholder(..) | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r), } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 8dc20544f..56e834898 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -22,6 +22,7 @@ use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; @@ -63,8 +64,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; + debug!("query_response = {:#?}", query_response); let canonical_result = self.canonicalize_response(query_response); - debug!("canonical_result = {:#?}", canonical_result); Ok(self.tcx.arena.alloc(canonical_result)) @@ -125,13 +126,17 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { debug!("ambig_errors = {:#?}", ambig_errors); let region_obligations = self.take_registered_region_obligations(); + debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( tcx, - region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), region_constraints, ) }); + debug!(?region_constraints); let certainty = if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; @@ -246,6 +251,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // the original values `v_o` that was canonicalized into a // variable... + let constraint_category = cause.to_constraint_category(); + for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { @@ -261,12 +268,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. if v_o != v_r { - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r))); - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o))); + output_query_region_constraints.outlives.push(( + ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)), + constraint_category, + )); + output_query_region_constraints.outlives.push(( + ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)), + constraint_category, + )); } } @@ -312,7 +321,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Screen out `'a: 'a` cases -- we skip the binder here but // only compare the inner values to one another, so they are still at // consistent binding levels. - let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder(); if k1 != r2.into() { Some(r_c) } else { None } }), ); @@ -557,7 +566,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Obligation<'tcx, ty::Predicate<'tcx>> { - let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder(); let atom = match k1.unpack() { GenericArgKind::Lifetime(r1) => { @@ -572,7 +581,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { span_bug!(cause.span, "unexpected const outlives {:?}", predicate); } }; - let predicate = predicate.rebind(atom).to_predicate(self.tcx); + let predicate = predicate.0.rebind(atom).to_predicate(self.tcx); Obligation::new(cause, param_env, predicate) } @@ -623,7 +632,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// creates query region constraints. pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, - outlives_obligations: impl Iterator, ty::Region<'tcx>)>, + outlives_obligations: impl Iterator, ty::Region<'tcx>, ConstraintCategory<'tcx>)>, region_constraints: &RegionConstraintData<'tcx>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys, givens, member_constraints } = @@ -632,28 +641,35 @@ pub fn make_query_region_constraints<'tcx>( assert!(verifys.is_empty()); assert!(givens.is_empty()); + debug!(?constraints); + let outlives: Vec<_> = constraints .iter() - .map(|(k, _)| match *k { - // Swap regions because we are going from sub (<=) to outlives - // (>=). - Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( - tcx.mk_region(ty::ReVar(v2)).into(), - tcx.mk_region(ty::ReVar(v1)), - ), - Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) - } - Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) - } - Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), + .map(|(k, origin)| { + // no bound vars in the code above + let constraint = ty::Binder::dummy(match *k { + // Swap regions because we are going from sub (<=) to outlives + // (>=). + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + tcx.mk_region(ty::ReVar(v2)).into(), + tcx.mk_region(ty::ReVar(v1)), + ), + Constraint::VarSubReg(v1, r2) => { + ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) + } + Constraint::RegSubVar(r1, v2) => { + ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) + } + Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), + }); + (constraint, origin.to_constraint_category()) }) - .map(ty::Binder::dummy) // no bound vars in the code above .chain( outlives_obligations - .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r)) - .map(ty::Binder::dummy), // no bound vars in the code above + // no bound vars in the code above + .map(|(ty, r, constraint_category)| { + (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category) + }), ) .collect(); diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 34b611342..389afe22e 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -72,15 +72,16 @@ where value } else { let delegate = FnMutDelegate { - regions: |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { + regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { GenericArgKind::Lifetime(l) => l, r => bug!("{:?} is a region but value is {:?}", br, r), }, - types: |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { + types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), }, - consts: |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() { + consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() + { GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 8bf1de34a..c406df9e4 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -391,7 +391,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { /// Preconditions: /// /// - `for_vid` is a "root vid" - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn generalize( &self, ty: Ty<'tcx>, @@ -435,15 +435,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { cache: SsoHashMap::new(), }; - let ty = match generalize.relate(ty, ty) { - Ok(ty) => ty, - Err(e) => { - debug!(?e, "failure"); - return Err(e); - } - }; + let ty = generalize.relate(ty, ty)?; let needs_wf = generalize.needs_wf; - trace!(?ty, ?needs_wf, "success"); Ok(Generalization { ty, needs_wf }) } @@ -493,12 +486,13 @@ struct Generalizer<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, - cache: SsoHashMap, RelateResult<'tcx, Ty<'tcx>>>, + cache: SsoHashMap, Ty<'tcx>>, } /// Result from a generalization operation. This includes /// not only the generalized type, but also a bool flag /// indicating whether further WF checks are needed. +#[derive(Debug)] struct Generalization<'tcx> { ty: Ty<'tcx>, @@ -599,8 +593,8 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - if let Some(result) = self.cache.get(&t) { - return result.clone(); + if let Some(&result) = self.cache.get(&t) { + return Ok(result); } debug!("generalize: t={:?}", t); @@ -670,10 +664,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { Ok(t) } _ => relate::super_relate_tys(self, t, t), - }; + }?; - self.cache.insert(t, result.clone()); - return result; + self.cache.insert(t, result); + Ok(result) } fn regions( @@ -694,7 +688,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { ty::RePlaceholder(..) | ty::ReVar(..) - | ty::ReEmpty(_) | ty::ReStatic | ty::ReEarlyBound(..) | ty::ReFree(..) => { @@ -749,10 +742,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { + assert_eq!(promoted, ()); + let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -856,10 +848,9 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug_assert_eq!(t, _t); - debug!("ConstInferUnifier: t={:?}", t); match t.kind() { &ty::Infer(ty::TyVar(vid)) => { @@ -883,12 +874,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { .borrow_mut() .type_variables() .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); - debug!( - "ConstInferUnifier: replacing original vid={:?} with new={:?}", - vid, u - ); - Ok(u) + Ok(self.tcx().mk_ty_var(new_var_id)) } } } @@ -914,7 +900,6 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { ty::RePlaceholder(..) | ty::ReVar(..) - | ty::ReEmpty(_) | ty::ReStatic | ty::ReEarlyBound(..) | ty::ReFree(..) => { @@ -932,14 +917,13 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn consts( &mut self, c: ty::Const<'tcx>, _c: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug_assert_eq!(c, _c); - debug!("ConstInferUnifier: c={:?}", c); match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { @@ -980,16 +964,16 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { - assert_eq!(promoted, None); + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { + assert_eq!(promoted, ()); + let substs = self.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), substs, substs, )?; + Ok(self.tcx().mk_const(ty::ConstS { ty: c.ty(), kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 20864c657..eb5afe828 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,14 +58,16 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::{ self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, @@ -77,7 +79,7 @@ use std::{cmp, fmt, iter}; mod note; -mod need_type_info; +pub(crate) mod need_type_info; pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; @@ -95,11 +97,6 @@ pub(super) fn note_and_explain_region<'tcx>( msg_span_from_free_region(tcx, region, alt_span) } - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span), - - // uh oh, hope no user ever sees THIS - ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span), - ty::RePlaceholder(_) => return, // FIXME(#13998) RePlaceholder should probably print like @@ -138,8 +135,6 @@ fn msg_span_from_free_region<'tcx>( (msg, Some(span)) } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span), - ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span), _ => bug!("{:?}", region), } } @@ -249,17 +244,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( // Explain the region we are capturing. match *hidden_region { - ty::ReEmpty(ty::UniverseIndex::ROOT) => { - // All lifetimes shorter than the function body are `empty` in - // lexical region resolution. The default explanation of "an empty - // lifetime" isn't really accurate here. - let message = format!( - "hidden type `{}` captures lifetime smaller than the function body", - hidden_ty - ); - err.span_note(span, &message); - } - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => { + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { // Assuming regionck succeeded (*), we ought to always be // capturing *some* region from the fn header, and hence it // ought to be free. So under normal circumstances, we will go @@ -385,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::UpperBoundUniverseConflict( _, _, - var_universe, + _, sup_origin, sup_r, ) => { @@ -396,7 +381,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // placeholder. In practice, we expect more // tailored errors that don't really use this // value. - let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); + let sub_r = self.tcx.lifetimes.re_erased; self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } @@ -457,7 +442,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: &TypeError<'tcx>) { + fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: TypeError<'tcx>) { use hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use ty::print::Printer; @@ -561,7 +546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } }; - match *terr { + match terr { TypeError::Sorts(ref exp_found) => { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate @@ -583,7 +568,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut Diagnostic, cause: &ObligationCause<'tcx>, exp_found: Option>>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, ) { match *cause.code() { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -739,12 +724,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("...or use `match` instead of `let...else`"); } _ => { - if let ObligationCauseCode::BindingObligation(_, binding_span) = - cause.code().peel_derives() + if let ObligationCauseCode::BindingObligation(_, span) + | ObligationCauseCode::ExprBindingObligation(_, span, ..) + = cause.code().peel_derives() + && let TypeError::RegionsPlaceholderMismatch = terr { - if matches!(terr, TypeError::RegionsPlaceholderMismatch) { - err.span_note(*binding_span, "the lifetime requirement is introduced here"); - } + err.span_note(*span, "the lifetime requirement is introduced here"); } } } @@ -960,12 +945,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> { + if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic { + normalize(self, sig) + } else { + sig + } + } + /// Given two `fn` signatures highlight only sub-parts that are different. fn cmp_fn_sig( &self, sig1: &ty::PolyFnSig<'tcx>, sig2: &ty::PolyFnSig<'tcx>, ) -> (DiagnosticStyledString, DiagnosticStyledString) { + let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1); + let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2); + let get_lifetimes = |sig| { use rustc_hir::def::Namespace; let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS) @@ -1422,9 +1418,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on /// E0271, like `src/test/ui/issues/issue-39970.stderr`. - #[tracing::instrument( + #[instrument( level = "debug", - skip(self, diag, secondary_span, swap_secondary_and_primary, force_label) + skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label) )] pub fn note_type_err( &self, @@ -1432,9 +1428,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, String)>, mut values: Option>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, swap_secondary_and_primary: bool, - force_label: bool, + prefer_label: bool, ) { let span = cause.span(); @@ -1574,23 +1570,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(values) => { let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { - ValuePairs::Terms(infer::ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) => { - let is_simple_err = expected.is_simple_text() && found.is_simple_text(); - OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) - .report(diag); - - ( - is_simple_err, - Mismatch::Variable(infer::ExpectedFound { expected, found }), - ) + ValuePairs::Terms(infer::ExpectedFound { expected, found }) => { + match (expected.unpack(), found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { + let is_simple_err = + expected.is_simple_text() && found.is_simple_text(); + OpaqueTypesVisitor::visit_expected_found( + self.tcx, expected, found, span, + ) + .report(diag); + + ( + is_simple_err, + Mismatch::Variable(infer::ExpectedFound { expected, found }), + ) + } + (ty::TermKind::Const(_), ty::TermKind::Const(_)) => { + (false, Mismatch::Fixed("constant")) + } + _ => (false, Mismatch::Fixed("type")), + } } ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { (false, Mismatch::Fixed("trait")) } - _ => (false, Mismatch::Fixed("type")), + ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), }; let vals = match self.values_str(values) { Some((expected, found)) => Some((expected, found)), @@ -1612,7 +1616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { TypeError::ObjectUnsafeCoercion(_) => {} _ => { let mut label_or_note = |span: Span, msg: &str| { - if force_label || &[span] == diag.span.primary_spans() { + if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() { diag.span_label(span, msg); } else { diag.span_note(span, msg); @@ -1662,6 +1666,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pos.col.to_usize() + 1, ) } + (true, ty::Projection(proj)) + if self.tcx.def_kind(proj.item_def_id) + == DefKind::ImplTraitPlaceholder => + { + let sm = self.tcx.sess.source_map(); + let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo()); + format!( + " (trait associated opaque type at <{}:{}:{}>)", + sm.filename_for_diagnostics(&pos.file.name), + pos.line, + pos.col.to_usize() + 1, + ) + } (true, _) => format!(" ({})", ty.sort_string(self.tcx)), (false, _) => "".to_string(), }; @@ -1713,7 +1730,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::error::TypeError::Sorts(terr) if exp_found.map_or(false, |ef| terr.found == ef.found) => { - Some(*terr) + Some(terr) } _ => exp_found, }; @@ -1750,6 +1767,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() && let Some(def_id) = def_id.as_local() + && terr.involves_regions() { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); @@ -2037,22 +2055,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (exp_found.expected.kind(), exp_found.found.kind()) { if let ty::Adt(found_def, found_substs) = *found_ty.kind() { - let path_str = format!("{:?}", exp_def); if exp_def == &found_def { - let opt_msg = "you can convert from `&Option` to `Option<&T>` using \ - `.as_ref()`"; - let result_msg = "you can convert from `&Result` to \ - `Result<&T, &E>` using `.as_ref()`"; let have_as_ref = &[ - ("std::option::Option", opt_msg), - ("core::option::Option", opt_msg), - ("std::result::Result", result_msg), - ("core::result::Result", result_msg), + ( + sym::Option, + "you can convert from `&Option` to `Option<&T>` using \ + `.as_ref()`", + ), + ( + sym::Result, + "you can convert from `&Result` to \ + `Result<&T, &E>` using `.as_ref()`", + ), ]; - if let Some(msg) = have_as_ref - .iter() - .find_map(|(path, msg)| (&path_str == path).then_some(msg)) - { + if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| { + self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg) + }) { let mut show_suggestion = true; for (exp_ty, found_ty) in iter::zip(exp_substs.types(), found_substs.types()) @@ -2078,7 +2096,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.span_suggestion( span, *msg, - format!("{}.as_ref()", snippet), + // HACK: fix issue# 100605, suggesting convert from &Option to Option<&T>, remove the extra `&` + format!("{}.as_ref()", snippet.trim_start_matches('&')), Applicability::MachineApplicable, ); } @@ -2091,7 +2110,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_and_explain_type_error( &self, trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { use crate::traits::ObligationCauseCode::MatchExpressionArm; @@ -2254,11 +2273,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return None; } - Some(match (exp_found.expected, exp_found.found) { - (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found), - (expected, found) => ( - DiagnosticStyledString::highlighted(expected.to_string()), - DiagnosticStyledString::highlighted(found.to_string()), + Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found), + _ => ( + DiagnosticStyledString::highlighted(exp_found.expected.to_string()), + DiagnosticStyledString::highlighted(exp_found.found.to_string()), ), }) } @@ -2376,19 +2395,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { type_param_span: Option<(Span, bool)>, bound_kind: GenericKind<'tcx>, sub: S, + add_lt_sugg: Option<(Span, String)>, ) { let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes)) = type_param_span { let suggestion = if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; - err.span_suggestion_verbose( - sp, - &format!("{}...", msg), - suggestion, + let mut suggestions = vec![(sp, suggestion)]; + if let Some(add_lt_sugg) = add_lt_sugg { + suggestions.push(add_lt_sugg); + } + err.multipart_suggestion_verbose( + format!("{msg}..."), + suggestions, Applicability::MaybeIncorrect, // Issue #41966 ); } else { - let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,); + let consider = format!("{} `{}: {}`...", msg, bound_kind, sub); err.help(&consider); } } @@ -2404,7 +2427,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let mut sugg = vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; - if let Some(lt) = add_lt_sugg { + if let Some(lt) = add_lt_sugg.clone() { sugg.push(lt); sugg.rotate_right(1); } @@ -2510,7 +2533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name); + binding_suggestion(&mut err, type_param_span, bound_kind, name, None); err } @@ -2523,7 +2546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{} may not live long enough", labeled_user_string ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None); err } @@ -2557,7 +2580,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { new_binding_suggestion(&mut err, type_param_span); } _ => { - binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); + binding_suggestion( + &mut err, + type_param_span, + bound_kind, + new_lt, + add_lt_sugg, + ); } } } @@ -2659,67 +2688,95 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Float types, respectively). When comparing two ADTs, these rules apply recursively. pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); - match (a.kind(), b.kind()) { - (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { - if def_a != def_b { - return false; - } + SameTypeModuloInfer(self).relate(a, b).is_ok() + } +} - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { - if did_a != did_b { - return false; - } +struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>); - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) +impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.0.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + // Unused, only for consts which we treat as always equal + ty::ParamEnv::empty() + } + + fn tag(&self) -> &'static str { + "SameTypeModuloInfer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> relate::RelateResult<'tcx, T> { + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + match (a.kind(), b.kind()) { + (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_))) | ( - &ty::Infer(ty::InferTy::IntVar(_)), - &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), + ty::Infer(ty::InferTy::IntVar(_)), + ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)), ) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_))) | ( - &ty::Infer(ty::InferTy::FloatVar(_)), - &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ty::Infer(ty::InferTy::FloatVar(_)), + ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), ) - | (&ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { - mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) - } - (&ty::RawPtr(a), &ty::RawPtr(b)) => { - a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) - } - (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), - (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { - self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct - } - (&ty::Tuple(a), &ty::Tuple(b)) => { - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnPtr(a), &ty::FnPtr(b)) => { - let a = a.skip_binder().inputs_and_output; - let b = b.skip_binder().inputs_and_output; - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - // FIXME(compiler-errors): This needs to be generalized more - _ => a == b, + | (ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), + (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), + _ => relate::super_relate_tys(self, a, b), + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + if (a.is_var() && b.is_free_or_static()) + || (b.is_var() && a.is_free_or_static()) + || (a.is_var() && b.is_var()) + || a == b + { + Ok(a) + } else { + Err(TypeError::Mismatch) } } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: relate::Relate<'tcx>, + { + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + _b: ty::Const<'tcx>, + ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> { + // FIXME(compiler-errors): This could at least do some first-order + // relation + Ok(a) + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -2781,12 +2838,12 @@ pub enum FailureCode { } pub trait ObligationCauseExt<'tcx> { - fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode; + fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; fn as_requirement_str(&self) -> &'static str; } impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { - fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { + fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; match self.code() { @@ -2823,7 +2880,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { TypeError::IntrinsicCast => { Error0308("cannot coerce intrinsics to function pointers") } - TypeError::ObjectUnsafeCoercion(did) => Error0038(*did), + TypeError::ObjectUnsafeCoercion(did) => Error0038(did), _ => Error0308("mismatched types"), }, } @@ -2853,6 +2910,30 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { } } +/// Newtype to allow implementing IntoDiagnosticArg +pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); + +impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + use crate::traits::ObligationCauseCode::*; + let kind = match self.0.code() { + CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", + CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", + CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", + ExprAssignable => "expr_assignable", + IfExpression { .. } => "if_else_different", + IfExpressionWithNoElse => "no_else", + MainFunctionType => "fn_main_correct_type", + StartFunctionType => "fn_start_correct_type", + IntrinsicType => "intristic_correct_type", + MethodReceiver => "method_correct_type", + _ => "other", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) + } +} + /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. #[derive(Clone, Copy, PartialEq, Eq, Hash)] diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 561d1354e..cb2be9358 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,6 +1,10 @@ +use crate::errors::{ + AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, + SourceKindMultiSuggestion, SourceKindSubdiag, +}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -14,6 +18,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; +use rustc_session::SessionDiagnostic; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; @@ -60,38 +65,49 @@ pub struct InferenceDiagnosticsParentData { name: String, } +#[derive(Clone)] pub enum UnderspecifiedArgKind { Type { prefix: Cow<'static, str> }, Const { is_parameter: bool }, } impl InferenceDiagnosticsData { - /// Generate a label for a generic argument which can't be inferred. When not - /// much is known about the argument, `use_diag` may be used to describe the - /// labeled value. - fn cannot_infer_msg(&self) -> String { - if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) { - return "cannot infer type".to_string(); - } - - let suffix = match &self.parent { - Some(parent) => parent.suffix_string(), - None => String::new(), - }; - - // For example: "cannot infer type for type parameter `T`" - format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix) + fn can_add_more_info(&self) -> bool { + !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. })) } - fn where_x_is_specified(&self, in_type: Ty<'_>) -> String { + fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { if in_type.is_ty_infer() { - String::new() + "empty" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. - ", where the placeholders `_` are specified".to_string() + "underscore" } else { - format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name) + "has_name" + } + } + + /// Generate a label for a generic argument which can't be inferred. When not + /// much is known about the argument, `use_diag` may be used to describe the + /// labeled value. + fn make_bad_error(&self, span: Span) -> InferenceBadError<'_> { + let has_parent = self.parent.is_some(); + let bad_kind = if self.can_add_more_info() { "more_info" } else { "other" }; + let (parent_prefix, parent_name) = self + .parent + .as_ref() + .map(|parent| (parent.prefix, parent.name.clone())) + .unwrap_or_default(); + InferenceBadError { + span, + bad_kind, + prefix_kind: self.kind.clone(), + prefix: self.kind.try_get_prefix().unwrap_or_default(), + name: self.name.clone(), + has_parent, + parent_prefix, + parent_name, } } } @@ -113,18 +129,24 @@ impl InferenceDiagnosticsParentData { fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { Self::for_parent_def_id(tcx, tcx.parent(def_id)) } +} - fn suffix_string(&self) -> String { - format!(" declared on the {} `{}`", self.prefix, self.name) +impl IntoDiagnosticArg for UnderspecifiedArgKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { + Self::Type { .. } => "type", + Self::Const { is_parameter: true } => "const_with_param", + Self::Const { is_parameter: false } => "const", + }; + rustc_errors::DiagnosticArgValue::Str(kind.into()) } } impl UnderspecifiedArgKind { - fn prefix_string(&self) -> Cow<'static, str> { + fn try_get_prefix(&self) -> Option<&str> { match self { - Self::Type { prefix } => format!("type for {}", prefix).into(), - Self::Const { is_parameter: true } => "the value of const parameter".into(), - Self::Const { is_parameter: false } => "the value of the constant".into(), + Self::Type { prefix } => Some(prefix.as_ref()), + Self::Const { .. } => None, } } } @@ -177,7 +199,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { } /// We don't want to directly use `ty_to_string` for closures as their type isn't really -/// something users are familar with. Directly printing the `fn_sig` of closures also +/// something users are familiar with. Directly printing the `fn_sig` of closures also /// doesn't work as they actually use the "rust-call" API. fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { let ty::Closure(_, substs) = ty.kind() else { unreachable!() }; @@ -303,11 +325,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let error_code = error_code.into(); - let mut err = - self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); - err.span_label(span, arg_data.cannot_infer_msg()); - err + let source_kind = "other"; + let source_name = ""; + let failure_span = None; + let infer_subdiags = Vec::new(); + let multi_suggestions = Vec::new(); + let bad_label = Some(arg_data.make_bad_error(span)); + match error_code { + TypeAnnotationNeeded::E0282 => AnnotationRequired { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + TypeAnnotationNeeded::E0283 => AmbigousImpl { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + TypeAnnotationNeeded::E0284 => AmbigousReturn { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + } } pub fn emit_inference_failure_err( @@ -340,48 +395,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code) }; - let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - span, - &format!("type annotations needed{}", kind.ty_msg(self)), - error_code, - ); - - if should_label_span && !failure_span.overlaps(span) { - err.span_label(failure_span, "type must be known at this point"); - } + let (source_kind, name) = kind.ty_localized_msg(self); + let failure_span = if should_label_span && !failure_span.overlaps(span) { + Some(failure_span) + } else { + None + }; + let mut infer_subdiags = Vec::new(); + let mut multi_suggestions = Vec::new(); match kind { InferSourceKind::LetBinding { insert_span, pattern_name, ty } => { - let suggestion_msg = if let Some(name) = pattern_name { - format!( - "consider giving `{}` an explicit type{}", - name, - arg_data.where_x_is_specified(ty) - ) - } else { - format!( - "consider giving this pattern a type{}", - arg_data.where_x_is_specified(ty) - ) - }; - err.span_suggestion_verbose( - insert_span, - &suggestion_msg, - format!(": {}", ty_to_string(self, ty)), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::LetLike { + span: insert_span, + name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), + x_kind: arg_data.where_x_is_kind(ty), + prefix_kind: arg_data.kind.clone(), + prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), + arg_name: arg_data.name, + kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, + type_name: ty_to_string(self, ty), + }); } InferSourceKind::ClosureArg { insert_span, ty } => { - err.span_suggestion_verbose( - insert_span, - &format!( - "consider giving this closure parameter an explicit type{}", - arg_data.where_x_is_specified(ty) - ), - format!(": {}", ty_to_string(self, ty)), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::LetLike { + span: insert_span, + name: String::new(), + x_kind: arg_data.where_x_is_kind(ty), + prefix_kind: arg_data.kind.clone(), + prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), + arg_name: arg_data.name, + kind: "closure", + type_name: ty_to_string(self, ty), + }); } InferSourceKind::GenericArg { insert_span, @@ -393,19 +439,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(generics_def_id); let is_type = matches!(arg.unpack(), GenericArgKind::Type(_)); - let cannot_infer_msg = format!( - "cannot infer {} of the {} parameter `{}`{}", - if is_type { "type" } else { "the value" }, - if is_type { "type" } else { "const" }, - generics.params[argument_index].name, - // We use the `generics_def_id` here, as even when suggesting `None::`, - // the type parameter `T` was still declared on the enum, not on the - // variant. + let (parent_exists, parent_prefix, parent_name) = InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id) - .map_or(String::new(), |parent| parent.suffix_string()), - ); + .map_or((false, String::new(), String::new()), |parent| { + (true, parent.prefix.to_string(), parent.name) + }); - err.span_label(span, cannot_infer_msg); + infer_subdiags.push(SourceKindSubdiag::GenericLabel { + span, + is_type, + param_name: generics.params[argument_index].name.to_string(), + parent_exists, + parent_prefix, + parent_name, + }); let args = fmt_printer(self, Namespace::TypeNS) .comma_sep(generic_args.iter().copied().map(|arg| { @@ -435,15 +482,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .unwrap() .into_buffer(); - err.span_suggestion_verbose( - insert_span, - &format!( - "consider specifying the generic argument{}", - pluralize!(generic_args.len()), - ), - format!("::<{}>", args), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::GenericSuggestion { + span: insert_span, + arg_count: generic_args.len(), + args, + }); } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => { let printer = fmt_printer(self, Namespace::ValueNS); @@ -468,37 +511,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => "", }; - let suggestion = vec![ - (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")), - (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()), - ]; - err.multipart_suggestion_verbose( - "try using a fully qualified path to specify the expected types", - suggestion, - Applicability::HasPlaceholders, - ); + multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified( + receiver.span, + def_path, + adjustment, + successor, + )); } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let ret = ty_to_string(self, ty); - let (arrow, post) = match data { - FnRetTy::DefaultReturn(_) => ("-> ", " "), - _ => ("", ""), - }; - let suggestion = match should_wrap_expr { - Some(end_span) => vec![ - (data.span(), format!("{}{}{}{{ ", arrow, ret, post)), - (end_span, " }".to_string()), - ], - None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))], - }; - err.multipart_suggestion_verbose( - "try giving this closure an explicit return type", - suggestion, - Applicability::HasPlaceholders, - ); + let ty_info = ty_to_string(self, ty); + multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( + ty_info, + data, + should_wrap_expr, + )); + } + } + match error_code { + TypeAnnotationNeeded::E0282 => AnnotationRequired { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + TypeAnnotationNeeded::E0283 => AmbigousImpl { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + TypeAnnotationNeeded::E0284 => AmbigousReturn { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), } - err } pub fn need_type_info_err_in_generator( @@ -510,15 +570,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); - let mut err = struct_span_err!( - self.tcx.sess, + NeedTypeInfoInGenerator { + bad_label: data.make_bad_error(span), span, - E0698, - "type inside {} must be known in this context", - kind, - ); - err.span_label(span, data.cannot_infer_msg()); - err + generator_kind: GeneratorKindAsDiagArg(kind), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + } +} + +pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind); + +impl IntoDiagnosticArg for GeneratorKindAsDiagArg { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self.0 { + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn", + hir::GeneratorKind::Gen => "generator", + }; + rustc_errors::DiagnosticArgValue::Str(kind.into()) } } @@ -579,22 +650,22 @@ impl<'tcx> InferSource<'tcx> { } impl<'tcx> InferSourceKind<'tcx> { - fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String { + fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) { match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { - format!(" for the closure `{}`", closure_as_fn_str(infcx, ty)) + ("closure", closure_as_fn_str(infcx, ty)) } else if !ty.is_ty_infer() { - format!(" for `{}`", ty_to_string(infcx, ty)) + ("normal", ty_to_string(infcx, ty)) } else { - String::new() + ("other", String::new()) } } // FIXME: We should be able to add some additional info here. InferSourceKind::GenericArg { .. } - | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(), + | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()), } } } @@ -830,7 +901,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } } - hir::ExprKind::MethodCall(segment, _, _) => { + hir::ExprKind::MethodCall(segment, ..) => { if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) { let generics = tcx.generics_of(def_id); let insertable: Option<_> = try { @@ -838,7 +909,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { None? } let substs = self.node_substs_opt(expr.hir_id)?; - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { insert_span, @@ -886,13 +957,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { path.segments .iter() .filter_map(move |segment| { - let res = segment.res?; + let res = segment.res; let generics_def_id = tcx.res_generics_def_id(res)?; let generics = tcx.generics_of(generics_def_id); if generics.has_impl_trait() { return None; } - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); Some(InsertableGenericArgs { insert_span, @@ -925,7 +996,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if !segment.infer_args || generics.has_impl_trait() { None?; } - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id } }; @@ -1061,7 +1132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { let generic_args = &generics.own_substs_no_defaults(tcx, substs) [generics.own_counts().lifetimes..]; let span = match expr.kind { - ExprKind::MethodCall(path, _, _) => path.ident.span, + ExprKind::MethodCall(path, ..) => path.ident.span, _ => expr.span, }; @@ -1110,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { }) .any(|generics| generics.has_impl_trait()) }; - if let ExprKind::MethodCall(path, args, span) = expr.kind + if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind && let Some(substs) = self.node_substs_opt(expr.hir_id) && substs.iter().any(|arg| self.generic_arg_contains_target(arg)) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) @@ -1118,12 +1189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { && !has_impl_trait(def_id) { let successor = - args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); + args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); let substs = self.infcx.resolve_vars_if_possible(substs); self.update_infer_source(InferSource { span: path.ident.span, kind: InferSourceKind::FullyQualifiedMethodCall { - receiver: args.first().unwrap(), + receiver, successor, substs, def_id, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 9a2ab3e32..3a4320a9a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -1,6 +1,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where both the regions are anonymous. +use crate::errors::AddLifetimeParamsSuggestion; +use crate::errors::LifetimeMismatch; +use crate::errors::LifetimeMismatchLabels; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::infer::error_reporting::nice_region_error::NiceRegionError; @@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::SubregionOrigin; use crate::infer::TyCtxt; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; -use rustc_hir as hir; -use rustc_hir::{GenericParamKind, Ty}; +use rustc_errors::AddSubdiagnostic; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_hir::Ty; use rustc_middle::ty::Region; -use rustc_span::symbol::kw; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. @@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_param_sup.pat.simple_ident() { - Some(simple_ident) => format!(" from `{}`", simple_ident), - None => String::new(), - }; - - let span_label_var2 = match anon_param_sub.pat.simple_ident() { - Some(simple_ident) => format!(" into `{}`", simple_ident), - None => String::new(), - }; - debug!( "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}", sub_is_ret_type, sup_is_ret_type ); - let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); - - match (sup_is_ret_type, sub_is_ret_type) { + let labels = match (sup_is_ret_type, sub_is_ret_type) { (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => { let param_span = if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span }; - - err.span_label( + LifetimeMismatchLabels::InRet { param_span, - "this parameter and the return type are declared with different lifetimes...", - ); - err.span_label(ret_span, ""); - err.span_label(span, format!("...but data{} is returned here", span_label_var1)); - } - - (None, None) => { - if ty_sup.hir_id == ty_sub.hir_id { - err.span_label(ty_sup.span, "this type is declared with multiple lifetimes..."); - err.span_label(ty_sub.span, ""); - err.span_label(span, "...but data with one lifetime flows into the other here"); - } else { - err.span_label( - ty_sup.span, - "these two types are declared with different lifetimes...", - ); - err.span_label(ty_sub.span, ""); - err.span_label( - span, - format!("...but data{} flows{} here", span_label_var1, span_label_var2), - ); + ret_span, + span, + label_var1: anon_param_sup.pat.simple_ident(), } } - } - if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) { - err.note("each elided lifetime in input position becomes a distinct lifetime"); - } + (None, None) => LifetimeMismatchLabels::Normal { + hir_equal: ty_sup.hir_id == ty_sub.hir_id, + ty_sup: ty_sup.span, + ty_sub: ty_sub.span, + span, + sup: anon_param_sup.pat.simple_ident(), + sub: anon_param_sub.pat.simple_ident(), + }, + }; - let reported = err.emit(); + let suggestion = + AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true }; + let err = LifetimeMismatch { span, labels, suggestion }; + let reported = self.tcx().sess.emit_err(err); Some(reported) } } +/// Currently only used in rustc_borrowck, probably should be +/// removed in favour of public_errors::AddLifetimeParamsSuggestion pub fn suggest_adding_lifetime_params<'tcx>( tcx: TyCtxt<'tcx>, sub: Region<'tcx>, - ty_sup: &Ty<'_>, - ty_sub: &Ty<'_>, + ty_sup: &'tcx Ty<'_>, + ty_sub: &'tcx Ty<'_>, err: &mut Diagnostic, -) -> bool { - let ( - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, - ) = (ty_sub, ty_sup) else { - return false; - }; - - if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { - return false; - }; - - let Some(anon_reg) = tcx.is_suitable_region(sub) else { - return false; - }; - - let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); - - let node = tcx.hir().get(hir_id); - let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let generics = match node { - hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, - _ => return false, - }; - - let suggestion_param_name = generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .find(|i| *i != kw::UnderscoreLifetime); - let introduce_new = suggestion_param_name.is_none(); - let suggestion_param_name = - suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); - - debug!(?lifetime_sup.span); - debug!(?lifetime_sub.span); - let make_suggestion = |span: rustc_span::Span| { - if span.is_empty() { - (span, format!("{}, ", suggestion_param_name)) - } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() { - (span.shrink_to_hi(), format!("{} ", suggestion_param_name)) - } else { - (span, suggestion_param_name.clone()) - } - }; - let mut suggestions = - vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)]; - - if introduce_new { - let new_param_suggestion = - if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) { - (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) - } else { - (generics.span, format!("<{}>", suggestion_param_name)) - }; - - suggestions.push(new_param_suggestion); - } - - let mut sugg = String::from("consider introducing a named lifetime parameter"); - if is_impl { - sugg.push_str(" and update trait if needed"); - } - err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect); - - true +) { + let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false }; + suggestion.add_to_diagnostic(err); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index c1b201da6..d8f540b74 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -91,7 +91,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { hir::TyKind::TraitObject(bounds, ..) => { for bound in bounds { self.current_index.shift_in(1); - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + self.visit_poly_trait_ref(bound); self.current_index.shift_out(1); } } @@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // Find the index of the named region that was part of the // error. We will then search the function parameters for a bound // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_type = Some(arg); @@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { Some( rl::Region::Static | rl::Region::Free(_, _) - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _), ) | None, @@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { // the lifetime of the TyPath! - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_it = true; @@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { ( Some( rl::Region::Static - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _) | rl::Region::Free(_, _), ) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 893ca3cf7..1410e2b63 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -1,13 +1,14 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. +use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; +use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::note_and_explain_region; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::TypeVisitor; @@ -35,15 +36,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else { return None; }; - let ObligationCauseCode::BindingObligation(_def_id, binding_span) = *parent.code() else { + let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) + = *parent.code() else { return None; }; - let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type"); + // FIXME: we should point at the lifetime - let mut multi_span: MultiSpan = vec![binding_span].into(); - multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement"); - err.span_note(multi_span, "because this has an unmet lifetime requirement"); - note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span)); + let multi_span: MultiSpan = vec![binding_span].into(); + let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq { + unmet_requirements: multi_span, + binding_span, + }; + + let expl = note_and_explain::RegionExplanation::new( + self.tcx(), + sup, + Some(binding_span), + note_and_explain::PrefixKind::Empty, + note_and_explain::SuffixKind::Continues, + ); + let mut impl_span = None; + let mut trait_subdiags = Vec::new(); if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. @@ -72,31 +85,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // there aren't trait objects or because none are implicit, then just // write a single note on the impl itself. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } else { // Otherwise, point at all implicit static lifetimes - err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); for span in &traits { - err.span_note(*span, "this has an implicit `'static` lifetime requirement"); + trait_subdiags.push(TraitSubdiag::Note { span: *span }); // It would be nice to put this immediately under the above note, but they get // pushed to the end. - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() }); } } } else { // Otherwise just point out the impl. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } - let reported = err.emit(); + let err = MismatchedStaticLifetime { + cause_span: cause.span, + unmet_lifetime_reqs: multispan_subdiag, + expl, + impl_note: ImplNote { impl_span }, + trait_subdiags, + }; + let reported = self.tcx().sess.emit_err(err); Some(reported) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 998699158..d4db07512 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -211,7 +211,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ); let mut err = self.tcx().sess.struct_span_err(span, &msg); - let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() { + let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) + | ObligationCauseCode::ExprItemObligation(def_id, ..) = + *cause.code() + { err.span_label(span, "doesn't satisfy where-clause"); err.span_label( self.tcx().def_span(def_id), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 9886c572a..ae56bea6f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), _ => cause.code(), } - && let (&ObligationCauseCode::ItemObligation(item_def_id), None) = (code, override_error_code) + && let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code) { // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` // lifetime as above, but called using a fully-qualified path to the method: @@ -300,7 +300,7 @@ pub fn suggest_new_region_bound( continue; } match fn_return.kind { - TyKind::OpaqueDef(item_id, _) => { + TyKind::OpaqueDef(item_id, _, _) => { let item = tcx.hir().item(item_id); let ItemKind::OpaqueTy(opaque) = &item.kind else { return; @@ -544,7 +544,7 @@ pub struct TraitObjectVisitor(pub FxHashSet); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - ty::Dynamic(preds, re) if re.is_static() => { + ty::Dynamic(preds, re, _) if re.is_static() => { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index da465a764..a6a39d062 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -154,16 +154,11 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { } hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [segment] - if segment - .res - .map(|res| { - matches!( - res, - Res::SelfTy { trait_: _, alias_to: _ } - | Res::Def(hir::def::DefKind::TyParam, _) - ) - }) - .unwrap_or(false) => + if matches!( + segment.res, + Res::SelfTy { trait_: _, alias_to: _ } + | Res::Def(hir::def::DefKind::TyParam, _) + ) => { self.types.push(path.span); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index c1940c5c0..adaa47c01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,100 +1,89 @@ -use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; +use crate::errors::RegionOriginNote; +use crate::infer::error_reporting::note_and_explain_region; use crate::infer::{self, InferCtxt, SubregionOrigin}; -use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; +use super::ObligationCauseAsDiagArg; + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { - let mut label_or_note = |span, msg: &str| { - let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); - let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); - let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); - if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { - err.span_label(span, msg); - } else if span_is_primary && expanded_sub_count == 0 { - err.note(msg); - } else { - err.span_note(span, msg); - } - }; match *origin { - infer::Subtype(ref trace) => { - if let Some((expected, found)) = self.values_str(trace.values) { - label_or_note( - trace.cause.span, - &format!("...so that the {}", trace.cause.as_requirement_str()), - ); - - err.note_expected_found(&"", expected, &"", found); - } else { - // FIXME: this really should be handled at some earlier stage. Our - // handling of region checking when type errors are present is - // *terrible*. - - label_or_note( - trace.cause.span, - &format!("...so that {}", trace.cause.as_requirement_str()), - ); - } - } - infer::Reborrow(span) => { - label_or_note(span, "...so that reference does not outlive borrowed content"); + infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + span: trace.cause.span, + requirement: ObligationCauseAsDiagArg(trace.cause.clone()), + expected_found: self.values_str(trace.values), } + .add_to_diagnostic(err), + infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow } + .add_to_diagnostic(err), infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - label_or_note(span, &format!("...so that closure can access `{}`", var_name)); + RegionOriginNote::WithName { + span, + msg: fluent::infer::reborrow, + name: &var_name.to_string(), + continues: false, + } + .add_to_diagnostic(err); } infer::RelateObjectBound(span) => { - label_or_note(span, "...so that it can be closed over into an object"); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound } + .add_to_diagnostic(err); } infer::DataBorrowed(ty, span) => { - label_or_note( + RegionOriginNote::WithName { span, - &format!( - "...so that the type `{}` is not borrowed for too long", - self.ty_to_string(ty) - ), - ); + msg: fluent::infer::data_borrowed, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diagnostic(err); } infer::ReferenceOutlivesReferent(ty, span) => { - label_or_note( + RegionOriginNote::WithName { span, - &format!( - "...so that the reference type `{}` does not outlive the data it points at", - self.ty_to_string(ty) - ), - ); + msg: fluent::infer::reference_outlives_referent, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diagnostic(err); } - infer::RelateParamBound(span, t, opt_span) => { - label_or_note( + infer::RelateParamBound(span, ty, opt_span) => { + RegionOriginNote::WithName { span, - &format!( - "...so that the type `{}` will meet its required lifetime bounds{}", - self.ty_to_string(t), - if opt_span.is_some() { "..." } else { "" }, - ), - ); + msg: fluent::infer::relate_param_bound, + name: &self.ty_to_string(ty), + continues: opt_span.is_some(), + } + .add_to_diagnostic(err); if let Some(span) = opt_span { - err.span_note(span, "...that is required by this bound"); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 } + .add_to_diagnostic(err); } } infer::RelateRegionParamBound(span) => { - label_or_note( - span, - "...so that the declared lifetime parameter bounds are satisfied", - ); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound } + .add_to_diagnostic(err); } infer::CompareImplItemObligation { span, .. } => { - label_or_note( - span, - "...so that the definition in impl matches the definition from the trait", - ); + RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation } + .add_to_diagnostic(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, &parent); } + infer::AscribeUserTypeProvePredicate(span) => { + RegionOriginNote::Plain { + span, + msg: fluent::infer::ascribe_user_type_prove_predicate, + } + .add_to_diagnostic(err); + } } } @@ -107,7 +96,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, &terr); + let mut err = self.report_and_explain_type_error(trace, terr); match (*sub, *sup) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} (ty::RePlaceholder(_), _) => { @@ -374,6 +363,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } + infer::AscribeUserTypeProvePredicate(span) => { + let mut err = + struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); + note_and_explain_region( + self.tcx, + &mut err, + "lifetime instantiated with ", + sup, + "", + None, + ); + note_and_explain_region( + self.tcx, + &mut err, + "but lifetime must outlive ", + sub, + "", + None, + ); + err + } } } @@ -390,10 +400,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if matches!( &trace.cause.code().peel_derives(), ObligationCauseCode::BindingObligation(..) + | ObligationCauseCode::ExprBindingObligation(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::BindingObligation(_, span) = + if let ObligationCauseCode::BindingObligation(_, span) + | ObligationCauseCode::ExprBindingObligation(_, span, ..) = &trace.cause.code().peel_derives() { let span = *span; @@ -406,7 +418,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } infer::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; - return self.report_and_explain_type_error(trace, &terr); + return self.report_and_explain_type_error(trace, terr); } _ => return self.report_concrete_failure(placeholder_origin, sub, sup), } diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index d566634a4..728d691a2 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -27,13 +27,13 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct FreeRegionMap<'tcx> { // Stores the relation `a < b`, where `a` and `b` are regions. // // Invariant: only free regions like `'x` or `'static` are stored // in this relation, not scopes. - relation: TransitiveRelation>, + pub(crate) relation: TransitiveRelation>, } impl<'tcx> FreeRegionMap<'tcx> { @@ -45,15 +45,6 @@ impl<'tcx> FreeRegionMap<'tcx> { self.relation.is_empty() } - // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`. - // (with the exception that `'static: 'x` is not notable) - pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { - debug!("relate_regions(sub={:?}, sup={:?})", sub, sup); - if sub.is_free_or_static() && sup.is_free() { - self.relation.add(sub, sup) - } - } - /// Tests whether `r_a <= r_b`. /// /// Both regions must meet `is_free_or_static`. diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 84004d2b2..fee15afc7 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -126,7 +126,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::ReFree(_) | ty::ReVar(_) | ty::RePlaceholder(..) - | ty::ReEmpty(_) | ty::ReErased => { // replace all free regions with 'erased self.tcx().lifetimes.re_erased diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index d0d9efe15..0ce271c0e 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// For more details visit the relevant sections of the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn replace_bound_vars_with_placeholders(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx> + Copy, @@ -81,19 +81,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let next_universe = self.create_next_universe(); let delegate = FnMutDelegate { - regions: |br: ty::BoundRegion| { + regions: &mut |br: ty::BoundRegion| { self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, name: br.kind, })) }, - types: |bound_ty: ty::BoundTy| { + types: &mut |bound_ty: ty::BoundTy| { self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: next_universe, name: bound_ty.var, })) }, - consts: |bound_var: ty::BoundVar, ty| { + consts: &mut |bound_var: ty::BoundVar, ty| { self.tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(ty::PlaceholderConst { universe: next_universe, @@ -104,9 +104,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, }; - let result = self.tcx.replace_bound_vars_uncached(binder, delegate); - debug!(?next_universe, ?result); - result + debug!(?next_universe); + self.tcx.replace_bound_vars_uncached(binder, delegate) } /// See [RegionConstraintCollector::leak_check][1]. diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 3783cfb4c..5f13b2b3d 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -15,8 +15,9 @@ use rustc_data_structures::graph::implementation::{ use rustc_data_structures::intern::Interned; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::PlaceholderRegion; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; +use rustc_middle::ty::{ReEarlyBound, ReErased, ReFree, ReStatic}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{Region, RegionVid}; use rustc_span::Span; @@ -51,6 +52,13 @@ pub struct LexicalRegionResolutions<'tcx> { #[derive(Copy, Clone, Debug)] pub(crate) enum VarValue<'tcx> { + /// Empty lifetime is for data that is never accessed. We tag the + /// empty lifetime with a universe -- the idea is that we don't + /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable. + /// Therefore, the `'empty` in a universe `U` is less than all + /// regions visible from `U`, but not less than regions not visible + /// from `U`. + Empty(ty::UniverseIndex), Value(Region<'tcx>), ErrorValue, } @@ -117,7 +125,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &mut self, errors: &mut Vec>, ) -> LexicalRegionResolutions<'tcx> { - let mut var_data = self.construct_var_data(self.tcx()); + let mut var_data = self.construct_var_data(); if cfg!(debug_assertions) { self.dump_constraints(); @@ -137,13 +145,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// Initially, the value for all variables is set to `'empty`, the /// empty region. The `expansion` phase will grow this larger. - fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> { + fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> { LexicalRegionResolutions { values: IndexVec::from_fn_n( |vid| { let vid_universe = self.var_infos[vid].universe; - let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe)); - VarValue::Value(re_empty) + VarValue::Empty(vid_universe) }, self.num_vars(), ), @@ -189,20 +196,131 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// Gets the LUb of a given region and the empty region + fn lub_empty(&self, a_region: Region<'tcx>) -> Result, PlaceholderRegion> { + match *a_region { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", a_region); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub invoked with non-concrete regions: {:?}", + a_region, + ); + } + + ReStatic => { + // nothing lives longer than `'static` + Ok(self.tcx().lifetimes.re_static) + } + + ReEarlyBound(_) | ReFree(_) => { + // All empty regions are less than early-bound, free, + // and scope regions. + Ok(a_region) + } + + RePlaceholder(placeholder) => Err(placeholder), + } + } + fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { + // In the first pass, we expand region vids according to constraints we + // have previously found. In the second pass, we loop through the region + // vids we expanded and expand *across* region vids (effectively + // "expanding" new `RegSubVar` constraints). + + // Tracks the `VarSubVar` constraints generated for each region vid. We + // later use this to expand across vids. let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len()); + // Tracks the changed region vids. let mut changes = Vec::new(); for constraint in self.data.constraints.keys() { - let (a_vid, a_region, b_vid, b_data) = match *constraint { + match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); - (None, a_region, b_vid, b_data) + + if self.expand_node(a_region, b_vid, b_data) { + changes.push(b_vid); + } } Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { VarValue::ErrorValue => continue, + VarValue::Empty(a_universe) => { + let b_data = var_values.value_mut(b_vid); + + let changed = (|| match *b_data { + VarValue::Empty(b_universe) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = a_universe.min(b_universe); + + debug!( + "Expanding value of {:?} \ + from empty lifetime with universe {:?} \ + to empty lifetime with universe {:?}", + b_vid, b_universe, ui + ); + + *b_data = VarValue::Empty(ui); + true + } + VarValue::Value(cur_region) => { + let lub = match self.lub_empty(cur_region) { + Ok(r) => r, + // If the empty and placeholder regions are in the same universe, + // then the LUB is the Placeholder region (which is the cur_region). + // If they are not in the same universe, the LUB is the Static lifetime. + Err(placeholder) if a_universe == placeholder.universe => { + cur_region + } + Err(_) => self.tcx().lifetimes.re_static, + }; + + if lub == cur_region { + return false; + } + + debug!( + "Expanding value of {:?} from {:?} to {:?}", + b_vid, cur_region, lub + ); + + *b_data = VarValue::Value(lub); + true + } + + VarValue::ErrorValue => false, + })(); + + if changed { + changes.push(b_vid); + } + match b_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[a_vid].push((a_vid, b_vid)); + constraints[b_vid].push((a_vid, b_vid)); + } + } + } VarValue::Value(a_region) => { let b_data = var_values.value_mut(b_vid); - (Some(a_vid), a_region, b_vid, b_data) + + if self.expand_node(a_region, b_vid, b_data) { + changes.push(b_vid); + } + match b_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[a_vid].push((a_vid, b_vid)); + constraints[b_vid].push((a_vid, b_vid)); + } + } } }, Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { @@ -210,18 +328,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // is done, in `collect_errors`. continue; } - }; - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - if let Some(a_vid) = a_vid { - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); - } - } } } @@ -242,6 +348,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// Expands the value of the region represented with `b_vid` with current + /// value `b_data` to the lub of `b_data` and `a_region`. The corresponds + /// with the constraint `'?b: 'a` (`'a <: '?b`), where `'a` is some known + /// region and `'?b` is some region variable. fn expand_node( &self, a_region: Region<'tcx>, @@ -263,14 +373,28 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } match *b_data { + VarValue::Empty(empty_ui) => { + let lub = match self.lub_empty(a_region) { + Ok(r) => r, + // If this empty region is from a universe that can + // name the placeholder, then the placeholder is + // larger; otherwise, the only ancestor is `'static`. + Err(placeholder) if empty_ui.can_name(placeholder.universe) => { + self.tcx().mk_region(RePlaceholder(placeholder)) + } + Err(_) => self.tcx().lifetimes.re_static, + }; + + debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub); + + *b_data = VarValue::Value(lub); + true + } VarValue::Value(cur_region) => { // This is a specialized version of the `lub_concrete_regions` // check below for a common case, here purely as an // optimization. let b_universe = self.var_infos[b_vid].universe; - if let ReEmpty(a_universe) = *a_region && a_universe == b_universe { - return false; - } let mut lub = self.lub_concrete_regions(a_region, cur_region); if lub == cur_region { @@ -300,6 +424,78 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// True if `a <= b`. + fn sub_region_values(&self, a: VarValue<'tcx>, b: VarValue<'tcx>) -> bool { + match (a, b) { + // Error region is `'static` + (VarValue::ErrorValue, _) | (_, VarValue::ErrorValue) => return true, + (VarValue::Empty(a_ui), VarValue::Empty(b_ui)) => { + // Empty regions are ordered according to the universe + // they are associated with. + a_ui.min(b_ui) == b_ui + } + (VarValue::Value(a), VarValue::Empty(_)) => { + match *a { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", a); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub_concrete_regions invoked with non-concrete region: {:?}", + a + ); + } + + ReStatic | ReEarlyBound(_) | ReFree(_) => { + // nothing lives longer than `'static` + + // All empty regions are less than early-bound, free, + // and scope regions. + + false + } + + RePlaceholder(_) => { + // The LUB is either `a` or `'static` + false + } + } + } + (VarValue::Empty(a_ui), VarValue::Value(b)) => { + match *b { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", b); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub_concrete_regions invoked with non-concrete regions: {:?}", + b + ); + } + + ReStatic | ReEarlyBound(_) | ReFree(_) => { + // nothing lives longer than `'static` + // All empty regions are less than early-bound, free, + // and scope regions. + true + } + + RePlaceholder(placeholder) => { + // If this empty region is from a universe that can + // name the placeholder, then the placeholder is + // larger; otherwise, the only ancestor is `'static`. + if a_ui.can_name(placeholder.universe) { true } else { false } + } + } + } + (VarValue::Value(a), VarValue::Value(b)) => self.sub_concrete_regions(a, b), + } + } + /// True if `a <= b`, but not defined over inference variables. #[instrument(level = "trace", skip(self))] fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool { @@ -333,9 +529,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// /// Neither `a` nor `b` may be an inference variable (hence the /// term "concrete regions"). - #[instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self), ret)] fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { - let r = match (*a, *b) { + match (*a, *b) { (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } @@ -355,37 +551,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.tcx().lifetimes.re_static } - (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => { - // All empty regions are less than early-bound, free, - // and scope regions. - b - } - - (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => { - // All empty regions are less than early-bound, free, - // and scope regions. - a - } - - (ReEmpty(a_ui), ReEmpty(b_ui)) => { - // Empty regions are ordered according to the universe - // they are associated with. - let ui = a_ui.min(b_ui); - self.tcx().mk_region(ReEmpty(ui)) - } - - (ReEmpty(empty_ui), RePlaceholder(placeholder)) - | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => { - // If this empty region is from a universe that can - // name the placeholder, then the placeholder is - // larger; otherwise, the only ancestor is `'static`. - if empty_ui.can_name(placeholder.universe) { - self.tcx().mk_region(RePlaceholder(placeholder)) - } else { - self.tcx().lifetimes.re_static - } - } - (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => { self.region_rels.lub_free_regions(a, b) } @@ -399,11 +564,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.tcx().lifetimes.re_static } } - }; - - debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r); - - r + } } /// After expansion is complete, go and check upper bounds (i.e., @@ -512,7 +673,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for (node_vid, value) in var_data.values.iter_enumerated() { match *value { - VarValue::Value(_) => { /* Inference successful */ } + VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ } VarValue::ErrorValue => { // Inference impossible: this value contains // inconsistent constraints. @@ -833,12 +994,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::OutlivedBy(r) => { - self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r)) + let a = match *min { + ty::ReVar(rid) => var_values.values[rid], + _ => VarValue::Value(min), + }; + let b = match **r { + ty::ReVar(rid) => var_values.values[rid], + _ => VarValue::Value(*r), + }; + self.sub_region_values(a, b) } - VerifyBound::IsEmpty => { - matches!(*min, ty::ReEmpty(_)) - } + VerifyBound::IsEmpty => match *min { + ty::ReVar(rid) => match var_values.values[rid] { + VarValue::ErrorValue => false, + VarValue::Empty(_) => true, + VarValue::Value(_) => false, + }, + _ => false, + }, VerifyBound::AnyBound(bs) => { bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min)) @@ -880,6 +1054,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { ) -> ty::Region<'tcx> { let result = match *r { ty::ReVar(rid) => match self.values[rid] { + VarValue::Empty(_) => r, VarValue::Value(r) => r, VarValue::ErrorValue => tcx.lifetimes.re_static, }, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d7d1b5fa2..3abed1221 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -32,7 +33,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, Ref, RefCell}; use std::fmt; @@ -316,12 +317,12 @@ pub struct InferCtxt<'a, 'tcx> { /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. - tainted_by_errors_flag: Cell, + tainted_by_errors: Cell>, /// Track how many errors were reported when this infcx is created. /// If the number of errors increases, that's also a sign (line /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` + // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, /// This flag is true while there is an active snapshot. @@ -337,6 +338,9 @@ pub struct InferCtxt<'a, 'tcx> { /// when we enter into a higher-ranked (`for<..>`) type or trait /// bound. universe: Cell, + + normalize_fn_sig_for_diagnostic: + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } /// See the `error_reporting` module for more details. @@ -350,12 +354,11 @@ pub enum ValuePairs<'tcx> { impl<'tcx> ValuePairs<'tcx> { pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - if let ValuePairs::Terms(ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) = self + if let ValuePairs::Terms(ExpectedFound { expected, found }) = self + && let Some(expected) = expected.ty() + && let Some(found) = found.ty() { - Some((*expected, *found)) + Some((expected, found)) } else { None } @@ -406,7 +409,11 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl method against /// the containing trait. - CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId }, + CompareImplItemObligation { + span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + }, /// Checking that the bounds of a trait's associated type hold for a given impl CheckAssociatedTypeBounds { @@ -414,12 +421,24 @@ pub enum SubregionOrigin<'tcx> { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, }, + + AscribeUserTypeProvePredicate(Span), } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(SubregionOrigin<'_>, 32); +impl<'tcx> SubregionOrigin<'tcx> { + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { + match self { + Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), + Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), + _ => ConstraintCategory::BoringNoLocation, + } + } +} + /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -504,7 +523,7 @@ pub enum FixupError<'tcx> { } /// See the `region_obligations` field for more information. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct RegionObligation<'tcx> { pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, @@ -540,6 +559,8 @@ pub struct InferCtxtBuilder<'tcx> { defining_use_anchor: DefiningAnchor, considering_regions: bool, fresh_typeck_results: Option>>, + normalize_fn_sig_for_diagnostic: + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } pub trait TyCtxtInferExt<'tcx> { @@ -553,6 +574,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { defining_use_anchor: DefiningAnchor::Error, considering_regions: true, fresh_typeck_results: None, + normalize_fn_sig_for_diagnostic: None, } } } @@ -582,6 +604,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn with_normalize_fn_sig_for_diagnostic( + mut self, + fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, + ) -> Self { + self.normalize_fn_sig_for_diagnostic = Some(fun); + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -611,6 +641,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { defining_use_anchor, considering_regions, ref fresh_typeck_results, + ref normalize_fn_sig_for_diagnostic, } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { @@ -624,11 +655,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { evaluation_cache: Default::default(), reported_trait_errors: Default::default(), reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), + tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), + normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic + .as_ref() + .map(|f| f.clone()), }) } } @@ -988,7 +1022,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: ty::PolyCoercePredicate<'tcx>, - ) -> Option> { + ) -> Result, (TyVid, TyVid)> { let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate { a_is_expected: false, // when coercing from `a` to `b`, `b` is expected a: p.a, @@ -1002,7 +1036,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: ty::PolySubtypePredicate<'tcx>, - ) -> Option> { + ) -> Result, (TyVid, TyVid)> { // Check for two unresolved inference variables, in which case we can // make no progress. This is partly a micro-optimization, but it's // also an opportunity to "sub-unify" the variables. This isn't @@ -1021,12 +1055,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match (r_a.kind(), r_b.kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { self.inner.borrow_mut().type_variables().sub(a_vid, b_vid); - return None; + return Err((a_vid, b_vid)); } _ => {} } - Some(self.commit_if_ok(|_snapshot| { + Ok(self.commit_if_ok(|_snapshot| { let ty::SubtypePredicate { a_is_expected, a, b } = self.replace_bound_vars_with_placeholders(predicate); @@ -1227,23 +1261,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn is_tainted_by_errors(&self) -> bool { debug!( "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", + tainted_by_errors={})", self.tcx.sess.err_count(), self.err_count_on_creation, - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() ); if self.tcx.sess.err_count() > self.err_count_on_creation { return true; // errors reported since this infcx was made } - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() } /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. pub fn set_tainted_by_errors(&self) { debug!("set_tainted_by_errors()"); - self.tainted_by_errors_flag.set(true) + self.tainted_by_errors.set(Some( + self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), + )); } pub fn skip_region_resolution(&self) { @@ -1313,7 +1349,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible` as well as `fully_resolve`. /// /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferrably use [`InferCtxt::check_region_obligations_and_report_errors`] + /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] /// to do both of these operations together. pub fn resolve_regions_and_report_errors( &self, @@ -1527,8 +1563,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { actual: Ty<'tcx>, err: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let trace = TypeTrace::types(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err) + self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } pub fn report_mismatched_consts( @@ -1538,8 +1573,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { actual: ty::Const<'tcx>, err: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let trace = TypeTrace::consts(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err) + self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } pub fn replace_bound_vars_with_fresh_vars( @@ -1656,7 +1690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn try_const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx, ()>, ty: Ty<'tcx>, span: Option, ) -> Result, ErrorHandled> { @@ -1691,7 +1725,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn const_eval_resolve( &self, mut param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx, ()>, span: Option, ) -> EvalToValTreeResult<'tcx> { let mut substs = self.resolve_vars_if_possible(unevaluated.substs); @@ -1700,7 +1734,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Postpone the evaluation of constants whose substs depend on inference // variables if substs.has_infer_types_or_consts() { - let ac = AbstractConst::new(self.tcx, unevaluated.shrink()); + let ac = AbstractConst::new(self.tcx, unevaluated); match ac { Ok(None) => { substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did); @@ -1722,11 +1756,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!(?param_env_erased); debug!(?substs_erased); - let unevaluated = ty::Unevaluated { - def: unevaluated.def, - substs: substs_erased, - promoted: unevaluated.promoted, - }; + let unevaluated = + ty::Unevaluated { def: unevaluated.def, substs: substs_erased, promoted: () }; // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. @@ -1814,7 +1845,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a type, returns `None` /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). - pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option { + fn maybe_from_ty(ty: Ty<'tcx>) -> Option { match *ty.kind() { ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), @@ -1825,7 +1856,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a constant, returns `None` /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option { + fn maybe_from_const(ct: ty::Const<'tcx>) -> Option { match ct.kind() { ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), _ => None, @@ -1937,6 +1968,18 @@ impl<'tcx> TypeTrace<'tcx> { } } + pub fn poly_trait_refs( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } + pub fn consts( cause: &ObligationCause<'tcx>, a_is_expected: bool, @@ -1962,6 +2005,7 @@ impl<'tcx> SubregionOrigin<'tcx> { DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, + AscribeUserTypeProvePredicate(span) => span, CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1994,6 +2038,10 @@ impl<'tcx> SubregionOrigin<'tcx> { parent: Box::new(default()), }, + traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) + } + _ => default(), } } @@ -2015,16 +2063,6 @@ impl RegionVariableOrigin { } } -impl<'tcx> fmt::Debug for RegionObligation<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, self.sup_type - ) - } -} - /// Replaces substs that reference param or infer variables with suitable /// placeholders. This function is meant to remove these param and infer /// substs when they're not actually needed to evaluate a constant. diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index bab4f3e9e..00fc442d3 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -396,6 +396,32 @@ where generalizer.relate(value, value) } + + fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; + let mut generalize = |ty, ty_is_expected| { + let var = self.infcx.next_ty_var_id_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.delegate.span(), + }, + ty::UniverseIndex::ROOT, + ); + if ty_is_expected { + self.relate_ty_var((ty, var)) + } else { + self.relate_ty_var((var, ty)) + } + }; + let (a, b) = match (a.kind(), b.kind()) { + (&ty::Opaque(..), _) => (a, generalize(b, false)?), + (_, &ty::Opaque(..)) => (generalize(a, true)?, b), + _ => unreachable!(), + }; + self.delegate.register_opaque_type(a, b, true)?; + trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); + Ok(a) + } } /// When we instantiate an inference variable with a value in @@ -516,7 +542,7 @@ where true } - #[instrument(skip(self, info), level = "trace")] + #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance>( &mut self, variance: ty::Variance, @@ -534,8 +560,6 @@ where self.ambient_variance = old_ambient_variance; - debug!(?r); - Ok(r) } @@ -572,32 +596,16 @@ where (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { - self.infcx.super_combine_tys(self, a, b) + infcx.super_combine_tys(self, a, b).or_else(|err| { + self.tcx().sess.delay_span_bug( + self.delegate.span(), + "failure to relate an opaque to itself should result in an error later on", + ); + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + }) } (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - let mut generalize = |ty, ty_is_expected| { - let var = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), - }, - ty::UniverseIndex::ROOT, - ); - if ty_is_expected { - self.relate_ty_var((ty, var)) - } else { - self.relate_ty_var((var, ty)) - } - }; - let (a, b) = match (a.kind(), b.kind()) { - (&ty::Opaque(..), _) => (a, generalize(b, false)?), - (_, &ty::Opaque(..)) => (generalize(a, true)?, b), - _ => unreachable!(), - }; - self.delegate.register_opaque_type(a, b, true)?; - trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); - Ok(a) + self.relate_opaques(a, b) } (&ty::Projection(projection_ty), _) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index e579afbf3..8c9ddf866 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,3 +1,4 @@ +use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def_id::{DefId, LocalDefId}; @@ -72,7 +73,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // for opaque types, and then use that kind to fix the spans for type errors // that we see later on. let ty_var = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, + kind: TypeVariableOriginKind::OpaqueTypeInference(def_id), span, }); obligations.extend( @@ -153,22 +154,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(OpaqueTyOrigin::TyAlias) = did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span)) { - self.tcx - .sess - .struct_span_err( - cause.span, - "opaque type's hidden type cannot be another opaque type from the same scope", - ) - .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope") - .span_note( - self.tcx.def_span(def_id), - "opaque type whose hidden type is being assigned", - ) - .span_note( - self.tcx.def_span(did2), - "opaque type being used as hidden type", - ) - .emit(); + self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { + span: cause.span, + hidden_type: self.tcx.def_span(did2), + opaque_type: self.tcx.def_span(def_id), + }); } } Some(self.register_hidden_type( @@ -400,7 +390,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }); } - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option { let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = match self.defining_use_anchor { @@ -431,16 +421,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { in_definition_scope.then_some(*origin) } - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { - let origin = match self.tcx.hir().expect_item(def_id).kind { + match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind) } - }; - trace!(?origin); - origin + } } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index fb12da0cc..4d124554a 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -29,7 +29,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } - #[instrument(level = "debug")] + #[instrument(level = "debug", ret)] pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { std::mem::take(&mut self.opaque_types) } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index b2decd64f..9922b156e 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -2,6 +2,7 @@ use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -51,23 +52,49 @@ pub struct OutlivesEnvironment<'tcx> { region_bound_pairs: RegionBoundPairs<'tcx>, } +/// Builder of OutlivesEnvironment. +#[derive(Debug)] +struct OutlivesEnvironmentBuilder<'tcx> { + param_env: ty::ParamEnv<'tcx>, + region_relation: TransitiveRelationBuilder>, + region_bound_pairs: RegionBoundPairs<'tcx>, +} + /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. pub type RegionBoundPairs<'tcx> = FxIndexSet, Region<'tcx>>>; -impl<'a, 'tcx> OutlivesEnvironment<'tcx> { - pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { - let mut env = OutlivesEnvironment { +impl<'tcx> OutlivesEnvironment<'tcx> { + /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. + fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> { + let mut builder = OutlivesEnvironmentBuilder { param_env, - free_region_map: Default::default(), + region_relation: Default::default(), region_bound_pairs: Default::default(), }; - env.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); + builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); - env + builder + } + + #[inline] + /// Create a new `OutlivesEnvironment` without extra outlives bounds. + pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { + Self::builder(param_env).build() + } + + /// Create a new `OutlivesEnvironment` with extra outlives bounds. + pub fn with_bounds<'a>( + param_env: ty::ParamEnv<'tcx>, + infcx: Option<&InferCtxt<'a, 'tcx>>, + extra_bounds: impl IntoIterator>, + ) -> Self { + let mut builder = Self::builder(param_env); + builder.add_outlives_bounds(infcx, extra_bounds); + builder.build() } /// Borrows current value of the `free_region_map`. @@ -79,6 +106,18 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { &self.region_bound_pairs } +} + +impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { + #[inline] + #[instrument(level = "debug")] + fn build(self) -> OutlivesEnvironment<'tcx> { + OutlivesEnvironment { + param_env: self.param_env, + free_region_map: FreeRegionMap { relation: self.region_relation.freeze() }, + region_bound_pairs: self.region_bound_pairs, + } + } /// Processes outlives bounds that are known to hold, whether from implied or other sources. /// @@ -86,11 +125,8 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// contain inference variables, it must be supplied, in which /// case we will register "givens" on the inference context. (See /// `RegionConstraintData`.) - pub fn add_outlives_bounds( - &mut self, - infcx: Option<&InferCtxt<'a, 'tcx>>, - outlives_bounds: I, - ) where + fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) + where I: IntoIterator>, { // Record relationships such as `T:'x` that don't go into the @@ -122,7 +158,9 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { // system to be more general and to make use // of *every* relationship that arises here, // but presently we do not.) - self.free_region_map.relate_regions(r_a, r_b); + if r_a.is_free_or_static() && r_b.is_free() { + self.region_relation.add(r_a, r_b) + } } } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 2a085288f..2d19d1823 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -9,7 +9,7 @@ pub mod verify; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty; -#[instrument(level = "debug", skip(param_env))] +#[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> impl Iterator> + 'tcx { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ad052f58c..5bd1774f6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -69,6 +69,7 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable}; use smallvec::smallvec; @@ -92,12 +93,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { sub_region: Region<'tcx>, cause: &ObligationCause<'tcx>, ) { + debug!(?sup_type, ?sub_region, ?cause); let origin = SubregionOrigin::from_obligation_cause(cause, || { infer::RelateParamBound( cause.span, sup_type, match cause.code().peel_derives() { - ObligationCauseCode::BindingObligation(_, span) => Some(*span), + ObligationCauseCode::BindingObligation(_, span) + | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span), _ => None, }, ) @@ -161,7 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let outlives = &mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env); - outlives.type_must_outlive(origin, sup_type, sub_region); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); } } @@ -205,6 +209,7 @@ pub trait TypeOutlivesDelegate<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + constraint_category: ConstraintCategory<'tcx>, ); fn push_verify( @@ -247,19 +252,19 @@ where /// - `origin`, the reason we need this constraint /// - `ty`, the type `T` /// - `region`, the region `'a` + #[instrument(level = "debug", skip(self))] pub fn type_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, region: ty::Region<'tcx>, + category: ConstraintCategory<'tcx>, ) { - debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin); - assert!(!ty.has_escaping_bound_vars()); let mut components = smallvec![]; push_outlives_components(self.tcx, ty, &mut components); - self.components_must_outlive(origin, &components, region); + self.components_must_outlive(origin, &components, region, category); } fn components_must_outlive( @@ -267,12 +272,13 @@ where origin: infer::SubregionOrigin<'tcx>, components: &[Component<'tcx>], region: ty::Region<'tcx>, + category: ConstraintCategory<'tcx>, ) { for component in components.iter() { let origin = origin.clone(); match component { Component::Region(region1) => { - self.delegate.push_sub_region_constraint(origin, region, *region1); + self.delegate.push_sub_region_constraint(origin, region, *region1, category); } Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); @@ -281,7 +287,7 @@ where self.projection_must_outlive(origin, region, *projection_ty); } Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, &subcomponents, region); + self.components_must_outlive(origin, &subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error @@ -312,7 +318,7 @@ where self.delegate.push_verify(origin, generic, region, verify_bound); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn projection_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, @@ -388,13 +394,19 @@ where if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); + let constraint = origin.to_constraint_category(); for k in projection_ty.substs { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint(origin.clone(), region, lt); + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); } GenericArgKind::Type(ty) => { - self.type_must_outlive(origin.clone(), ty, region); + self.type_must_outlive(origin.clone(), ty, region, constraint); } GenericArgKind::Const(_) => { // Const parameters don't impose constraints. @@ -432,7 +444,8 @@ where let unique_bound = trait_bounds[0]; debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound); debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.delegate.push_sub_region_constraint(origin, region, unique_bound); + let category = origin.to_constraint_category(); + self.delegate.push_sub_region_constraint(origin, region, unique_bound, category); return; } @@ -454,6 +467,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + _constraint_category: ConstraintCategory<'tcx>, ) { self.sub_regions(origin, a, b) } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 772e297b7..a5c21f0fb 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -34,7 +34,7 @@ use crate::infer::region_constraints::VerifyIfEq; /// like are used. This is a particular challenge since this function is invoked /// very late in inference and hence cannot make use of the normal inference /// machinery. -#[tracing::instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx, param_env))] pub fn extract_verify_if_eq<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -71,7 +71,7 @@ pub fn extract_verify_if_eq<'tcx>( } /// True if a (potentially higher-ranked) outlives -#[tracing::instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx, param_env))] pub(super) fn can_match_erased_ty<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -110,7 +110,7 @@ impl<'tcx> Match<'tcx> { /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern /// is already bound to a different value. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn bind( &mut self, br: ty::BoundRegion, @@ -174,7 +174,14 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { #[instrument(skip(self), level = "debug")] fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) } + if let ty::Error(_) = pattern.kind() { + // Unlike normal `TypeRelation` rules, `ty::Error` does not equal any type. + self.no_match() + } else if pattern == value { + Ok(pattern) + } else { + relate::super_relate_tys(self, pattern, value) + } } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c7d7ef40d..752334950 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -50,13 +50,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { - debug!("param_bound(param_ty={:?})", param_ty); - // Start with anything like `T: 'a` we can scrape from the // environment. If the environment contains something like // `for<'a> T: 'a`, then we know that `T` outlives everything. let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty); + debug!(?declared_bounds_from_env); let mut param_bounds = vec![]; for declared_bound in declared_bounds_from_env { let bound_region = declared_bound.map_bound(|outlives| outlives.1); @@ -65,6 +65,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { param_bounds.push(VerifyBound::OutlivedBy(region)); } else { // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here. + debug!("found that {param_ty:?} outlives any lifetime, returning empty vector"); return VerifyBound::AllBounds(vec![]); } } @@ -72,6 +73,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Add in the default bound of fn body that applies to all in // scope type parameters: if let Some(r) = self.implicit_region_bound { + debug!("adding implicit region bound of {r:?}"); param_bounds.push(VerifyBound::OutlivedBy(r)); } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 0d4472a1c..e43d28ee5 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -187,7 +187,7 @@ pub enum GenericKind<'tcx> { /// } /// ``` /// This is described with an `AnyRegion('a, 'b)` node. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeFoldable, TypeVisitable)] pub enum VerifyBound<'tcx> { /// See [`VerifyIfEq`] docs IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>), @@ -426,21 +426,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { data } - pub fn data(&self) -> &RegionConstraintData<'tcx> { + pub(super) fn data(&self) -> &RegionConstraintData<'tcx> { &self.data } - pub fn start_snapshot(&mut self) -> RegionSnapshot { + pub(super) fn start_snapshot(&mut self) -> RegionSnapshot { debug!("RegionConstraintCollector: start_snapshot"); RegionSnapshot { any_unifications: self.any_unifications } } - pub fn rollback_to(&mut self, snapshot: RegionSnapshot) { + pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); self.any_unifications = snapshot.any_unifications; } - pub fn new_region_var( + pub(super) fn new_region_var( &mut self, universe: ty::UniverseIndex, origin: RegionVariableOrigin, @@ -455,12 +455,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } /// Returns the universe for the given variable. - pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { + pub(super) fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { self.var_infos[vid].universe } /// Returns the origin for the given variable. - pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { + pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { self.var_infos[vid].origin } @@ -492,7 +492,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.undo_log.push(AddVerify(index)); } - pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) { + pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) { // cannot add givens once regions are resolved if self.data.givens.insert((sub, sup)) { debug!("add_given({:?} <= {:?})", sub, sup); @@ -501,7 +501,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn make_eqregion( + pub(super) fn make_eqregion( &mut self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, @@ -530,7 +530,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn member_constraint( + pub(super) fn member_constraint( &mut self, key: ty::OpaqueTypeKey<'tcx>, definition_span: Span, @@ -554,7 +554,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } #[instrument(skip(self, origin), level = "debug")] - pub fn make_subregion( + pub(super) fn make_subregion( &mut self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, @@ -585,7 +585,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn verify_generic_bound( + pub(super) fn verify_generic_bound( &mut self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, @@ -595,7 +595,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.add_verify(Verify { kind, origin, region: sub, bound }); } - pub fn lub_regions( + pub(super) fn lub_regions( &mut self, tcx: TyCtxt<'tcx>, origin: SubregionOrigin<'tcx>, @@ -613,7 +613,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn glb_regions( + pub(super) fn glb_regions( &mut self, tcx: TyCtxt<'tcx>, origin: SubregionOrigin<'tcx>, @@ -634,7 +634,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } /// Resolves the passed RegionVid to the root RegionVid in the unification table - pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid { + pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid { self.unification_table().find(rid).vid } @@ -699,7 +699,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => { ty::UniverseIndex::ROOT } - ty::ReEmpty(ui) => ui, ty::RePlaceholder(placeholder) => placeholder.universe, ty::ReVar(vid) => self.var_universe(vid), ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region), diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index b27571275..b7eab5d43 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -4,6 +4,7 @@ use super::SubregionOrigin; use crate::infer::combine::ConstEquateRelation; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::Obligation; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::TyVar; @@ -141,17 +142,27 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(infcx.tcx.mk_ty_var(var)) }; let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) }; - let (a, b) = match (a.kind(), b.kind()) { + let (ga, gb) = match (a.kind(), b.kind()) { (&ty::Opaque(..), _) => (a, generalize(b, true)?), (_, &ty::Opaque(..)) => (generalize(a, false)?, b), _ => unreachable!(), }; self.fields.obligations.extend( infcx - .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())? + .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env()) + // Don't leak any generalized type variables out of this + // subtyping relation in the case of a type error. + .map_err(|err| { + let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb)); + if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb { + TypeError::Sorts(ExpectedFound { expected: a, found: b }) + } else { + err + } + })? .obligations, ); - Ok(a) + Ok(ga) } _ => { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index a0e2965b6..7ff086452 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -122,6 +122,7 @@ pub enum TypeVariableOriginKind { MiscVariable, NormalizeProjectionType, TypeInference, + OpaqueTypeInference(DefId), TypeParameterDefinition(Symbol, Option), /// One of the upvars or closure kind parameters in a `ClosureSubsts` diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 74a26ebc3..611961ab1 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -100,7 +100,7 @@ impl Default for InferCtxtUndoLogs<'_> { } /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any -/// action that is convertable into an UndoLog (per the From impls above). +/// action that is convertible into an UndoLog (per the From impls above). impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 7769a68ba..ef60d2c91 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -17,9 +17,9 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extend_one)] -#![feature(label_break_value)] +#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(try_blocks)] @@ -35,5 +35,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 1ecbc876c..da4002d09 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -17,6 +17,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_expand = { path = "../rustc_expand" } +rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs new file mode 100644 index 000000000..6a497aed4 --- /dev/null +++ b/compiler/rustc_interface/src/errors.rs @@ -0,0 +1,89 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::{Span, Symbol}; + +use std::io; +use std::path::Path; + +#[derive(SessionDiagnostic)] +#[diag(interface::ferris_identifier)] +pub struct FerrisIdentifier { + #[primary_span] + pub spans: Vec, + #[suggestion(code = "ferris", applicability = "maybe-incorrect")] + pub first_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::emoji_identifier)] +pub struct EmojiIdentifier { + #[primary_span] + pub spans: Vec, + pub ident: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::mixed_bin_crate)] +pub struct MixedBinCrate; + +#[derive(SessionDiagnostic)] +#[diag(interface::mixed_proc_macro_crate)] +pub struct MixedProcMacroCrate; + +#[derive(SessionDiagnostic)] +#[diag(interface::proc_macro_doc_without_arg)] +pub struct ProcMacroDocWithoutArg; + +#[derive(SessionDiagnostic)] +#[diag(interface::error_writing_dependencies)] +pub struct ErrorWritingDependencies<'a> { + pub path: &'a Path, + pub error: io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::input_file_would_be_overwritten)] +pub struct InputFileWouldBeOverWritten<'a> { + pub path: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::generated_file_conflicts_with_directory)] +pub struct GeneratedFileConflictsWithDirectory<'a> { + pub input_path: &'a Path, + pub dir_path: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::temps_dir_error)] +pub struct TempsDirError; + +#[derive(SessionDiagnostic)] +#[diag(interface::out_dir_error)] +pub struct OutDirError; + +#[derive(SessionDiagnostic)] +#[diag(interface::cant_emit_mir)] +pub struct CantEmitMIR { + pub error: io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::rustc_error_fatal)] +pub struct RustcErrorFatal { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::rustc_error_unexpected_annotation)] +pub struct RustcErrorUnexpectedAnnotation { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(interface::failed_writing_file)] +pub struct FailedWritingFile<'a> { + pub path: &'a Path, + pub error: io::Error, +} diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 94f81b660..949bd02ad 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -176,7 +176,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { let ident = arg.ident().expect("multi-segment cfg key"); names_valid.insert(ident.name.to_string()); } else { - error!("`names()` arguments must be simple identifers"); + error!("`names()` arguments must be simple identifiers"); } } continue 'specs; @@ -204,7 +204,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { continue 'specs; } else { error!( - "`values()` first argument must be a simple identifer" + "`values()` first argument must be a simple identifier" ); } } else if args.is_empty() { @@ -330,9 +330,9 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R } // JUSTIFICATION: before session exists, only config -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { - tracing::trace!("run_compiler"); + trace!("run_compiler"); util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index d443057eb..41cd7b0e9 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,12 +1,18 @@ #![feature(box_patterns)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(once_cell)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + +#[macro_use] +extern crate tracing; mod callbacks; +mod errors; pub mod interface; mod passes; mod proc_macro_decls; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8f0835917..c41b154c3 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1,3 +1,8 @@ +use crate::errors::{ + CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier, + GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate, + MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError, +}; use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; @@ -8,7 +13,7 @@ use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult}; +use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; use rustc_hir::def_id::StableCrateId; use rustc_hir::definitions::Definitions; @@ -33,7 +38,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; -use tracing::{info, warn}; use std::any::Any; use std::cell::RefCell; @@ -64,7 +68,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { } if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); } Ok(krate) @@ -160,7 +164,7 @@ pub fn create_resolver( krate: &ast::Crate, crate_name: &str, ) -> BoxedResolver { - tracing::trace!("create_resolver"); + trace!("create_resolver"); BoxedResolver::new(sess, move |sess, resolver_arenas| { Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas) }) @@ -274,7 +278,7 @@ pub fn configure_and_expand( crate_name: &str, resolver: &mut Resolver<'_>, ) -> Result { - tracing::trace!("configure_and_expand"); + trace!("configure_and_expand"); pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); @@ -374,10 +378,10 @@ pub fn configure_and_expand( if crate_types.len() > 1 { if is_executable_crate { - sess.err("cannot mix `bin` crate type with others"); + sess.emit_err(MixedBinCrate); } if is_proc_macro_crate { - sess.err("cannot mix `proc-macro` crate type with others"); + sess.emit_err(MixedProcMacroCrate); } } @@ -388,13 +392,7 @@ pub fn configure_and_expand( // However, we do emit a warning, to let such users know that they should // start passing '--crate-type proc-macro' if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { - let mut msg = sess.diagnostic().struct_warn( - "Trying to document proc macro crate \ - without passing '--crate-type proc-macro to rustdoc", - ); - - msg.warn("The generated documentation may be incorrect"); - msg.emit(); + sess.emit_warning(ProcMacroDocWithoutArg); } else { krate = sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; @@ -417,7 +415,7 @@ pub fn configure_and_expand( } if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS", "ast-stats-2"); } resolver.resolve_crate(&krate); @@ -443,23 +441,9 @@ pub fn configure_and_expand( spans.sort(); if ident == sym::ferris { let first_span = spans[0]; - sess.diagnostic() - .struct_span_err( - MultiSpan::from(spans), - "Ferris cannot be used as an identifier", - ) - .span_suggestion( - first_span, - "try using their name instead", - "ferris", - Applicability::MaybeIncorrect, - ) - .emit(); + sess.emit_err(FerrisIdentifier { spans, first_span }); } else { - sess.diagnostic().span_err( - MultiSpan::from(spans), - &format!("identifiers cannot contain emoji: `{}`", ident), - ); + sess.emit_err(EmojiIdentifier { spans, ident }); } } }); @@ -589,13 +573,24 @@ fn write_out_deps( // Account for explicitly marked-to-track files // (e.g. accessed in proc macros). let file_depinfo = sess.parse_sess.file_depinfo.borrow(); - let extra_tracked_files = file_depinfo.iter().map(|path_sym| { - let path = PathBuf::from(path_sym.as_str()); + + let normalize_path = |path: PathBuf| { let file = FileName::from(path); escape_dep_filename(&file.prefer_local().to_string()) - }); + }; + + let extra_tracked_files = + file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))); files.extend(extra_tracked_files); + // We also need to track used PGO profile files + if let Some(ref profile_instr) = sess.opts.cg.profile_use { + files.push(normalize_path(profile_instr.as_path().to_path_buf())); + } + if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use { + files.push(normalize_path(profile_sample.as_path().to_path_buf())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { @@ -662,11 +657,9 @@ fn write_out_deps( .emit_artifact_notification(&deps_filename, "dep-info"); } } - Err(e) => sess.fatal(&format!( - "error writing dependencies to `{}`: {}", - deps_filename.display(), - e - )), + Err(error) => { + sess.emit_fatal(ErrorWritingDependencies { path: &deps_filename, error }); + } } } @@ -696,20 +689,12 @@ pub fn prepare_outputs( if let Some(ref input_path) = compiler.input_path { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { - let reported = sess.err(&format!( - "the input file \"{}\" would be overwritten by the generated \ - executable", - input_path.display() - )); + let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); return Err(reported); } - if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { - let reported = sess.err(&format!( - "the generated executable for the input file \"{}\" conflicts with the \ - existing directory \"{}\"", - input_path.display(), - dir_path.display() - )); + if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) { + let reported = + sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path }); return Err(reported); } } @@ -717,8 +702,7 @@ pub fn prepare_outputs( if let Some(ref dir) = compiler.temps_dir { if fs::create_dir_all(dir).is_err() { - let reported = - sess.err("failed to find or create the directory specified by `--temps-dir`"); + let reported = sess.emit_err(TempsDirError); return Err(reported); } } @@ -731,8 +715,7 @@ pub fn prepare_outputs( if !only_dep_info { if let Some(ref dir) = compiler.output_dir { if fs::create_dir_all(dir).is_err() { - let reported = - sess.err("failed to find or create the directory specified by `--out-dir`"); + let reported = sess.emit_err(OutDirError); return Err(reported); } } @@ -907,13 +890,13 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }); }, { - sess.time("liveness_and_intrinsic_checking", || { - tcx.hir().par_for_each_module(|module| { + sess.time("liveness_checking", || { + tcx.hir().par_body_owners(|def_id| { // this must run before MIR dump, because // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? - tcx.ensure().check_mod_liveness(module); + tcx.ensure().check_liveness(def_id.to_def_id()); }); }); } @@ -1015,8 +998,8 @@ pub fn start_codegen<'tcx>( info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { - tcx.sess.err(&format!("could not emit MIR: {}", e)); + if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { + tcx.sess.emit_err(CantEmitMIR { error }); tcx.sess.abort_if_errors(); } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 73402ae08..6c725a01b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,3 +1,4 @@ +use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation}; use crate::interface::{Compiler, Result}; use crate::passes::{self, BoxedResolver, QueryContext}; @@ -165,7 +166,7 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, ) -> Result<&Query<(Lrc, Rc>, Lrc)>> { - tracing::trace!("expansion"); + trace!("expansion"); self.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let (krate, lint_store) = self.register_plugins()?.take(); @@ -274,18 +275,14 @@ impl<'tcx> Queries<'tcx> { // Bare `#[rustc_error]`. None => { - tcx.sess.span_fatal( - tcx.def_span(def_id), - "fatal error triggered by #[rustc_error]", - ); + tcx.sess.emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) }); } // Some other attribute. Some(_) => { - tcx.sess.span_warn( - tcx.def_span(def_id), - "unexpected annotation used with `#[rustc_error(...)]!", - ); + tcx.sess.emit_warning(RustcErrorUnexpectedAnnotation { + span: tcx.def_span(def_id), + }); } } } @@ -360,9 +357,8 @@ impl Linker { if sess.opts.unstable_opts.no_link { let encoded = CodegenResults::serialize_rlink(&codegen_results); let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); - std::fs::write(&rlink_file, encoded).map_err(|err| { - sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); - })?; + std::fs::write(&rlink_file, encoded) + .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; return Ok(()); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a9fdfa241..c7615a577 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#![allow(rustc::bad_opt_access)] use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; @@ -21,10 +21,8 @@ use rustc_session::{build_session, getopts, DiagnosticOutput, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; -use rustc_target::spec::{ - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, -}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; +use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -552,7 +550,7 @@ fn test_codegen_options_tracking_hash() { untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); - untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); + untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc)); untracked!(no_stack_check, true); untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")])); untracked!(rpath, true); @@ -767,6 +765,7 @@ fn test_unstable_options_tracking_hash() { tracked!(no_profiler_runtime, true); tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); + tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(pick_stable_methods_before_any_unstable, false); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 5e5596f13..f7e70d355 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,3 +1,4 @@ +use info; use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; @@ -31,7 +32,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::thread; -use tracing::info; /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box; @@ -559,7 +559,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec LateLintPass<'tcx> for ArrayIntoIter { } // We only care about method call expressions. - if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind { + if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind { if call.ident.name != sym::into_iter { return; } @@ -75,7 +75,6 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { }; // As this is a method call expression, we have at least one argument. - let receiver_arg = &args[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index bd58021f7..0ff2ef5cd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{ + errors::BuiltinEllpisisInclusiveRangePatterns, types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; @@ -58,7 +59,6 @@ use rustc_trait_selection::traits::{self, misc::can_type_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; use std::fmt::Write; -use tracing::{debug, trace}; // hardwired lints from librustc_middle pub use rustc_session::lint::builtin::*; @@ -259,17 +259,8 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) { cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { - let binding = match binding_annot { - hir::BindingAnnotation::Unannotated => None, - hir::BindingAnnotation::Mutable => Some("mut"), - hir::BindingAnnotation::Ref => Some("ref"), - hir::BindingAnnotation::RefMut => Some("ref mut"), - }; - let suggested_ident = if let Some(binding) = binding { - format!("{} {}", binding, ident) - } else { - ident.to_string() - }; + let suggested_ident = + format!("{}{}", binding_annot.prefix_str(), ident); lint.build(fluent::lint::builtin_non_shorthand_field_patterns) .set_arg("ident", ident.clone()) .span_suggestion( @@ -1476,7 +1467,7 @@ impl TypeAliasBounds { if TypeAliasBounds::is_type_variable_assoc(qpath) { self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help); } - intravisit::walk_qpath(self, qpath, id, span) + intravisit::walk_qpath(self, qpath, id) } } @@ -1760,18 +1751,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { None => format!("&(..={})", end), }; if join.edition() >= Edition::Edition2021 { - let mut err = cx.sess().struct_span_err_with_code( - pat.span, - msg, - rustc_errors::error_code!(E0783), - ); - err.span_suggestion( - pat.span, - suggestion, + cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + span: pat.span, + suggestion: pat.span, replace, - Applicability::MachineApplicable, - ) - .emit(); + }); } else { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| { lint.build(msg) @@ -1787,18 +1771,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } else { let replace = "..="; if join.edition() >= Edition::Edition2021 { - let mut err = cx.sess().struct_span_err_with_code( - pat.span, - msg, - rustc_errors::error_code!(E0783), - ); - err.span_suggestion_short( - join, - suggestion, - replace, - Applicability::MachineApplicable, - ) - .emit(); + cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + span: pat.span, + suggestion: join, + replace: replace.to_string(), + }); } else { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| { lint.build(msg) @@ -2023,7 +2000,7 @@ impl KeywordIdents { } impl EarlyLintPass for KeywordIdents { - fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) { + fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) { self.check_tokens(cx, mac_def.body.inner_tokens()); } fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { @@ -2039,13 +2016,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], - index: u32, + def_id: DefId, ) -> Vec> { inferred_outlives .iter() .filter_map(|(pred, _)| match pred.kind().skip_binder() { ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { - ty::ReEarlyBound(ebr) if ebr.index == index => Some(b), + ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, _ => None, @@ -2082,8 +2059,12 @@ impl ExplicitOutlivesRequirements { .filter_map(|(i, bound)| { if let hir::GenericBound::Outlives(lifetime) = bound { let is_inferred = match tcx.named_region(lifetime.hir_id) { - Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { - if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false } + Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| { + if let ty::ReEarlyBound(ebr) = **r { + ebr.def_id == def_id + } else { + false + } }), _ => false, }; @@ -2177,11 +2158,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate { hir::WherePredicate::RegionPredicate(predicate) => { - if let Some(Region::EarlyBound(index, ..)) = + if let Some(Region::EarlyBound(region_def_id)) = cx.tcx.named_region(predicate.lifetime.hir_id) { ( - Self::lifetimes_outliving_lifetime(inferred_outlives, index), + Self::lifetimes_outliving_lifetime( + inferred_outlives, + region_def_id, + ), &predicate.bounds, predicate.span, predicate.in_where_clause, @@ -2419,13 +2403,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { _ => {} } } - } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind { + } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind { // Find problematic calls to `MaybeUninit::assume_init`. let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) { // This is a call to *some* method named `assume_init`. // See if the `self` parameter is one of the dangerous constructors. - if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { + if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; match cx.tcx.get_diagnostic_name(def_id) { @@ -2475,6 +2459,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { Char if init == InitKind::Uninit => { Some(("characters must be a valid Unicode codepoint".to_string(), None)) } + Int(_) | Uint(_) if init == InitKind::Uninit => { + Some(("integers must not be uninitialized".to_string(), None)) + } + Float(_) if init == InitKind::Uninit => { + Some(("floats must not be uninitialized".to_string(), None)) + } + RawPtr(_) if init == InitKind::Uninit => { + Some(("raw pointers must not be uninitialized".to_string(), None)) + } // Recurse and checks for some compound types. Adt(adt_def, substs) if !adt_def.is_union() => { // First check if this ADT has a layout attribute (like `NonNull` and friends). @@ -3170,3 +3163,117 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } } } + +declare_lint! { + /// The `special_module_name` lint detects module + /// declarations for files that have a special meaning. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// mod lib; + /// + /// fn main() { + /// lib::run(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Cargo recognizes `lib.rs` and `main.rs` as the root of a + /// library or binary crate, so declaring them as modules + /// will lead to miscompilation of the crate unless configured + /// explicitly. + /// + /// To access a library from a binary target within the same crate, + /// use `your_crate_name::` as the path path instead of `lib::`: + /// + /// ```rust,compile_fail + /// // bar/src/lib.rs + /// fn run() { + /// // ... + /// } + /// + /// // bar/src/main.rs + /// fn main() { + /// bar::run(); + /// } + /// ``` + /// + /// Binary targets cannot be used as libraries and so declaring + /// one as a module is not allowed. + pub SPECIAL_MODULE_NAME, + Warn, + "module declarations for files with a special meaning", +} + +declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]); + +impl EarlyLintPass for SpecialModuleName { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { + for item in &krate.items { + if let ast::ItemKind::Mod( + _, + ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _), + ) = item.kind + { + if item.attrs.iter().any(|a| a.has_name(sym::path)) { + continue; + } + + match item.ident.name.as_str() { + "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for lib.rs") + .note("lib.rs is the root of this crate's library target") + .help("to refer to it from other targets, use the library's name as the path") + .emit() + }), + "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for main.rs") + .note("a binary crate cannot be used as library") + .emit() + }), + _ => continue + } + } + } + } +} + +pub use rustc_session::lint::builtin::UNEXPECTED_CFGS; + +declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]); + +impl EarlyLintPass for UnexpectedCfgs { + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { + let cfg = &cx.sess().parse_sess.config; + let check_cfg = &cx.sess().parse_sess.check_config; + for &(name, value) in cfg { + if let Some(names_valid) = &check_cfg.names_valid { + if !names_valid.contains(&name) { + cx.lookup(UNEXPECTED_CFGS, None::, |diag| { + diag.build(fluent::lint::builtin_unexpected_cli_config_name) + .help(fluent::lint::help) + .set_arg("name", name) + .emit(); + }); + } + } + if let Some(value) = value { + if let Some(values) = &check_cfg.values_valid.get(&name) { + if !values.contains(&value) { + cx.lookup(UNEXPECTED_CFGS, None::, |diag| { + diag.build(fluent::lint::builtin_unexpected_cli_config_value) + .help(fluent::lint::help) + .set_arg("name", name) + .set_arg("value", value) + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b95fc341d..7ca6ec5d9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,12 +16,16 @@ use self::TargetLint::*; +use crate::errors::{ + CheckNameDeprecated, CheckNameUnknown, CheckNameUnknownTool, CheckNameWarning, RequestedLevel, + UnsupportedGroup, +}; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err}; +use rustc_errors::add_elided_lifetime_in_path_suggestion; use rustc_errors::{ Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle, }; @@ -39,14 +43,17 @@ use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintI use rustc_session::Session; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, Span}; use rustc_target::abi; -use tracing::debug; use std::cell::Cell; use std::iter; use std::slice; +type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync; +type LateLintPassFactory = + dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync; + /// Information about the registered lints. /// /// This is basically the subset of `Context` that we can @@ -61,11 +68,11 @@ pub struct LintStore { /// interior mutability, we don't enforce this (and lints should, in theory, /// be compatible with being constructed more than once, though not /// necessarily in a sane manner. This is safe though.) - pub pre_expansion_passes: Vec EarlyLintPassObject + sync::Send + sync::Sync>>, - pub early_passes: Vec EarlyLintPassObject + sync::Send + sync::Sync>>, - pub late_passes: Vec LateLintPassObject + sync::Send + sync::Sync>>, + pub pre_expansion_passes: Vec>, + pub early_passes: Vec>, + pub late_passes: Vec>, /// This is unique in that we construct them per-module, so not once. - pub late_module_passes: Vec LateLintPassObject + sync::Send + sync::Sync>>, + pub late_module_passes: Vec>, /// Lints indexed by name. by_name: FxHashMap, @@ -183,14 +190,20 @@ impl LintStore { pub fn register_late_pass( &mut self, - pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + + 'static + + sync::Send + + sync::Sync, ) { self.late_passes.push(Box::new(pass)); } pub fn register_late_mod_pass( &mut self, - pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + + 'static + + sync::Send + + sync::Sync, ) { self.late_module_passes.push(Box::new(pass)); } @@ -326,68 +339,41 @@ impl LintStore { ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { - struct_span_err!( - sess, - DUMMY_SP, - E0602, - "`{}` lint group is not supported with ´--force-warn´", - crate::WARNINGS.name_lower() - ) - .emit(); + sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); return; } - let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) { - CheckLintNameResult::Ok(_) => None, - CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), + let lint_name = lint_name.to_string(); + match self.check_lint_name(lint_name_only, tool_name, registered_tools) { + CheckLintNameResult::Warning(msg, _) => { + sess.emit_warning(CheckNameWarning { + msg, + sub: RequestedLevel { level, lint_name }, + }); + } CheckLintNameResult::NoLint(suggestion) => { - let mut err = - struct_span_err!(sess, DUMMY_SP, E0602, "unknown lint: `{}`", lint_name); - - if let Some(suggestion) = suggestion { - err.help(&format!("did you mean: `{}`", suggestion)); + sess.emit_err(CheckNameUnknown { + lint_name: lint_name.clone(), + suggestion, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::Tool(result) => { + if let Err((Some(_), new_name)) = result { + sess.emit_warning(CheckNameDeprecated { + lint_name: lint_name.clone(), + new_name, + sub: RequestedLevel { level, lint_name }, + }); } - - Some(err.forget_guarantee()) } - CheckLintNameResult::Tool(result) => match result { - Err((Some(_), new_name)) => Some(sess.struct_warn(&format!( - "lint name `{}` is deprecated \ - and does not have an effect anymore. \ - Use: {}", - lint_name, new_name - ))), - _ => None, - }, - CheckLintNameResult::NoTool => Some( - struct_span_err!( - sess, - DUMMY_SP, - E0602, - "unknown lint tool: `{}`", - tool_name.unwrap() - ) - .forget_guarantee(), - ), + CheckLintNameResult::NoTool => { + sess.emit_err(CheckNameUnknownTool { + tool_name: tool_name.unwrap(), + sub: RequestedLevel { level, lint_name }, + }); + } + _ => {} }; - - if let Some(mut db) = db { - let msg = format!( - "requested on the command line with `{} {}`", - match level { - Level::Allow => "-A", - Level::Warn => "-W", - Level::ForceWarn(_) => "--force-warn", - Level::Deny => "-D", - Level::Forbid => "-F", - Level::Expect(_) => { - unreachable!("lints with the level of `expect` should not run this code"); - } - }, - lint_name - ); - db.note(&msg); - db.emit(); - } } /// True if this symbol represents a lint group name. @@ -440,7 +426,7 @@ impl LintStore { None => { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? - tracing::debug!("lints={:?}", self.by_name.keys().collect::>()); + debug!("lints={:?}", self.by_name.keys().collect::>()); let tool_prefix = format!("{}::", tool_name); return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name) @@ -533,7 +519,7 @@ impl LintStore { CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) } Some(other) => { - tracing::debug!("got renamed lint {:?}", other); + debug!("got renamed lint {:?}", other); CheckLintNameResult::NoLint(None) } } @@ -582,7 +568,7 @@ pub trait LintPassObject: Sized {} impl LintPassObject for EarlyLintPassObject {} -impl LintPassObject for LateLintPassObject {} +impl LintPassObject for LateLintPassObject<'_> {} pub trait LintContext: Sized { type PassObject: LintPassObject; @@ -865,9 +851,14 @@ pub trait LintContext: Sized { if let Some(positional_arg_to_replace) = position_sp_to_replace { let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name }; - + let span_to_replace = if let Ok(positional_arg_content) = + self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(':') { + positional_arg_to_replace.shrink_to_lo() + } else { + positional_arg_to_replace + }; db.span_suggestion_verbose( - positional_arg_to_replace, + span_to_replace, "use the named argument by name to avoid ambiguity", name, Applicability::MaybeIncorrect, @@ -968,8 +959,8 @@ impl<'a> EarlyContext<'a> { } } -impl LintContext for LateContext<'_> { - type PassObject = LateLintPassObject; +impl<'tcx> LintContext for LateContext<'tcx> { + type PassObject = LateLintPassObject<'tcx>; /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index d13711c3a..96ecd79a6 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -26,7 +26,6 @@ use rustc_span::symbol::Ident; use rustc_span::Span; use std::slice; -use tracing::debug; macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); @@ -45,7 +44,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { lint_id.lint, Some(span), |lint| { - lint.build(&msg).emit(); + lint.build(msg).emit(); }, diagnostic, ); @@ -101,6 +100,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_pat_post, p); } + fn visit_pat_field(&mut self, field: &'a ast::PatField) { + self.with_lint_attrs(field.id, &field.attrs, |cx| { + ast_visit::walk_pat_field(cx, field); + }); + } + fn visit_anon_const(&mut self, c: &'a ast::AnonConst) { self.check_id(c.id); ast_visit::walk_anon_const(self, c); @@ -142,7 +147,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) { run_early_pass!(self, check_fn, fk, span, id); self.check_id(id); - ast_visit::walk_fn(self, fk, span); + ast_visit::walk_fn(self, fk); // Explicitly check for lints associated with 'closure_id', since // it does not have a corresponding AST node @@ -219,9 +224,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { - run_early_pass!(self, check_generic_param, param); - self.check_id(param.id); - ast_visit::walk_generic_param(self, param); + self.with_lint_attrs(param.id, ¶m.attrs, |cx| { + run_early_pass!(cx, check_generic_param, param); + ast_visit::walk_generic_param(cx, param); + }); } fn visit_generics(&mut self, g: &'a ast::Generics) { @@ -233,9 +239,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_where_predicate(self, p); } - fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) { - run_early_pass!(self, check_poly_trait_ref, t, m); - ast_visit::walk_poly_trait_ref(self, t, m); + fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { + run_early_pass!(self, check_poly_trait_ref, t); + ast_visit::walk_poly_trait_ref(self, t); } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) { @@ -260,9 +266,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_path(self, p); } - fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) { + fn visit_path_segment(&mut self, s: &'a ast::PathSegment) { self.check_id(s.id); - ast_visit::walk_path_segment(self, path_span, s); + ast_visit::walk_path_segment(self, s); } fn visit_attribute(&mut self, attr: &'a ast::Attribute) { @@ -270,7 +276,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) { - run_early_pass!(self, check_mac_def, mac, id); + run_early_pass!(self, check_mac_def, mac); self.check_id(id); } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs new file mode 100644 index 000000000..5c183d409 --- /dev/null +++ b/compiler/rustc_lint/src/errors.rs @@ -0,0 +1,162 @@ +use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed, Handler}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_session::{lint::Level, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(lint::overruled_attribute, code = "E0453")] +pub struct OverruledAttribute { + #[primary_span] + pub span: Span, + #[label] + pub overruled: Span, + pub lint_level: String, + pub lint_source: Symbol, + #[subdiagnostic] + pub sub: OverruledAttributeSub, +} +// +pub enum OverruledAttributeSub { + DefaultSource { id: String }, + NodeSource { span: Span, reason: Option }, + CommandLineSource, +} + +impl AddSubdiagnostic for OverruledAttributeSub { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + OverruledAttributeSub::DefaultSource { id } => { + diag.note(fluent::lint::default_source); + diag.set_arg("id", id); + } + OverruledAttributeSub::NodeSource { span, reason } => { + diag.span_label(span, fluent::lint::node_source); + if let Some(rationale) = reason { + diag.note(rationale.as_str()); + } + } + OverruledAttributeSub::CommandLineSource => { + diag.note(fluent::lint::command_line_source); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::malformed_attribute, code = "E0452")] +pub struct MalformedAttribute { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: MalformedAttributeSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum MalformedAttributeSub { + #[label(lint::bad_attribute_argument)] + BadAttributeArgument(#[primary_span] Span), + #[label(lint::reason_must_be_string_literal)] + ReasonMustBeStringLiteral(#[primary_span] Span), + #[label(lint::reason_must_come_last)] + ReasonMustComeLast(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")] +pub struct UnknownToolInScopedLint { + #[primary_span] + pub span: Option, + pub tool_name: Symbol, + pub lint_name: String, + #[help] + pub is_nightly_build: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")] +pub struct BuiltinEllpisisInclusiveRangePatterns { + #[primary_span] + pub span: Span, + #[suggestion_short(code = "{replace}", applicability = "machine-applicable")] + pub suggestion: Span, + pub replace: String, +} + +pub struct RequestedLevel { + pub level: Level, + pub lint_name: String, +} + +impl AddSubdiagnostic for RequestedLevel { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + diag.note(fluent::lint::requested_level); + diag.set_arg( + "level", + match self.level { + Level::Allow => "-A", + Level::Warn => "-W", + Level::ForceWarn(_) => "--force-warn", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Expect(_) => { + unreachable!("lints with the level of `expect` should not run this code"); + } + }, + ); + diag.set_arg("lint_name", self.lint_name); + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::unsupported_group, code = "E0602")] +pub struct UnsupportedGroup { + pub lint_group: String, +} + +pub struct CheckNameUnknown { + pub lint_name: String, + pub suggestion: Option, + pub sub: RequestedLevel, +} + +impl SessionDiagnostic<'_> for CheckNameUnknown { + fn into_diagnostic( + self, + handler: &Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::lint::check_name_unknown); + diag.code(rustc_errors::error_code!(E0602)); + if let Some(suggestion) = self.suggestion { + diag.help(fluent::lint::help); + diag.set_arg("suggestion", suggestion); + } + diag.set_arg("lint_name", self.lint_name); + diag.subdiagnostic(self.sub); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_unknown_tool, code = "E0602")] +pub struct CheckNameUnknownTool { + pub tool_name: Symbol, + #[subdiagnostic] + pub sub: RequestedLevel, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_warning)] +pub struct CheckNameWarning { + pub msg: String, + #[subdiagnostic] + pub sub: RequestedLevel, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_deprecated)] +pub struct CheckNameDeprecated { + pub lint_name: String, + pub new_name: String, + #[subdiagnostic] + pub sub: RequestedLevel, +} diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index fe2712525..8f2222132 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -120,8 +120,8 @@ impl EarlyLintPass for HiddenUnicodeCodepoints { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString` let (text, span, padding) = match &expr.kind { - ast::ExprKind::Lit(ast::Lit { token, kind, span }) => { - let text = token.symbol; + ast::ExprKind::Lit(ast::Lit { token_lit, kind, span }) => { + let text = token_lit.symbol; if !contains_text_flow_control_chars(text.as_str()) { return; } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c26d78247..dd1fc5916 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -12,7 +12,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use tracing::debug; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -52,7 +51,7 @@ fn typeck_results_of_method_fn<'tcx>( expr: &Expr<'_>, ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> { match expr.kind { - ExprKind::MethodCall(segment, _, _) + ExprKind::MethodCall(segment, ..) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id))) @@ -119,8 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { _: rustc_hir::HirId, ) { if let Some(segment) = path.segments.iter().nth_back(1) - && let Some(res) = &segment.res - && lint_ty_kind_usage(cx, res) + && lint_ty_kind_usage(cx, &segment.res) { let span = path.span.with_hi( segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() @@ -393,8 +391,14 @@ impl LateLintPass<'_> for Diagnostics { return; } + let mut found_parent_with_attr = false; let mut found_impl = false; - for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { + for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { + if let Some(owner_did) = hir_id.as_owner() { + found_parent_with_attr = found_parent_with_attr + || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics); + } + debug!(?parent); if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent && let Impl { of_trait: Some(of_trait), .. } = impl_ && @@ -407,7 +411,7 @@ impl LateLintPass<'_> for Diagnostics { } } debug!(?found_impl); - if !found_impl { + if !found_parent_with_attr && !found_impl { cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { lint.build(fluent::lint::diag_out_of_impl).emit(); }) @@ -425,7 +429,7 @@ impl LateLintPass<'_> for Diagnostics { } } debug!(?found_diagnostic_message); - if !found_diagnostic_message { + if !found_parent_with_attr && !found_diagnostic_message { cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { lint.build(fluent::lint::untranslatable_diag).emit(); }) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index a329b3751..da6f1c5ee 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -24,13 +24,11 @@ use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::LintPass; -use rustc_span::symbol::Symbol; use rustc_span::Span; use std::any::Any; use std::cell::Cell; use std::slice; -use tracing::debug; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. @@ -78,8 +76,8 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { self.context.param_env = old_param_env; } - fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) { - lint_callback!(self, check_mod, m, s, n); + fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: hir::HirId) { + lint_callback!(self, check_mod, m, n); hir_visit::walk_mod(self, m, n); } } @@ -189,19 +187,12 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let old_cached_typeck_results = self.context.cached_typeck_results.take(); let body = self.context.tcx.hir().body(body_id); lint_callback!(self, check_fn, fk, decl, body, span, id); - hir_visit::walk_fn(self, fk, decl, body_id, span, id); + hir_visit::walk_fn(self, fk, decl, body_id, id); self.context.enclosing_body = old_enclosing_body; self.context.cached_typeck_results.set(old_cached_typeck_results); } - fn visit_variant_data( - &mut self, - s: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &'tcx hir::Generics<'tcx>, - _: hir::HirId, - _: Span, - ) { + fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) { lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); } @@ -213,15 +204,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas }) } - fn visit_variant( - &mut self, - v: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { self.with_lint_attrs(v.id, |cx| { lint_callback!(cx, check_variant, v); - hir_visit::walk_variant(cx, v, g, item_id); + hir_visit::walk_variant(cx, v); }) } @@ -234,9 +220,9 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_inf(self, inf); } - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: hir::HirId) { if !self.context.only_module { - self.process_mod(m, s, n); + self.process_mod(m, n); } } @@ -272,13 +258,9 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_where_predicate(self, p); } - fn visit_poly_trait_ref( - &mut self, - t: &'tcx hir::PolyTraitRef<'tcx>, - m: hir::TraitBoundModifier, - ) { - lint_callback!(self, check_poly_trait_ref, t, m); - hir_visit::walk_poly_trait_ref(self, t, m); + fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) { + lint_callback!(self, check_poly_trait_ref, t); + hir_visit::walk_poly_trait_ref(self, t); } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { @@ -320,12 +302,12 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } } -struct LateLintPassObjects<'a> { - lints: &'a mut [LateLintPassObject], +struct LateLintPassObjects<'a, 'tcx> { + lints: &'a mut [LateLintPassObject<'tcx>], } #[allow(rustc::lint_pass_impl_without_macro)] -impl LintPass for LateLintPassObjects<'_> { +impl LintPass for LateLintPassObjects<'_, '_> { fn name(&self) -> &'static str { panic!() } @@ -343,7 +325,7 @@ macro_rules! expand_late_lint_pass_impl_methods { macro_rules! late_lint_pass_impl { ([], [$hir:tt], $methods:tt) => { - impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> { + impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> { expand_late_lint_pass_impl_methods!([$hir], $methods); } }; @@ -372,8 +354,8 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( let mut cx = LateContextAndPass { context, pass }; - let (module, span, hir_id) = tcx.hir().get_module(module_def_id); - cx.process_mod(module, span, hir_id); + let (module, _span, hir_id) = tcx.hir().get_module(module_def_id); + cx.process_mod(module, hir_id); // Visit the crate attributes if hir_id == hir::CRATE_HIR_ID { @@ -396,7 +378,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( late_lint_mod_pass(tcx, module_def_id, builtin_lints); let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); if !passes.is_empty() { late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); @@ -432,7 +414,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) } fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { - let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::>(); + let mut passes = + unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::>(); if !tcx.sess.opts.unstable_opts.no_interleave_lints { if !passes.is_empty() { @@ -448,7 +431,7 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints } let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); for pass in &mut passes { tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run( diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs new file mode 100644 index 000000000..7e885e6c5 --- /dev/null +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -0,0 +1,175 @@ +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan}; +use rustc_hir as hir; +use rustc_middle::ty; +use rustc_span::Symbol; + +declare_lint! { + /// The `let_underscore_drop` lint checks for statements which don't bind + /// an expression which has a non-trivial Drop implementation to anything, + /// causing the expression to be dropped immediately instead of at end of + /// scope. + /// + /// ### Example + /// ``` + /// struct SomeStruct; + /// impl Drop for SomeStruct { + /// fn drop(&mut self) { + /// println!("Dropping SomeStruct"); + /// } + /// } + /// + /// fn main() { + /// #[warn(let_underscore_drop)] + /// // SomeStuct is dropped immediately instead of at end of scope, + /// // so "Dropping SomeStruct" is printed before "end of main". + /// // The order of prints would be reversed if SomeStruct was bound to + /// // a name (such as "_foo"). + /// let _ = SomeStruct; + /// println!("end of main"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `MutexGuard`, which are typically used to + /// lock a mutex for the duration of an entire scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_DROP, + Allow, + "non-binding let on a type that implements `Drop`" +} + +declare_lint! { + /// The `let_underscore_lock` lint checks for statements which don't bind + /// a mutex to anything, causing the lock to be released immediately instead + /// of at end of scope, which is typically incorrect. + /// + /// ### Example + /// ```compile_fail + /// use std::sync::{Arc, Mutex}; + /// use std::thread; + /// let data = Arc::new(Mutex::new(0)); + /// + /// thread::spawn(move || { + /// // The lock is immediately released instead of at the end of the + /// // scope, which is probably not intended. + /// let _ = data.lock().unwrap(); + /// println!("doing some work"); + /// let mut lock = data.lock().unwrap(); + /// *lock += 1; + /// }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `MutexGuard`, which are typically used to + /// lock a mutex for the duration of an entire scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_LOCK, + Deny, + "non-binding let on a synchronization lock" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); + +const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ + rustc_span::sym::MutexGuard, + rustc_span::sym::RwLockReadGuard, + rustc_span::sym::RwLockWriteGuard, +]; + +impl<'tcx> LateLintPass<'tcx> for LetUnderscore { + fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { + if !matches!(local.pat.kind, hir::PatKind::Wild) { + return; + } + if let Some(init) = local.init { + let init_ty = cx.typeck_results().expr_ty(init); + // If the type has a trivial Drop implementation, then it doesn't + // matter that we drop the value immediately. + if !init_ty.needs_drop(cx.tcx, cx.param_env) { + return; + } + let is_sync_lock = match init_ty.kind() { + ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS + .iter() + .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), + _ => false, + }; + + if is_sync_lock { + let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); + span.push_span_label( + local.pat.span, + "this lock is not assigned to a binding and is immediately dropped".to_string(), + ); + span.push_span_label( + init.span, + "this binding will immediately drop the value assigned to it".to_string(), + ); + cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| { + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a synchronization lock", + ) + }) + } else { + cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a type that implements `Drop`", + ); + }) + } + } + } +} + +fn build_and_emit_lint( + lint: LintDiagnosticBuilder<'_, ()>, + local: &hir::Local<'_>, + init_span: rustc_span::Span, + msg: &str, +) { + lint.build(msg) + .span_suggestion_verbose( + local.pat.span, + "consider binding to an unused variable to avoid immediately dropping the value", + "_unused", + Applicability::MachineApplicable, + ) + .multipart_suggestion( + "consider immediately dropping the value", + vec![ + (local.span.until(init_span), "drop(".to_string()), + (init_span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 00e96f20d..1e16ac51e 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,7 +3,7 @@ use crate::late::unerased_lint_store; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; @@ -21,7 +21,11 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use tracing::debug; + +use crate::errors::{ + MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub, + UnknownToolInScopedLint, +}; fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { let store = unerased_lint_store(tcx); @@ -186,16 +190,26 @@ impl<'s> LintLevelsBuilder<'s> { } }; if !fcw_warning { - let mut diag_builder = struct_span_err!( - self.sess, - src.span(), - E0453, - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), - ); - decorate_diag(&mut diag_builder); - diag_builder.emit(); + self.sess.emit_err(OverruledAttribute { + span: src.span(), + overruled: src.span(), + lint_level: level.as_str().to_string(), + lint_source: src.name(), + sub: match old_src { + LintLevelSource::Default => { + OverruledAttributeSub::DefaultSource { id: id.to_string() } + } + LintLevelSource::Node(_, forbid_source_span, reason) => { + OverruledAttributeSub::NodeSource { + span: forbid_source_span, + reason, + } + } + LintLevelSource::CommandLine(_, _) => { + OverruledAttributeSub::CommandLineSource + } + }, + }); } else { self.struct_lint( FORBIDDEN_LINT_GROUPS, @@ -266,7 +280,6 @@ impl<'s> LintLevelsBuilder<'s> { self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); let sess = self.sess; - let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); for (attr_index, attr) in attrs.iter().enumerate() { if attr.has_name(sym::automatically_derived) { self.current_specs_mut().insert( @@ -317,20 +330,27 @@ impl<'s> LintLevelsBuilder<'s> { } reason = Some(rationale); } else { - bad_attr(name_value.span) - .span_label(name_value.span, "reason must be a string literal") - .emit(); + sess.emit_err(MalformedAttribute { + span: name_value.span, + sub: MalformedAttributeSub::ReasonMustBeStringLiteral( + name_value.span, + ), + }); } // found reason, reslice meta list to exclude it metas.pop().unwrap(); } else { - bad_attr(item.span) - .span_label(item.span, "bad attribute argument") - .emit(); + sess.emit_err(MalformedAttribute { + span: item.span, + sub: MalformedAttributeSub::BadAttributeArgument(item.span), + }); } } ast::MetaItemKind::List(_) => { - bad_attr(item.span).span_label(item.span, "bad attribute argument").emit(); + sess.emit_err(MalformedAttribute { + span: item.span, + sub: MalformedAttributeSub::BadAttributeArgument(item.span), + }); } } } @@ -348,20 +368,21 @@ impl<'s> LintLevelsBuilder<'s> { let meta_item = match li { ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item, _ => { - let mut err = bad_attr(sp); - let mut add_label = true; if let Some(item) = li.meta_item() { if let ast::MetaItemKind::NameValue(_) = item.kind { if item.path == sym::reason { - err.span_label(sp, "reason in lint attribute must come last"); - add_label = false; + sess.emit_err(MalformedAttribute { + span: sp, + sub: MalformedAttributeSub::ReasonMustComeLast(sp), + }); + continue; } } } - if add_label { - err.span_label(sp, "bad attribute argument"); - } - err.emit(); + sess.emit_err(MalformedAttribute { + span: sp, + sub: MalformedAttributeSub::BadAttributeArgument(sp), + }); continue; } }; @@ -419,8 +440,10 @@ impl<'s> LintLevelsBuilder<'s> { sp, reason, ); - for id in ids { - self.insert_spec(*id, (level, src)); + for &id in ids { + if self.check_gated_lint(id, attr.span) { + self.insert_spec(id, (level, src)); + } } if let Level::Expect(expect_id) = level { self.lint_expectations.push(( @@ -485,22 +508,12 @@ impl<'s> LintLevelsBuilder<'s> { } &CheckLintNameResult::NoTool => { - let mut err = struct_span_err!( - sess, - tool_ident.map_or(DUMMY_SP, |ident| ident.span), - E0710, - "unknown tool name `{}` found in scoped lint: `{}::{}`", - tool_name.unwrap(), - tool_name.unwrap(), - pprust::path_to_string(&meta_item.path), - ); - if sess.is_nightly_build() { - err.help(&format!( - "add `#![register_tool({})]` to the crate root", - tool_name.unwrap() - )); - } - err.emit(); + sess.emit_err(UnknownToolInScopedLint { + span: tool_ident.map(|ident| ident.span), + tool_name: tool_name.unwrap(), + lint_name: pprust::path_to_string(&meta_item.path), + is_nightly_build: sess.is_nightly_build().then_some(()), + }); continue; } @@ -766,20 +779,21 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { }) } + fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_expr_field(builder, field); + }) + } + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { self.with_lint_attrs(s.hir_id, |builder| { intravisit::walk_field_def(builder, s); }) } - fn visit_variant( - &mut self, - v: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { self.with_lint_attrs(v.id, |builder| { - intravisit::walk_variant(builder, v, g, item_id); + intravisit::walk_variant(builder, v); }) } @@ -806,6 +820,18 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::walk_impl_item(builder, impl_item); }); } + + fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_pat_field(builder, field); + }) + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + self.with_lint_attrs(p.hir_id, |builder| { + intravisit::walk_generic_param(builder, p); + }); + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 389a0b5d1..752a751f6 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -34,7 +34,7 @@ #![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![recursion_limit = "256"] @@ -42,16 +42,20 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; +#[macro_use] +extern crate tracing; mod array_into_iter; pub mod builtin; mod context; mod early; mod enum_intrinsics_non_enums; +mod errors; mod expect; pub mod hidden_unicode_codepoints; mod internal; mod late; +mod let_underscore; mod levels; mod methods; mod non_ascii_idents; @@ -83,6 +87,7 @@ use builtin::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use hidden_unicode_codepoints::*; use internal::*; +use let_underscore::*; use methods::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; @@ -130,6 +135,7 @@ macro_rules! early_lint_passes { UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, + SpecialModuleName: SpecialModuleName, AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, @@ -140,6 +146,7 @@ macro_rules! early_lint_passes { IncompleteFeatures: IncompleteFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, + UnexpectedCfgs: UnexpectedCfgs, ] ); }; @@ -185,6 +192,7 @@ macro_rules! late_lint_mod_passes { VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, + LetUnderscore: LetUnderscore, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, NonUpperCaseGlobals: NonUpperCaseGlobals, @@ -252,26 +260,41 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { ) } - macro_rules! register_pass { + macro_rules! register_early_pass { ($method:ident, $ty:ident, $constructor:expr) => { store.register_lints(&$ty::get_lints()); store.$method(|| Box::new($constructor)); }; } - macro_rules! register_passes { + macro_rules! register_late_pass { + ($method:ident, $ty:ident, $constructor:expr) => { + store.register_lints(&$ty::get_lints()); + store.$method(|_| Box::new($constructor)); + }; + } + + macro_rules! register_early_passes { ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( $( - register_pass!($method, $passes, $constructor); + register_early_pass!($method, $passes, $constructor); + )* + ) + } + + macro_rules! register_late_passes { + ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( + $( + register_late_pass!($method, $passes, $constructor); )* ) } if no_interleave_lints { - pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass); - early_lint_passes!(register_passes, register_early_pass); - late_lint_passes!(register_passes, register_late_pass); - late_lint_mod_passes!(register_passes, register_late_mod_pass); + pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass); + early_lint_passes!(register_early_passes, register_early_pass); + late_lint_passes!(register_late_passes, register_late_pass); + late_lint_mod_passes!(register_late_passes, register_late_mod_pass); } else { store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); @@ -311,6 +334,8 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { REDUNDANT_SEMICOLONS ); + add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); + add_lint_group!( "rust_2018_idioms", BARE_TRAIT_OBJECTS, @@ -500,19 +525,19 @@ fn register_internals(store: &mut LintStore) { store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| Box::new(LintPassImpl)); store.register_lints(&DefaultHashTypes::get_lints()); - store.register_late_pass(|| Box::new(DefaultHashTypes)); + store.register_late_pass(|_| Box::new(DefaultHashTypes)); store.register_lints(&QueryStability::get_lints()); - store.register_late_pass(|| Box::new(QueryStability)); + store.register_late_pass(|_| Box::new(QueryStability)); store.register_lints(&ExistingDocKeyword::get_lints()); - store.register_late_pass(|| Box::new(ExistingDocKeyword)); + store.register_late_pass(|_| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); - store.register_late_pass(|| Box::new(TyTyKind)); + store.register_late_pass(|_| Box::new(TyTyKind)); store.register_lints(&Diagnostics::get_lints()); - store.register_late_pass(|| Box::new(Diagnostics)); + store.register_late_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::get_lints()); - store.register_late_pass(|| Box::new(BadOptAccess)); + store.register_late_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); - store.register_late_pass(|| Box::new(PassByValue)); + store.register_late_pass(|_| Box::new(PassByValue)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index ff5a01749..5f7f03480 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -44,9 +44,13 @@ fn in_macro(span: Span) -> bool { fn first_method_call<'tcx>( expr: &'tcx Expr<'tcx>, -) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> { - if let ExprKind::MethodCall(path, args, _) = &expr.kind { - if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) } +) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind { + if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() { + None + } else { + Some((path, *receiver)) + } } else { None } @@ -59,15 +63,13 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { } match first_method_call(expr) { - Some((path, args)) if path.ident.name == sym::as_ptr => { - let unwrap_arg = &args[0]; + Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => { let as_ptr_span = path.ident.span; match first_method_call(unwrap_arg) { - Some((path, args)) + Some((path, receiver)) if path.ident.name == sym::unwrap || path.ident.name == sym::expect => { - let source_arg = &args[0]; - lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg); + lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg); } _ => return, } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 8d04d68bf..768ad8483 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -327,13 +327,7 @@ impl NonSnakeCase { } impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { - fn check_mod( - &mut self, - cx: &LateContext<'_>, - _: &'tcx hir::Mod<'tcx>, - _: Span, - id: hir::HirId, - ) { + fn check_mod(&mut self, cx: &LateContext<'_>, _: &'tcx hir::Mod<'tcx>, id: hir::HirId) { if id != hir::CRATE_HIR_ID { return; } @@ -437,19 +431,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { if let PatKind::Binding(_, hid, ident, _) = p.kind { - if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) + if let hir::Node::PatField(field) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) { - if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind { - if field_pats - .iter() - .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id) - { - // Only check if a new name has been introduced, to avoid warning - // on both the struct definition and this pattern. - self.check_snake_case(cx, "variable", &ident); - } - return; + if !field.is_shorthand { + // Only check if a new name has been introduced, to avoid warning + // on both the struct definition and this pattern. + self.check_snake_case(cx, "variable", &ident); } + return; } self.check_snake_case(cx, "variable", &ident); } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 11a752ff0..d1449496d 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -41,7 +41,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls. - let ExprKind::MethodCall(call, elements, _) = &expr.kind else { + let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else { return }; // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` @@ -81,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { ) { return; } - let receiver = &elements[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); if receiver_ty != expr_ty { diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index cb7bd407e..1c6a057d1 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -16,7 +16,7 @@ macro_rules! late_lint_methods { fn check_body_post(a: &$hir hir::Body<$hir>); fn check_crate(); fn check_crate_post(); - fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId); + fn check_mod(a: &$hir hir::Mod<$hir>, b: hir::HirId); fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>); fn check_item(a: &$hir hir::Item<$hir>); fn check_item_post(a: &$hir hir::Item<$hir>); @@ -31,7 +31,7 @@ macro_rules! late_lint_methods { fn check_ty(a: &$hir hir::Ty<$hir>); fn check_generic_param(a: &$hir hir::GenericParam<$hir>); fn check_generics(a: &$hir hir::Generics<$hir>); - fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>, b: hir::TraitBoundModifier); + fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>); fn check_fn( a: rustc_hir::intravisit::FnKind<$hir>, b: &$hir hir::FnDecl<$hir>, @@ -156,14 +156,13 @@ macro_rules! early_lint_methods { fn check_generic_arg(a: &ast::GenericArg); fn check_generic_param(a: &ast::GenericParam); fn check_generics(a: &ast::Generics); - fn check_poly_trait_ref(a: &ast::PolyTraitRef, - b: &ast::TraitBoundModifier); + fn check_poly_trait_ref(a: &ast::PolyTraitRef); fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId); fn check_trait_item(a: &ast::AssocItem); fn check_impl_item(a: &ast::AssocItem); fn check_variant(a: &ast::Variant); fn check_attribute(a: &ast::Attribute); - fn check_mac_def(a: &ast::MacroDef, b: ast::NodeId); + fn check_mac_def(a: &ast::MacroDef); fn check_mac(a: &ast::MacCall); /// Called when entering a syntax node that can have lint attributes such @@ -244,6 +243,5 @@ macro_rules! declare_combined_early_lint_pass { } /// A lint pass boxed up as a trait object. -pub type EarlyLintPassObject = Box; -pub type LateLintPassObject = - Box LateLintPass<'tcx> + sync::Send + sync::Sync + 'static>; +pub type EarlyLintPassObject = Box; +pub type LateLintPassObject<'tcx> = Box + sync::Send + 'tcx>; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5c07afeb7..4fb6d65a6 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -19,7 +19,6 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; use std::iter; use std::ops::ControlFlow; -use tracing::debug; declare_lint! { /// The `unused_comparisons` lint detects comparisons made useless by @@ -125,45 +124,51 @@ fn lint_overflowing_range_endpoint<'tcx>( lit_val: u128, max: u128, expr: &'tcx hir::Expr<'tcx>, - parent_expr: &'tcx hir::Expr<'tcx>, ty: &str, ) -> bool { // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. + let par_id = cx.tcx.hir().get_parent_node(expr.hir_id); + let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false }; + let field_par_id = cx.tcx.hir().get_parent_node(field.hir_id); + let Node::Expr(struct_expr) = cx.tcx.hir().get(field_par_id) else { return false }; + if !is_range_literal(struct_expr) { + return false; + }; + let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false }; + if eps.len() != 2 { + return false; + } + let mut overwritten = false; - if let ExprKind::Struct(_, eps, _) = &parent_expr.kind { - if eps.len() != 2 { - return false; - } - // We can suggest using an inclusive range - // (`..=`) instead only if it is the `end` that is - // overflowing and only by 1. - if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { - cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| { - let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); - err.set_arg("ty", ty); - if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { - use ast::{LitIntType, LitKind}; - // We need to preserve the literal's suffix, - // as it may determine typing information. - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); - err.span_suggestion( - parent_expr.span, - fluent::lint::suggestion, - suggestion, - Applicability::MachineApplicable, - ); - err.emit(); - overwritten = true; - } - }); - } + // We can suggest using an inclusive range + // (`..=`) instead only if it is the `end` that is + // overflowing and only by 1. + if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { + cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| { + let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); + err.set_arg("ty", ty); + if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { + use ast::{LitIntType, LitKind}; + // We need to preserve the literal's suffix, + // as it may determine typing information. + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); + err.span_suggestion( + struct_expr.span, + fluent::lint::suggestion, + suggestion, + Applicability::MachineApplicable, + ); + err.emit(); + overwritten = true; + } + }); } overwritten } @@ -339,16 +344,9 @@ fn lint_int_literal<'tcx>( return; } - let par_id = cx.tcx.hir().get_parent_node(e.hir_id); - if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { - if let hir::ExprKind::Struct(..) = par_e.kind { - if is_range_literal(par_e) - && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) - { - // The overflowing literal lint was overridden. - return; - } - } + if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { + // The overflowing literal lint was overridden. + return; } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { @@ -408,16 +406,13 @@ fn lint_uint_literal<'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(par_e) => { - let t = t.name_str(); - if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { - // The overflowing literal lint was overridden. - return; - } - } _ => {} } } + if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { + // The overflowing literal lint was overridden. + return; + } if let Some(repr_str) = get_bin_hex_repr(cx, lit) { report_bin_hex_error( cx, @@ -724,7 +719,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { let inner_field_ty = { - let first_non_zst_ty = field_def + let mut first_non_zst_ty = field_def .variants() .iter() .filter_map(|v| transparent_newtype_field(cx.tcx, v)); @@ -734,7 +729,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option, expr: &Expr<'_>) { if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering)) = match method { - sym::load => Some((&args[1], sym::Release)), - sym::store => Some((&args[2], sym::Acquire)), + sym::load => Some((&args[0], sym::Release)), + sym::store => Some((&args[1], sym::Acquire)), _ => None, } && let Some(ordering) = Self::match_ordering(cx, ordering_arg) @@ -1541,8 +1536,8 @@ impl InvalidAtomicOrdering { else {return }; let fail_order_arg = match method { - sym::fetch_update => &args[2], - sym::compare_exchange | sym::compare_exchange_weak => &args[4], + sym::fetch_update => &args[1], + sym::compare_exchange | sym::compare_exchange_weak => &args[3], _ => return, }; @@ -1550,7 +1545,7 @@ impl InvalidAtomicOrdering { if matches!(fail_ordering, sym::Release | sym::AcqRel) { #[derive(LintDiagnostic)] - #[lint(lint::atomic_ordering_invalid)] + #[diag(lint::atomic_ordering_invalid)] #[help] struct InvalidAtomicOrderingDiag { method: Symbol, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b6cf18291..8c9ceb711 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, Span}; declare_lint! { /// The `unused_must_use` lint detects unused result of a type flagged as @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }, ty::Closure(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the + // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.build(fluent::lint::unused_closure) .set_arg("count", plural_len) @@ -281,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Generator(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the + // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.build(fluent::lint::unused_generator) .set_arg("count", plural_len) @@ -310,7 +310,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ) -> bool { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post + // FIXME(davidtwco): this isn't properly translatable because of the pre/post // strings let mut err = lint.build(fluent::lint::unused_def); err.set_arg("pre", descr_pre_path); @@ -504,23 +504,23 @@ trait UnusedDelimLint { ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => { let start = block.stmts[0].span; let end = block.stmts[block.stmts.len() - 1].span; - if value.span.from_expansion() || start.from_expansion() || end.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + if let Some(start) = start.find_ancestor_inside(value.span) + && let Some(end) = end.find_ancestor_inside(value.span) + { + Some(( + value.span.with_hi(start.lo()), + value.span.with_lo(end.hi()), + )) } else { - (value.span.with_hi(start.lo()), value.span.with_lo(end.hi())) + None } } ast::ExprKind::Paren(ref expr) => { - if value.span.from_expansion() || expr.span.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + let expr_span = expr.span.find_ancestor_inside(value.span); + if let Some(expr_span) = expr_span { + Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))) } else { - (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi())) + None } } _ => return, @@ -529,36 +529,38 @@ trait UnusedDelimLint { left_pos.map_or(false, |s| s >= value.span.lo()), right_pos.map_or(false, |s| s <= value.span.hi()), ); - self.emit_unused_delims(cx, spans, ctx.into(), keep_space); + self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space); } fn emit_unused_delims( &self, cx: &EarlyContext<'_>, - spans: (Span, Span), + value_span: Span, + spans: Option<(Span, Span)>, msg: &str, keep_space: (bool, bool), ) { - // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc - // properly. - if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP { - return; - } - - cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { - let replacement = vec![ - (spans.0, if keep_space.0 { " ".into() } else { "".into() }), - (spans.1, if keep_space.1 { " ".into() } else { "".into() }), - ]; - lint.build(fluent::lint::unused_delim) - .set_arg("delim", Self::DELIM_STR) - .set_arg("item", msg) - .multipart_suggestion( + let primary_span = if let Some((lo, hi)) = spans { + MultiSpan::from(vec![lo, hi]) + } else { + MultiSpan::from(value_span) + }; + cx.struct_span_lint(self.lint(), primary_span, |lint| { + let mut db = lint.build(fluent::lint::unused_delim); + db.set_arg("delim", Self::DELIM_STR); + db.set_arg("item", msg); + if let Some((lo, hi)) = spans { + let replacement = vec![ + (lo, if keep_space.0 { " ".into() } else { "".into() }), + (hi, if keep_space.1 { " ".into() } else { "".into() }), + ]; + db.multipart_suggestion( fluent::lint::suggestion, replacement, Applicability::MachineApplicable, - ) - .emit(); + ); + } + db.emit(); }); } @@ -750,7 +752,7 @@ impl UnusedParens { avoid_or: bool, avoid_mut: bool, ) { - use ast::{BindingMode, Mutability, PatKind}; + use ast::{BindingAnnotation, PatKind}; if let PatKind::Paren(inner) = &value.kind { match inner.kind { @@ -762,19 +764,18 @@ impl UnusedParens { // Avoid `p0 | .. | pn` if we should. PatKind::Or(..) if avoid_or => return, // Avoid `mut x` and `mut x @ p` if we should: - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return, + PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => { + return; + } // Otherwise proceed with linting. _ => {} } - let spans = if value.span.from_expansion() || inner.span.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) { + Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))) } else { - (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi())) + None }; - self.emit_unused_delims(cx, spans, "pattern", (false, false)); + self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false)); } } } @@ -879,15 +880,12 @@ impl EarlyLintPass for UnusedParens { ); } _ => { - let spans = if ty.span.from_expansion() || r.span.from_expansion() { - ( - ty.span.with_hi(ty.span.lo() + BytePos(1)), - ty.span.with_lo(ty.span.hi() - BytePos(1)), - ) + let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { + Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) } else { - (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi())) + None }; - self.emit_unused_delims(cx, spans, "type", (false, false)); + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f00165cd3..e5dfda24d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3094,7 +3094,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// #![cfg_attr(debug_assertions, crate_type = "lib")] /// ``` /// @@ -3114,7 +3114,7 @@ declare_lint! { /// rustc instead of `#![cfg_attr(..., crate_type = "...")]` and /// `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]`. pub DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - Warn, + Deny, "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`", @future_incompatible = FutureIncompatibleInfo { reference: "issue #91632 ", @@ -3206,12 +3206,62 @@ declare_lint! { /// [future-incompatible]: ../index.md#future-incompatible-lints pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, Warn, - "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", + "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { reference: "issue #78586 ", }; } +declare_lint! { + /// The `unstable_syntax_pre_expansion` lint detects the use of unstable + /// syntax that is discarded during attribute expansion. + /// + /// ### Example + /// + /// ```rust + /// #[cfg(FALSE)] + /// macro foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The input to active attributes such as `#[cfg]` or procedural macro + /// attributes is required to be valid syntax. Previously, the compiler only + /// gated the use of unstable syntax features after resolving `#[cfg]` gates + /// and expanding procedural macros. + /// + /// To avoid relying on unstable syntax, move the use of unstable syntax + /// into a position where the compiler does not parse the syntax, such as a + /// functionlike macro. + /// + /// ```rust + /// # #![deny(unstable_syntax_pre_expansion)] + /// + /// macro_rules! identity { + /// ( $($tokens:tt)* ) => { $($tokens)* } + /// } + /// + /// #[cfg(FALSE)] + /// identity! { + /// macro foo() {} + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #65860] for more details. + /// + /// [issue #65860]: https://github.com/rust-lang/rust/issues/65860 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub UNSTABLE_SYNTAX_PRE_EXPANSION, + Warn, + "unstable syntax can change at any point in the future, causing a hard error!", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #65860 ", + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3280,6 +3330,7 @@ declare_lint_pass! { POINTER_STRUCTURAL_MATCH, NONTRIVIAL_STRUCTURAL_MATCH, SOFT_UNSTABLE, + UNSTABLE_SYNTAX_PRE_EXPANSION, INLINE_NO_SANITIZE, BAD_ASM_STYLE, ASM_SUB_REGISTER, @@ -3314,7 +3365,6 @@ declare_lint_pass! { DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, SUSPICIOUS_AUTO_TRAIT_IMPLS, - UNEXPECTED_CFGS, DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, FFI_UNWIND_CALLS, @@ -3357,7 +3407,7 @@ declare_lint! { /// /// ### Example of drop reorder /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_incompatible_closure_captures)] /// # #![allow(unused)] /// @@ -3393,7 +3443,7 @@ declare_lint! { /// /// ### Example of auto-trait /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_incompatible_closure_captures)] /// use std::thread; /// @@ -3938,8 +3988,6 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(generic_associated_types)] - /// /// trait Trait { /// type Assoc<'a> where Self: 'a; /// } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6acbe97a7..11b2d057a 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,4 +1,6 @@ #![feature(min_specialization)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; @@ -7,7 +9,7 @@ pub use self::Level::*; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_ast::{AttrId, Attribute}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_error_messages::MultiSpan; +use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; use rustc_hir::HirId; use rustc_span::edition::Edition; @@ -39,7 +41,8 @@ macro_rules! pluralize { /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion /// to determine whether it should be automatically applied or if the user should be consulted /// before applying the suggestion. -#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Hash, Encodable, Decodable, Serialize, Deserialize)] +#[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Applicability { /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code. /// This suggestion should be automatically applied. @@ -489,7 +492,7 @@ pub struct BufferedEarlyLint { pub span: MultiSpan, /// The lint message. - pub msg: String, + pub msg: DiagnosticMessage, /// The `NodeId` of the AST node that generated the lint. pub node_id: NodeId, @@ -518,11 +521,11 @@ impl LintBuffer { lint: &'static Lint, node_id: NodeId, span: MultiSpan, - msg: &str, + msg: impl Into, diagnostic: BuiltinLintDiagnostics, ) { let lint_id = LintId::of(lint); - let msg = msg.to_string(); + let msg = msg.into(); self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic }); } @@ -535,7 +538,7 @@ impl LintBuffer { lint: &'static Lint, id: NodeId, sp: impl Into, - msg: &str, + msg: impl Into, ) { self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal) } @@ -545,7 +548,7 @@ impl LintBuffer { lint: &'static Lint, id: NodeId, sp: impl Into, - msg: &str, + msg: impl Into, diagnostic: BuiltinLintDiagnostics, ) { self.add_lint(lint, id, sp.into(), msg, diagnostic) @@ -655,18 +658,21 @@ macro_rules! declare_lint { macro_rules! declare_tool_lint { ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr + $(, @feature_gate = $gate:expr;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr + $(, @feature_gate = $gate:expr;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr + $(, @feature_gate = $gate:expr;)? ) => ( $(#[$attr])* $vis static $NAME: &$crate::Lint = &$crate::Lint { @@ -677,8 +683,9 @@ macro_rules! declare_tool_lint { report_in_external_macro: $external, future_incompatible: None, is_plugin: true, - feature_gate: None, + $(feature_gate: Some($gate),)? crate_level_only: false, + ..$crate::Lint::default_fields_for_macro() }; ); } diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 62ef5804d..28e092c1e 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -242,6 +242,13 @@ fn main() { println!("cargo:rustc-link-lib=uuid"); } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") { println!("cargo:rustc-link-lib=z"); + } else if target.starts_with("arm") + || target.starts_with("mips-") + || target.starts_with("mipsel-") + || target.starts_with("powerpc-") + { + // 32-bit targets need to link libatomic. + println!("cargo:rustc-link-lib=atomic"); } cmd.args(&components); @@ -335,10 +342,10 @@ fn main() { }; // RISC-V GCC erroneously requires libatomic for sub-word - // atomic operations. FreeBSD uses Clang as its system + // atomic operations. Some BSD uses Clang as its system // compiler and provides no libatomic in its base system so // does not want this. - if !target.contains("freebsd") && target.starts_with("riscv") { + if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd") { println!("cargo:rustc-link-lib=atomic"); } diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 97541e615..448a1f62f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -154,19 +154,6 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { return Name.data(); } -extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child, - size_t *Size) { - StringRef Buf; - Expected BufOrErr = Child->getBuffer(); - if (!BufOrErr) { - LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str()); - return nullptr; - } - Buf = BufOrErr.get(); - *Size = Buf.size(); - return Buf.data(); -} - extern "C" LLVMRustArchiveMemberRef LLVMRustArchiveMemberNew(char *Filename, char *Name, LLVMRustArchiveChildRef Child) { diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 154f554d6..7da6ab713 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -24,17 +24,10 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( const char* const Filenames[], size_t FilenamesLen, RustStringRef BufferOut) { -#if LLVM_VERSION_GE(13,0) SmallVector FilenameRefs; for (size_t i = 0; i < FilenamesLen; i++) { FilenameRefs.push_back(std::string(Filenames[i])); } -#else - SmallVector FilenameRefs; - for (size_t i = 0; i < FilenamesLen; i++) { - FilenameRefs.push_back(StringRef(Filenames[i])); - } -#endif auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter( makeArrayRef(FilenameRefs)); RawRustStringOstream OS(BufferOut); @@ -109,9 +102,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { -#if LLVM_VERSION_GE(13, 0) return coverage::CovMapVersion::Version6; -#else - return coverage::CovMapVersion::Version5; -#endif } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 0a6bd4999..24e188260 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -31,6 +31,9 @@ #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/FunctionImport.h" +#if LLVM_VERSION_GE(15, 0) +#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" +#endif #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/LTO/LTO.h" @@ -131,7 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool const bool CompileKernel = false; return wrap(createMemorySanitizerLegacyPassPass( - MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); +#if LLVM_VERSION_GE(14, 0) + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true} +#else + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel} +#endif + )); #else report_fatal_error("Legacy PM not supported with LLVM 15"); #endif @@ -822,7 +830,8 @@ LLVMRustOptimizeWithNewPassManager( bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, - bool InstrumentCoverage, bool InstrumentGCOV, + bool InstrumentCoverage, const char *InstrProfileOutput, + bool InstrumentGCOV, const char *PGOSampleUsePath, bool DebugInfoForProfiling, void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, @@ -869,19 +878,11 @@ LLVMRustOptimizeWithNewPassManager( PGOOptions::NoCSAction, DebugInfoForProfiling); } -#if LLVM_VERSION_GE(13, 0) PassBuilder PB(TM, PTO, PGOOpt, &PIC); LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; -#else - PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC); - LoopAnalysisManager LAM(DebugPassManager); - FunctionAnalysisManager FAM(DebugPassManager); - CGSCCAnalysisManager CGAM(DebugPassManager); - ModuleAnalysisManager MAM(DebugPassManager); -#endif FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); @@ -922,8 +923,11 @@ LLVMRustOptimizeWithNewPassManager( if (InstrumentCoverage) { PipelineStartEPCallbacks.push_back( - [](ModulePassManager &MPM, OptimizationLevel Level) { + [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) { InstrProfOptions Options; + if (InstrProfileOutput) { + Options.InstrProfileOutput = InstrProfileOutput; + } MPM.addPass(InstrProfiling(Options, false)); } ); @@ -931,18 +935,28 @@ LLVMRustOptimizeWithNewPassManager( if (SanitizerOptions) { if (SanitizerOptions->SanitizeMemory) { +#if LLVM_VERSION_GE(14, 0) + MemorySanitizerOptions Options( + SanitizerOptions->SanitizeMemoryTrackOrigins, + SanitizerOptions->SanitizeMemoryRecover, + /*CompileKernel=*/false, + /*EagerChecks=*/true); +#else MemorySanitizerOptions Options( SanitizerOptions->SanitizeMemoryTrackOrigins, SanitizerOptions->SanitizeMemoryRecover, /*CompileKernel=*/false); +#endif OptimizerLastEPCallbacks.push_back( [Options](ModulePassManager &MPM, OptimizationLevel Level) { -#if LLVM_VERSION_GE(14, 0) +#if LLVM_VERSION_GE(14, 0) && LLVM_VERSION_LT(16, 0) MPM.addPass(ModuleMemorySanitizerPass(Options)); #else MPM.addPass(MemorySanitizerPass(Options)); #endif +#if LLVM_VERSION_LT(16, 0) MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); +#endif } ); } @@ -973,7 +987,11 @@ LLVMRustOptimizeWithNewPassManager( /*UseAfterScope=*/true, AsanDetectStackUseAfterReturnMode::Runtime, }; +#if LLVM_VERSION_LT(16, 0) MPM.addPass(ModuleAddressSanitizerPass(opts)); +#else + MPM.addPass(AddressSanitizerPass(opts)); +#endif #else MPM.addPass(ModuleAddressSanitizerPass( /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); @@ -1015,11 +1033,7 @@ LLVMRustOptimizeWithNewPassManager( } } -#if LLVM_VERSION_GE(13, 0) ModulePassManager MPM; -#else - ModulePassManager MPM(DebugPassManager); -#endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. @@ -1434,17 +1448,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; -#if LLVM_VERSION_GE(13,0) // Uses FromPrevailing visibility scheme which works for many binary // formats. We probably could and should use ELF visibility scheme for many of // our targets, however. lto::Config conf; thinLTOResolvePrevailingInIndex(conf, Ret->Index, isPrevailing, recordNewLinkage, Ret->GUIDPreservedSymbols); -#else - thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage, - Ret->GUIDPreservedSymbols); -#endif + // Here we calculate an `ExportedGUIDs` set for use in the `isExported` // callback below. This callback below will dictate the linkage for all // summaries in the index, and we basically just only want to ensure that dead @@ -1599,13 +1609,31 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { { raw_string_ostream OS(Ret->data); { - legacy::PassManager PM; if (is_thin) { +#if LLVM_VERSION_LT(15, 0) + legacy::PassManager PM; PM.add(createWriteThinLTOBitcodePass(OS)); + PM.run(*unwrap(M)); +#else + PassBuilder PB; + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + ModulePassManager MPM; + MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr)); + MPM.run(*unwrap(M), MAM); +#endif } else { + legacy::PassManager PM; PM.add(createBitcodeWriterPass(OS)); + PM.run(*unwrap(M)); } - PM.run(*unwrap(M)); } } return Ret.release(); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 5f5b5de79..6ee3c7d68 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -413,18 +413,12 @@ LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target, LLVMValueRef Old, LLVMValueRef Source, LLVMAtomicOrdering Order, LLVMAtomicOrdering FailureOrder, LLVMBool Weak) { -#if LLVM_VERSION_GE(13,0) // Rust probably knows the alignment of the target value and should be able to // specify something more precise than MaybeAlign here. See also // https://reviews.llvm.org/D97224 which may be a useful reference. AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg( unwrap(Target), unwrap(Old), unwrap(Source), llvm::MaybeAlign(), fromRust(Order), fromRust(FailureOrder)); -#else - AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg( - unwrap(Target), unwrap(Old), unwrap(Source), fromRust(Order), - fromRust(FailureOrder)); -#endif ACXI->setWeak(Weak); return wrap(ACXI); } @@ -472,19 +466,11 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, char *Constraints, size_t ConstraintsLen, LLVMBool HasSideEffects, LLVMBool IsAlignStack, LLVMRustAsmDialect Dialect, LLVMBool CanThrow) { -#if LLVM_VERSION_GE(13, 0) return wrap(InlineAsm::get(unwrap(Ty), StringRef(AsmString, AsmStringLen), StringRef(Constraints, ConstraintsLen), HasSideEffects, IsAlignStack, fromRust(Dialect), CanThrow)); -#else - return wrap(InlineAsm::get(unwrap(Ty), - StringRef(AsmString, AsmStringLen), - StringRef(Constraints, ConstraintsLen), - HasSideEffects, IsAlignStack, - fromRust(Dialect))); -#endif } extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, @@ -924,6 +910,30 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( fromRust(Flags), unwrapDI(Ty))); } +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType( + LLVMRustDIBuilderRef Builder, + LLVMMetadataRef Scope, + const char *Name, + size_t NameLen, + LLVMMetadataRef File, + unsigned LineNo, + LLVMMetadataRef Ty, + LLVMRustDIFlags Flags, + LLVMValueRef val, + uint32_t AlignInBits +) { + return wrap(Builder->createStaticMemberType( + unwrapDI(Scope), + StringRef(Name, NameLen), + unwrapDI(File), + LineNo, + unwrapDI(Ty), + fromRust(Flags), + unwrap(val), + AlignInBits + )); +} + extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned Col) { @@ -1250,10 +1260,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { return LLVMRustDiagnosticKind::Linker; case DK_Unsupported: return LLVMRustDiagnosticKind::Unsupported; -#if LLVM_VERSION_GE(13, 0) case DK_SrcMgr: return LLVMRustDiagnosticKind::SrcMgr; -#endif default: return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther @@ -1327,30 +1335,11 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) -#if LLVM_VERSION_LT(13, 0) -using LLVMInlineAsmDiagHandlerTy = LLVMContext::InlineAsmDiagHandlerTy; -#else -using LLVMInlineAsmDiagHandlerTy = void*; -#endif - -extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( - LLVMContextRef C, LLVMInlineAsmDiagHandlerTy H, void *CX) { - // Diagnostic handlers were unified in LLVM change 5de2d189e6ad, so starting - // with LLVM 13 this function is gone. -#if LLVM_VERSION_LT(13, 0) - unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); -#endif -} - extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic( LLVMDiagnosticInfoRef DI, unsigned *Cookie) { -#if LLVM_VERSION_GE(13, 0) llvm::DiagnosticInfoSrcMgr *SM = static_cast(unwrap(DI)); *Cookie = SM->getLocCookie(); return wrap(&SM->getSMDiag()); -#else - report_fatal_error("Shouldn't get called on older versions"); -#endif } extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, @@ -1629,6 +1618,14 @@ extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty, return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList)); } +extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) { + auto C = unwrap(CV); + if (C->getBitWidth() > 64) + return false; + *value = C->getZExtValue(); + return true; +} + // Returns true if both high and low were successfully set. Fails in case constant wasn’t any of // the common sizes (1, 8, 16, 32, 64, 128 bits) extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low) diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8eade02a4..8542dcf5b 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index f2ec80b0c..458f5e87b 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -38,6 +38,9 @@ //! debugging, you can make changes inside those crates and quickly run main.rs //! to read the debug logs. +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io; diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 25b3aadc1..547c8debb 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" proc-macro = true [dependencies] -annotate-snippets = "0.8.0" +annotate-snippets = "0.9" fluent-bundle = "0.15.2" fluent-syntax = "0.11" synstructure = "0.12.1" diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 6b5b8b593..cf1c59455 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -21,7 +21,7 @@ impl<'a> SessionDiagnosticDerive<'a> { builder: DiagnosticDeriveBuilder { diag, fields: build_field_mapping(&structure), - kind: None, + kind: DiagnosticDeriveKind::SessionDiagnostic, code: None, slug: None, }, @@ -34,49 +34,31 @@ impl<'a> SessionDiagnosticDerive<'a> { let SessionDiagnosticDerive { mut structure, sess, mut builder } = self; let ast = structure.ast(); - let (implementation, param_ty) = { + let implementation = { if let syn::Data::Struct(..) = ast.data { let preamble = builder.preamble(&structure); let (attrs, args) = builder.body(&mut structure); let span = ast.span().unwrap(); let diag = &builder.diag; - let init = match (builder.kind.value(), builder.slug.value()) { - (None, _) => { - span_err(span, "diagnostic kind not specified") - .help("use the `#[error(...)]` attribute to create an error") - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - (Some(kind), None) => { + let init = match builder.slug.value() { + None => { span_err(span, "diagnostic slug not specified") .help(&format!( - "specify the slug as the first argument to the attribute, such as \ - `#[{}(typeck::example_error)]`", - kind.descr() + "specify the slug as the first argument to the `#[diag(...)]` attribute, \ + such as `#[diag(typeck::example_error)]`", )) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - (Some(DiagnosticDeriveKind::Lint), _) => { - span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported") - .help("use the `#[error(...)]` attribute to create a error") - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - (Some(DiagnosticDeriveKind::Error), Some(slug)) => { - quote! { - let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug); - } - } - (Some(DiagnosticDeriveKind::Warn), Some(slug)) => { + Some(slug) => { quote! { - let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug); + let mut #diag = #sess.struct_diagnostic(rustc_errors::fluent::#slug); } } }; - let implementation = quote! { + quote! { #init #preamble match self { @@ -86,18 +68,7 @@ impl<'a> SessionDiagnosticDerive<'a> { #args } #diag - }; - let param_ty = match builder.kind { - Some((DiagnosticDeriveKind::Error, _)) => { - quote! { rustc_errors::ErrorGuaranteed } - } - Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => { - quote! { () } - } - _ => unreachable!(), - }; - - (implementation, param_ty) + } } else { span_err( ast.span().unwrap(), @@ -105,20 +76,20 @@ impl<'a> SessionDiagnosticDerive<'a> { ) .emit(); - let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error(); - let param_ty = quote! { rustc_errors::ErrorGuaranteed }; - (implementation, param_ty) + DiagnosticDeriveError::ErrorHandled.to_compile_error() } }; structure.gen_impl(quote! { - gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty> + gen impl<'__session_diagnostic_sess, G> + rustc_session::SessionDiagnostic<'__session_diagnostic_sess, G> for @Self + where G: rustc_errors::EmissionGuarantee { fn into_diagnostic( self, - #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess - ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> { + #sess: &'__session_diagnostic_sess rustc_errors::Handler + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> { use rustc_errors::IntoDiagnosticArg; #implementation } @@ -139,7 +110,7 @@ impl<'a> LintDiagnosticDerive<'a> { builder: DiagnosticDeriveBuilder { diag, fields: build_field_mapping(&structure), - kind: None, + kind: DiagnosticDeriveKind::LintDiagnostic, code: None, slug: None, }, @@ -158,30 +129,17 @@ impl<'a> LintDiagnosticDerive<'a> { let diag = &builder.diag; let span = ast.span().unwrap(); - let init = match (builder.kind.value(), builder.slug.value()) { - (None, _) => { - span_err(span, "diagnostic kind not specified") - .help("use the `#[error(...)]` attribute to create an error") - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - (Some(kind), None) => { + let init = match builder.slug.value() { + None => { span_err(span, "diagnostic slug not specified") .help(&format!( "specify the slug as the first argument to the attribute, such as \ - `#[{}(typeck::example_error)]`", - kind.descr() + `#[diag(typeck::example_error)]`", )) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - (Some(DiagnosticDeriveKind::Error | DiagnosticDeriveKind::Warn), _) => { - span_err(span, "only `#[lint(..)]` is supported") - .help("use the `#[lint(...)]` attribute to create a lint") - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - (Some(DiagnosticDeriveKind::Lint), Some(slug)) => { + Some(slug) => { quote! { let mut #diag = #diag.build(rustc_errors::fluent::#slug); } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 6c9561925..2a4fe48a8 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -18,30 +18,15 @@ use syn::{ }; use synstructure::{BindingInfo, Structure}; -/// What kind of diagnostic is being derived - an error, a warning or a lint? -#[derive(Copy, Clone)] +/// What kind of diagnostic is being derived - a fatal/error/warning or a lint? +#[derive(Copy, Clone, PartialEq, Eq)] pub(crate) enum DiagnosticDeriveKind { - /// `#[error(..)]` - Error, - /// `#[warn(..)]` - Warn, - /// `#[lint(..)]` - Lint, -} - -impl DiagnosticDeriveKind { - /// Returns human-readable string corresponding to the kind. - pub fn descr(&self) -> &'static str { - match self { - DiagnosticDeriveKind::Error => "error", - DiagnosticDeriveKind::Warn => "warning", - DiagnosticDeriveKind::Lint => "lint", - } - } + SessionDiagnostic, + LintDiagnostic, } /// Tracks persistent information required for building up individual calls to diagnostic methods -/// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and +/// for generated diagnostic derives - both `SessionDiagnostic` for fatal/errors/warnings and /// `LintDiagnostic` for lints. pub(crate) struct DiagnosticDeriveBuilder { /// The identifier to use for the generated `DiagnosticBuilder` instance. @@ -51,8 +36,8 @@ pub(crate) struct DiagnosticDeriveBuilder { /// derive builder. pub fields: HashMap, - /// Kind of diagnostic requested via the struct attribute. - pub kind: Option<(DiagnosticDeriveKind, proc_macro::Span)>, + /// Kind of diagnostic that should be derived. + pub kind: DiagnosticDeriveKind, /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that /// has the actual diagnostic message. pub slug: Option<(Path, proc_macro::Span)>, @@ -143,7 +128,7 @@ impl DiagnosticDeriveBuilder { } /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct - /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates + /// attributes like `#[diag(..)]`, such as the slug and error code. Generates /// diagnostic builder calls for setting error code and creating note/help messages. fn generate_structure_code_for_attr( &mut self, @@ -156,16 +141,16 @@ impl DiagnosticDeriveBuilder { let name = name.as_str(); let meta = attr.parse_meta()?; - let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_"); + let is_diag = name == "diag"; let nested = match meta { - // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or + // Most attributes are lists, like `#[diag(..)]` for most cases or // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug. Meta::List(MetaList { ref nested, .. }) => nested, // Subdiagnostics without spans can be applied to the type too, and these are just - // paths: `#[help]` and `#[note]` - Meta::Path(_) if is_help_note_or_warn => { - let fn_name = if name == "warn_" { + // paths: `#[help]`, `#[note]` and `#[warning]` + Meta::Path(_) if !is_diag => { + let fn_name = if name == "warning" { Ident::new("warn", attr.span()) } else { Ident::new(name, attr.span()) @@ -178,41 +163,42 @@ impl DiagnosticDeriveBuilder { // Check the kind before doing any further processing so that there aren't misleading // "no kind specified" errors if there are failures later. match name { - "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)), - "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)), - "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)), - "help" | "note" | "warn_" => (), + "error" | "lint" => throw_invalid_attr!(attr, &meta, |diag| { + diag.help("`error` and `lint` have been replaced by `diag`") + }), + "warn_" => throw_invalid_attr!(attr, &meta, |diag| { + diag.help("`warn_` have been replaced by `warning`") + }), + "diag" | "help" | "note" | "warning" => (), _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help( - "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes", - ) + diag.help("only `diag`, `help`, `note` and `warning` are valid attributes") }), } - // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or + // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or // `#[help(typeck::another_help)]`. let mut nested_iter = nested.into_iter(); if let Some(nested_attr) = nested_iter.next() { // Report an error if there are any other list items after the path. - if is_help_note_or_warn && nested_iter.next().is_some() { + if !is_diag && nested_iter.next().is_some() { throw_invalid_nested_attr!(attr, &nested_attr, |diag| { diag.help( - "`help`, `note` and `warn_` struct attributes can only have one argument", + "`help`, `note` and `warning` struct attributes can only have one argument", ) }); } match nested_attr { - NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => { - let fn_name = proc_macro2::Ident::new(name, attr.span()); - return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); - } NestedMeta::Meta(Meta::Path(path)) => { - self.slug.set_once((path.clone(), span)); + if is_diag { + self.slug.set_once((path.clone(), span)); + } else { + let fn_name = proc_macro2::Ident::new(name, attr.span()); + return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); + } } NestedMeta::Meta(meta @ Meta::NameValue(_)) - if !is_help_note_or_warn - && meta.path().segments.last().unwrap().ident == "code" => + if is_diag && meta.path().segments.last().unwrap().ident == "code" => { // don't error for valid follow-up attributes } @@ -253,7 +239,7 @@ impl DiagnosticDeriveBuilder { } } - Ok(tokens.drain(..).collect()) + Ok(tokens.into_iter().collect()) } fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { @@ -346,21 +332,31 @@ impl DiagnosticDeriveBuilder { Ok(quote! {}) } "primary_span" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(quote! { - #diag.set_span(#binding); - }) + match self.kind { + DiagnosticDeriveKind::SessionDiagnostic => { + report_error_if_not_applied_to_span(attr, &info)?; + + Ok(quote! { + #diag.set_span(#binding); + }) + } + DiagnosticDeriveKind::LintDiagnostic => { + throw_invalid_attr!(attr, &meta, |diag| { + diag.help("the `primary_span` field attribute is not valid for lint diagnostics") + }) + } + } } "label" => { report_error_if_not_applied_to_span(attr, &info)?; Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label })) } - "note" | "help" | "warn_" => { + "note" | "help" | "warning" => { let warn_ident = Ident::new("warn", Span::call_site()); let (ident, path) = match name { "note" => (ident, parse_quote! { _subdiag::note }), "help" => (ident, parse_quote! { _subdiag::help }), - "warn_" => (&warn_ident, parse_quote! { _subdiag::warn }), + "warning" => (&warn_ident, parse_quote! { _subdiag::warn }), _ => unreachable!(), }; if type_matches_path(&info.ty, &["rustc_span", "Span"]) { @@ -397,7 +393,7 @@ impl DiagnosticDeriveBuilder { "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => { return self.generate_inner_field_code_suggestion(attr, info); } - "label" | "help" | "note" | "warn_" => (), + "label" | "help" | "note" | "warning" => (), _ => throw_invalid_attr!(attr, &meta, |diag| { diag.help( "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \ @@ -429,14 +425,14 @@ impl DiagnosticDeriveBuilder { Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) } "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)), - // `warn_` must be special-cased because the attribute `warn` already has meaning and + // `warning` must be special-cased because the attribute `warn` already has meaning and // so isn't used, despite the diagnostic API being named `warn`. - "warn_" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self + "warning" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)), - "warn_" if type_is_unit(&info.ty) => { + "warning" if type_is_unit(&info.ty) => { Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg)) } - "note" | "help" | "warn_" => report_type_error(attr, "`Span` or `()`")?, + "note" | "help" | "warning" => report_type_error(attr, "`Span` or `()`")?, _ => unreachable!(), } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 562d5e9f4..f7d8b494e 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -187,17 +187,41 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok for entry in resource.entries() { let span = res.ident.span(); if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { - let _ = previous_defns.entry(name.to_string()).or_insert(ident_span); + let _ = previous_defns.entry(name.to_string()).or_insert(path_span); + + if name.contains('-') { + Diagnostic::spanned( + path_span, + Level::Error, + format!("name `{name}` contains a '-' character"), + ) + .help("replace any '-'s with '_'s") + .emit(); + } + + // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`) + // `const_eval_baz` => `baz` (in `const_eval.ftl`) + // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`) + // The last case we error about above, but we want to fall back gracefully + // so that only the error is being emitted and not also one about the macro + // failing. + let crate_prefix = format!("{}_", res.ident); + + let snake_name = name.replace('-', "_"); + let snake_name = match snake_name.strip_prefix(&crate_prefix) { + Some(rest) => Ident::new(rest, span), + None => { + Diagnostic::spanned( + path_span, + Level::Error, + format!("name `{name}` does not start with the crate name"), + ) + .help(format!("prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`")) + .emit(); + Ident::new(&snake_name, span) + } + }; - // `typeck-foo-bar` => `foo_bar` (in `typeck.ftl`) - // `const-eval-baz` => `baz` (in `const_eval.ftl`) - let snake_name = Ident::new( - // FIXME: should probably trim prefix, not replace all occurrences - &name - .replace(&format!("{}-", res.ident).replace('_', "-"), "") - .replace('-', "_"), - span, - ); constants.extend(quote! { pub const #snake_name: crate::DiagnosticMessage = crate::DiagnosticMessage::FluentIdentifier( @@ -212,6 +236,16 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok continue; } + if attr_name.contains('-') { + Diagnostic::spanned( + path_span, + Level::Error, + format!("attribute `{attr_name}` contains a '-' character"), + ) + .help("replace any '-'s with '_'s") + .emit(); + } + constants.extend(quote! { pub const #snake_name: crate::SubdiagnosticMessage = crate::SubdiagnosticMessage::FluentAttr( @@ -227,7 +261,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok match e { FluentError::Overriding { kind, id } => { Diagnostic::spanned( - ident_span, + path_span, Level::Error, format!("overrides existing {}: `{}`", kind, id), ) diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 399790026..2ff21e18f 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -23,7 +23,7 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(SessionDiagnostic)] -/// #[error(borrowck::move_out_of_borrow, code = "E0505")] +/// #[diag(borrowck::move_out_of_borrow, code = "E0505")] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, @@ -38,9 +38,9 @@ use synstructure::Structure; /// ``` /// /// ```fluent -/// move-out-of-borrow = cannot move out of {$name} because it is borrowed +/// move_out_of_borrow = cannot move out of {$name} because it is borrowed /// .label = cannot move out of borrow -/// .first-borrow-label = `{$ty}` first borrowed here +/// .first_borrow_label = `{$ty}` first borrowed here /// .suggestion = consider cloning here /// ``` /// @@ -67,7 +67,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// /// ```ignore (rust) /// #[derive(LintDiagnostic)] -/// #[lint(lint::atomic_ordering_invalid_fail_success)] +/// #[diag(lint::atomic_ordering_invalid_fail_success)] /// pub struct AtomicOrderingInvalidLint { /// method: Symbol, /// success_ordering: Symbol, @@ -84,9 +84,9 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ``` /// /// ```fluent -/// lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering -/// .fail-label = `{$fail_ordering}` failure ordering -/// .success-label = `{$success_ordering}` success ordering +/// lint_atomic_ordering_invalid_fail_success = `{$method}`'s success ordering must be at least as strong as its failure ordering +/// .fail_label = `{$fail_ordering}` failure ordering +/// .success_label = `{$success_ordering}` success ordering /// .suggestion = consider using `{$success_suggestion}` success ordering instead /// ``` /// @@ -140,11 +140,11 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ``` /// /// ```fluent -/// parser-expected-identifier = expected identifier +/// parser_expected_identifier = expected identifier /// -/// parser-expected-identifier-found = expected identifier, found {$found} +/// parser_expected_identifier-found = expected identifier, found {$found} /// -/// parser-raw-identifier = escape `{$ident}` to use it as an identifier +/// parser_raw_identifier = escape `{$ident}` to use it as an identifier /// ``` /// /// Then, later, to add the subdiagnostic: diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index edf4dbed9..dce5d3cfb 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -12,7 +12,7 @@ use quote::{format_ident, quote}; use std::collections::HashMap; use std::fmt; use std::str::FromStr; -use syn::{parse_quote, spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; /// Which kind of suggestion is being created? @@ -28,8 +28,41 @@ enum SubdiagnosticSuggestionKind { Verbose, } +impl FromStr for SubdiagnosticSuggestionKind { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "" => Ok(SubdiagnosticSuggestionKind::Normal), + "_short" => Ok(SubdiagnosticSuggestionKind::Short), + "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden), + "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose), + _ => Err(()), + } + } +} + +impl SubdiagnosticSuggestionKind { + pub fn to_suggestion_style(&self) -> TokenStream { + match self { + SubdiagnosticSuggestionKind::Normal => { + quote! { rustc_errors::SuggestionStyle::ShowCode } + } + SubdiagnosticSuggestionKind::Short => { + quote! { rustc_errors::SuggestionStyle::HideCodeInline } + } + SubdiagnosticSuggestionKind::Hidden => { + quote! { rustc_errors::SuggestionStyle::HideCodeAlways } + } + SubdiagnosticSuggestionKind::Verbose => { + quote! { rustc_errors::SuggestionStyle::ShowAlways } + } + } + } +} + /// Which kind of subdiagnostic is being created from a variant? -#[derive(Clone, Copy)] +#[derive(Clone)] enum SubdiagnosticKind { /// `#[label(...)]` Label, @@ -37,34 +70,12 @@ enum SubdiagnosticKind { Note, /// `#[help(...)]` Help, - /// `#[warn_(...)]` + /// `#[warning(...)]` Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` - Suggestion(SubdiagnosticSuggestionKind), -} - -impl FromStr for SubdiagnosticKind { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "label" => Ok(SubdiagnosticKind::Label), - "note" => Ok(SubdiagnosticKind::Note), - "help" => Ok(SubdiagnosticKind::Help), - "warn_" => Ok(SubdiagnosticKind::Warn), - "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)), - "suggestion_short" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short)) - } - "suggestion_hidden" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden)) - } - "suggestion_verbose" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose)) - } - _ => Err(()), - } - } + Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream }, + /// `#[multipart_suggestion{,_short,_hidden,_verbose}]` + MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind }, } impl quote::IdentFragment for SubdiagnosticKind { @@ -74,17 +85,9 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), SubdiagnosticKind::Warn => write!(f, "warn"), - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => { - write!(f, "suggestion") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => { - write!(f, "suggestion_short") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => { - write!(f, "suggestion_hidden") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => { - write!(f, "suggestion_verbose") + SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"), + SubdiagnosticKind::MultipartSuggestion { .. } => { + write!(f, "multipart_suggestion_with_style") } } } @@ -148,11 +151,9 @@ impl<'a> SessionSubdiagnosticDerive<'a> { variant, span, fields: fields_map, - kind: None, - slug: None, - code: None, span_field: None, applicability: None, + has_suggestion_parts: false, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -193,21 +194,15 @@ struct SessionSubdiagnosticDeriveBuilder<'a> { /// derive builder. fields: HashMap, - /// Subdiagnostic kind of the type/variant. - kind: Option<(SubdiagnosticKind, proc_macro::Span)>, - - /// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the - /// `#[kind(slug)]` attribute on the type or variant. - slug: Option<(Path, proc_macro::Span)>, - /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]` - /// attribute on the type or variant. - code: Option<(TokenStream, proc_macro::Span)>, - /// Identifier for the binding to the `#[primary_span]` field. span_field: Option<(proc_macro2::Ident, proc_macro::Span)>, /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a /// `rustc_errors::Applicability::*` variant directly. applicability: Option<(TokenStream, proc_macro::Span)>, + + /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error + /// during finalization if still `false`. + has_suggestion_parts: bool, } impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { @@ -216,8 +211,40 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { } } +/// Provides frequently-needed information about the diagnostic kinds being derived for this type. +#[derive(Clone, Copy, Debug)] +struct KindsStatistics { + has_multipart_suggestion: bool, + all_multipart_suggestions: bool, + has_normal_suggestion: bool, +} + +impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics { + fn from_iter>(kinds: T) -> Self { + let mut ret = Self { + has_multipart_suggestion: false, + all_multipart_suggestions: true, + has_normal_suggestion: false, + }; + for kind in kinds { + if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { + ret.has_multipart_suggestion = true; + } else { + ret.all_multipart_suggestions = false; + } + + if let SubdiagnosticKind::Suggestion { .. } = kind { + ret.has_normal_suggestion = true; + } + } + ret + } +} + impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { - fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> { + fn identify_kind(&mut self) -> Result, DiagnosticDeriveError> { + let mut kind_slugs = vec![]; + for attr in self.variant.ast().attrs { let span = attr.span().unwrap(); @@ -225,116 +252,121 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let name = name.as_str(); let meta = attr.parse_meta()?; - let kind = match meta { - Meta::List(MetaList { ref nested, .. }) => { - let mut nested_iter = nested.into_iter(); - if let Some(nested_attr) = nested_iter.next() { - match nested_attr { - NestedMeta::Meta(Meta::Path(path)) => { - self.slug.set_once((path.clone(), span)); - } - NestedMeta::Meta(meta @ Meta::NameValue(_)) - if matches!( - meta.path().segments.last().unwrap().ident.to_string().as_str(), - "code" | "applicability" - ) => - { - // don't error for valid follow-up attributes - } - nested_attr => { - throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "first argument of the attribute should be the diagnostic \ - slug", - ) - }) - } - }; - } + let Meta::List(MetaList { ref nested, .. }) = meta else { + throw_invalid_attr!(attr, &meta); + }; - for nested_attr in nested_iter { - let meta = match nested_attr { - NestedMeta::Meta(ref meta) => meta, - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - - match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - match nested_name { - "code" => { - let formatted_str = self.build_format(&s.value(), s.span()); - self.code.set_once((formatted_str, span)); - } - "applicability" => { - let value = match Applicability::from_str(&s.value()) { - Ok(v) => v, - Err(()) => { - span_err(span, "invalid applicability").emit(); - Applicability::Unspecified - } - }; - self.applicability.set_once((quote! { #value }, span)); - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "only `code` and `applicability` are valid nested \ - attributes", - ) - }), - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - if matches!(meta, Meta::Path(_)) { - diag.help( - "a diagnostic slug must be the first argument to the \ - attribute", - ) - } else { - diag - } - }), - } + let mut kind = match name { + "label" => SubdiagnosticKind::Label, + "note" => SubdiagnosticKind::Note, + "help" => SubdiagnosticKind::Help, + "warning" => SubdiagnosticKind::Warn, + _ => { + if let Some(suggestion_kind) = + name.strip_prefix("suggestion").and_then(|s| s.parse().ok()) + { + SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() } + } else if let Some(suggestion_kind) = + name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok()) + { + SubdiagnosticKind::MultipartSuggestion { suggestion_kind } + } else { + throw_invalid_attr!(attr, &meta); } - - let Ok(kind) = SubdiagnosticKind::from_str(name) else { - throw_invalid_attr!(attr, &meta) - }; - - kind } - _ => throw_invalid_attr!(attr, &meta), }; - if matches!( - kind, - SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note - ) && self.code.is_some() - { - throw_span_err!( - span, - &format!("`code` is not a valid nested attribute of a `{}` attribute", name) - ); + let mut slug = None; + let mut code = None; + + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) => { + slug.set_once((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if matches!( + meta.path().segments.last().unwrap().ident.to_string().as_str(), + "code" | "applicability" + ) => + { + // Don't error for valid follow-up attributes. + } + nested_attr => { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "first argument of the attribute should be the diagnostic \ + slug", + ) + }) + } + }; } - if matches!( - kind, - SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note - ) && self.applicability.is_some() - { - throw_span_err!( - span, - &format!( - "`applicability` is not a valid nested attribute of a `{}` attribute", - name - ) - ); + for nested_attr in nested_iter { + let meta = match nested_attr { + NestedMeta::Meta(ref meta) => meta, + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + let span = meta.span().unwrap(); + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); + + let value = match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value, + Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("a diagnostic slug must be the first argument to the attribute") + }), + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + match nested_name { + "code" => { + if matches!(kind, SubdiagnosticKind::Suggestion { .. }) { + let formatted_str = self.build_format(&value.value(), value.span()); + code.set_once((formatted_str, span)); + } else { + span_err( + span, + &format!( + "`code` is not a valid nested attribute of a `{}` attribute", + name + ), + ) + .emit(); + } + } + "applicability" => { + if matches!( + kind, + SubdiagnosticKind::Suggestion { .. } + | SubdiagnosticKind::MultipartSuggestion { .. } + ) { + let value = + Applicability::from_str(&value.value()).unwrap_or_else(|()| { + span_err(span, "invalid applicability").emit(); + Applicability::Unspecified + }); + self.applicability.set_once((quote! { #value }, span)); + } else { + span_err( + span, + &format!( + "`applicability` is not a valid nested attribute of a `{}` attribute", + name + ) + ).emit(); + } + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("only `code` and `applicability` are valid nested attributes") + }), + } } - if self.slug.is_none() { + let Some((slug, _)) = slug else { throw_span_err!( span, &format!( @@ -342,150 +374,334 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { name ) ); + }; + + match kind { + SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => { + let Some((code, _)) = code else { + throw_span_err!(span, "suggestion without `code = \"...\"`"); + }; + *code_field = code; + } + SubdiagnosticKind::Label + | SubdiagnosticKind::Note + | SubdiagnosticKind::Help + | SubdiagnosticKind::Warn + | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - self.kind.set_once((kind, span)); + kind_slugs.push((kind, slug)) } - Ok(()) + Ok(kind_slugs) } - fn generate_field_code( + /// Generates the code for a field with no attributes. + fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream { + let ast = binding.ast(); + assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg"); + + let diag = &self.diag; + let ident = ast.ident.as_ref().unwrap(); + quote! { + #diag.set_arg( + stringify!(#ident), + #binding + ); + } + } + + /// Generates the necessary code for all attributes on a field. + fn generate_field_attr_code( &mut self, binding: &BindingInfo<'_>, - is_suggestion: bool, - ) -> Result { + kind_stats: KindsStatistics, + ) -> TokenStream { let ast = binding.ast(); + assert!(ast.attrs.len() > 0, "field without attributes generating attr code"); + // Abstract over `Vec` and `Option` fields using `FieldInnerTy`, which will + // apply the generated code on each element in the `Vec` or `Option`. let inner_ty = FieldInnerTy::from_type(&ast.ty); - let info = FieldInfo { - binding: binding, - ty: inner_ty.inner_type().unwrap_or(&ast.ty), - span: &ast.span(), - }; + ast.attrs + .iter() + .map(|attr| { + let info = FieldInfo { + binding, + ty: inner_ty.inner_type().unwrap_or(&ast.ty), + span: &ast.span(), + }; - for attr in &ast.attrs { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - let span = attr.span().unwrap(); + let generated = self + .generate_field_code_inner(kind_stats, attr, info) + .unwrap_or_else(|v| v.to_compile_error()); - let meta = attr.parse_meta()?; - match meta { - Meta::Path(_) => match name { - "primary_span" => { - report_error_if_not_applied_to_span(attr, &info)?; - self.span_field.set_once((binding.binding.clone(), span)); - return Ok(quote! {}); - } - "applicability" if is_suggestion => { - report_error_if_not_applied_to_applicability(attr, &info)?; - let binding = binding.binding.clone(); - self.applicability.set_once((quote! { #binding }, span)); - return Ok(quote! {}); - } - "applicability" => { - span_err(span, "`#[applicability]` is only valid on suggestions").emit(); - return Ok(quote! {}); - } - "skip_arg" => { - return Ok(quote! {}); - } - _ => throw_invalid_attr!(attr, &meta, |diag| { + inner_ty.with(binding, generated) + }) + .collect() + } + + fn generate_field_code_inner( + &mut self, + kind_stats: KindsStatistics, + attr: &Attribute, + info: FieldInfo<'_>, + ) -> Result { + let meta = attr.parse_meta()?; + match meta { + Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path), + Meta::List(list @ MetaList { .. }) => { + self.generate_field_code_inner_list(kind_stats, attr, info, list) + } + _ => throw_invalid_attr!(attr, &meta), + } + } + + /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`). + fn generate_field_code_inner_path( + &mut self, + kind_stats: KindsStatistics, + attr: &Attribute, + info: FieldInfo<'_>, + path: Path, + ) -> Result { + let span = attr.span().unwrap(); + let ident = &path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + + match name { + "skip_arg" => Ok(quote! {}), + "primary_span" => { + if kind_stats.has_multipart_suggestion { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { diag.help( - "only `primary_span`, `applicability` and `skip_arg` are valid field \ - attributes", + "multipart suggestions use one or more `#[suggestion_part]`s rather \ + than one `#[primary_span]`", ) - }), - }, - _ => throw_invalid_attr!(attr, &meta), + }) + } + + report_error_if_not_applied_to_span(attr, &info)?; + + let binding = info.binding.binding.clone(); + self.span_field.set_once((binding, span)); + + Ok(quote! {}) + } + "suggestion_part" => { + self.has_suggestion_parts = true; + + if kind_stats.has_multipart_suggestion { + span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") + .emit(); + Ok(quote! {}) + } else { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + diag.help( + "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead", + ) + }); + } + } + "applicability" => { + if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion { + report_error_if_not_applied_to_applicability(attr, &info)?; + + let binding = info.binding.binding.clone(); + self.applicability.set_once((quote! { #binding }, span)); + } else { + span_err(span, "`#[applicability]` is only valid on suggestions").emit(); + } + + Ok(quote! {}) } + _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + let mut span_attrs = vec![]; + if kind_stats.has_multipart_suggestion { + span_attrs.push("suggestion_part"); + } + if !kind_stats.all_multipart_suggestions { + span_attrs.push("primary_span") + } + diag.help(format!( + "only `{}`, `applicability` and `skip_arg` are valid field attributes", + span_attrs.join(", ") + )) + }), } + } - let ident = ast.ident.as_ref().unwrap(); + /// Generates the code for a `[Meta::List]`-like attribute on a field (e.g. + /// `#[suggestion_part(code = "...")]`). + fn generate_field_code_inner_list( + &mut self, + kind_stats: KindsStatistics, + attr: &Attribute, + info: FieldInfo<'_>, + list: MetaList, + ) -> Result { + let span = attr.span().unwrap(); + let ident = &list.path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + + match name { + "suggestion_part" => { + if !kind_stats.has_multipart_suggestion { + throw_invalid_attr!(attr, &Meta::List(list), |diag| { + diag.help( + "`#[suggestion_part(...)]` is only valid in multipart suggestions", + ) + }) + } - let diag = &self.diag; - let generated = quote! { - #diag.set_arg( - stringify!(#ident), - #binding - ); - }; + self.has_suggestion_parts = true; + + report_error_if_not_applied_to_span(attr, &info)?; + + let mut code = None; + for nested_attr in list.nested.iter() { + let NestedMeta::Meta(ref meta) = nested_attr else { + throw_invalid_nested_attr!(attr, &nested_attr); + }; + + let span = meta.span().unwrap(); + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); + + let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else { + throw_invalid_nested_attr!(attr, &nested_attr); + }; + + match nested_name { + "code" => { + let formatted_str = self.build_format(&value.value(), value.span()); + code.set_once((formatted_str, span)); + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("`code` is the only valid nested attribute") + }), + } + } - Ok(inner_ty.with(binding, generated)) + let Some((code, _)) = code else { + span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") + .emit(); + return Ok(quote! {}); + }; + let binding = info.binding; + + Ok(quote! { suggestions.push((#binding, #code)); }) + } + _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| { + let mut span_attrs = vec![]; + if kind_stats.has_multipart_suggestion { + span_attrs.push("suggestion_part"); + } + if !kind_stats.all_multipart_suggestions { + span_attrs.push("primary_span") + } + diag.help(format!( + "only `{}`, `applicability` and `skip_arg` are valid field attributes", + span_attrs.join(", ") + )) + }), + } } - fn into_tokens(&mut self) -> Result { - self.identify_kind()?; - let Some(kind) = self.kind.map(|(kind, _)| kind) else { + pub fn into_tokens(&mut self) -> Result { + let kind_slugs = self.identify_kind()?; + if kind_slugs.is_empty() { throw_span_err!( self.variant.ast().ident.span().unwrap(), "subdiagnostic kind not specified" ); }; - let is_suggestion = matches!(kind, SubdiagnosticKind::Suggestion(_)); + let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); - let mut args = TokenStream::new(); - for binding in self.variant.bindings() { - let arg = self - .generate_field_code(binding, is_suggestion) - .unwrap_or_else(|v| v.to_compile_error()); - args.extend(arg); - } - - // Missing slug errors will already have been reported. - let slug = self - .slug - .as_ref() - .map(|(slug, _)| slug.clone()) - .unwrap_or_else(|| parse_quote! { you::need::to::specify::a::slug }); - let code = match self.code.as_ref() { - Some((code, _)) => Some(quote! { #code }), - None if is_suggestion => { - span_err(self.span, "suggestion without `code = \"...\"`").emit(); - Some(quote! { /* macro error */ "..." }) - } - None => None, + let init = if kind_stats.has_multipart_suggestion { + quote! { let mut suggestions = Vec::new(); } + } else { + quote! {} }; + let attr_args: TokenStream = self + .variant + .bindings() + .iter() + .filter(|binding| !binding.ast().attrs.is_empty()) + .map(|binding| self.generate_field_attr_code(binding, kind_stats)) + .collect(); + let span_field = self.span_field.as_ref().map(|(span, _)| span); - let applicability = match self.applicability.clone() { - Some((applicability, _)) => Some(applicability), - None if is_suggestion => { - span_err(self.span, "suggestion without `applicability`").emit(); - Some(quote! { rustc_errors::Applicability::Unspecified }) - } - None => None, - }; + let applicability = self.applicability.take().map_or_else( + || quote! { rustc_errors::Applicability::Unspecified }, + |(applicability, _)| applicability, + ); let diag = &self.diag; - let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::fluent::#slug }; - let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { - if let Some(span) = span_field { - quote! { #diag.#name(#span, #message, #code, #applicability); } - } else { - span_err(self.span, "suggestion without `#[primary_span]` field").emit(); - quote! { unreachable!(); } - } - } else if matches!(kind, SubdiagnosticKind::Label) { - if let Some(span) = span_field { - quote! { #diag.#name(#span, #message); } - } else { - span_err(self.span, "label without `#[primary_span]` field").emit(); - quote! { unreachable!(); } - } - } else { - if let Some(span) = span_field { - quote! { #diag.#name(#span, #message); } - } else { - quote! { #diag.#name(#message); } - } - }; + let mut calls = TokenStream::new(); + for (kind, slug) in kind_slugs { + let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); + let message = quote! { rustc_errors::fluent::#slug }; + let call = match kind { + SubdiagnosticKind::Suggestion { suggestion_kind, code } => { + if let Some(span) = span_field { + let style = suggestion_kind.to_suggestion_style(); + + quote! { #diag.#name(#span, #message, #code, #applicability, #style); } + } else { + span_err(self.span, "suggestion without `#[primary_span]` field").emit(); + quote! { unreachable!(); } + } + } + SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { + if !self.has_suggestion_parts { + span_err( + self.span, + "multipart suggestion without any `#[suggestion_part(...)]` fields", + ) + .emit(); + } + + let style = suggestion_kind.to_suggestion_style(); + + quote! { #diag.#name(#message, suggestions, #applicability, #style); } + } + SubdiagnosticKind::Label => { + if let Some(span) = span_field { + quote! { #diag.#name(#span, #message); } + } else { + span_err(self.span, "label without `#[primary_span]` field").emit(); + quote! { unreachable!(); } + } + } + _ => { + if let Some(span) = span_field { + quote! { #diag.#name(#span, #message); } + } else { + quote! { #diag.#name(#message); } + } + } + }; + calls.extend(call); + } + + let plain_args: TokenStream = self + .variant + .bindings() + .iter() + .filter(|binding| binding.ast().attrs.is_empty()) + .map(|binding| self.generate_field_set_arg(binding)) + .collect(); Ok(quote! { - #call - #args + #init + #attr_args + #calls + #plain_args }) } } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 002abb152..ad9ecd39b 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -235,35 +235,40 @@ pub(crate) trait HasFieldMap { // the referenced fields. Leaves `it` sitting on the closing brace of the format string, so // the next call to `it.next()` retrieves the next character. while let Some(c) = it.next() { - if c == '{' && *it.peek().unwrap_or(&'\0') != '{' { - let mut eat_argument = || -> Option { - let mut result = String::new(); - // Format specifiers look like: - // - // format := '{' [ argument ] [ ':' format_spec ] '}' . - // - // Therefore, we only need to eat until ':' or '}' to find the argument. - while let Some(c) = it.next() { - result.push(c); - let next = *it.peek().unwrap_or(&'\0'); - if next == '}' { - break; - } else if next == ':' { - // Eat the ':' character. - assert_eq!(it.next().unwrap(), ':'); - break; - } - } - // Eat until (and including) the matching '}' - while it.next()? != '}' { - continue; + if c != '{' { + continue; + } + if *it.peek().unwrap_or(&'\0') == '{' { + assert_eq!(it.next().unwrap(), '{'); + continue; + } + let mut eat_argument = || -> Option { + let mut result = String::new(); + // Format specifiers look like: + // + // format := '{' [ argument ] [ ':' format_spec ] '}' . + // + // Therefore, we only need to eat until ':' or '}' to find the argument. + while let Some(c) = it.next() { + result.push(c); + let next = *it.peek().unwrap_or(&'\0'); + if next == '}' { + break; + } else if next == ':' { + // Eat the ':' character. + assert_eq!(it.next().unwrap(), ':'); + break; } - Some(result) - }; - - if let Some(referenced_field) = eat_argument() { - referenced_fields.insert(referenced_field); } + // Eat until (and including) the matching '}' + while it.next()? != '}' { + continue; + } + Some(result) + }; + + if let Some(referenced_field) = eat_argument() { + referenced_fields.insert(referenced_field); } } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index ab509b26f..2c027d754 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,9 +1,11 @@ #![feature(allow_internal_unstable)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] #![allow(rustc::default_hash_types)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![recursion_limit = "128"] use synstructure::decl_derive; @@ -65,10 +67,10 @@ pub fn newtype_index(input: TokenStream) -> TokenStream { /// ..where `typeck.ftl` has the following contents.. /// /// ```fluent -/// typeck-field-multiply-specified-in-initializer = +/// typeck_field_multiply_specified_in_initializer = /// field `{$ident}` specified more than once /// .label = used more than once -/// .label-previous-use = first use of `{$ident}` +/// .label_previous_use = first use of `{$ident}` /// ``` /// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and /// will generate the following code: @@ -81,11 +83,11 @@ pub fn newtype_index(input: TokenStream) -> TokenStream { /// mod fluent_generated { /// mod typeck { /// pub const field_multiply_specified_in_initializer: DiagnosticMessage = -/// DiagnosticMessage::fluent("typeck-field-multiply-specified-in-initializer"); +/// DiagnosticMessage::fluent("typeck_field_multiply_specified_in_initializer"); /// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage = /// DiagnosticMessage::fluent_attr( -/// "typeck-field-multiply-specified-in-initializer", -/// "previous-use-label" +/// "typeck_field_multiply_specified_in_initializer", +/// "previous_use_label" /// ); /// } /// } @@ -127,12 +129,10 @@ decl_derive!([Lift, attributes(lift)] => lift::lift_derive); decl_derive!( [SessionDiagnostic, attributes( // struct attributes - warning, - error, - lint, + diag, help, note, - warn_, + warning, // field attributes skip_arg, primary_span, @@ -146,12 +146,10 @@ decl_derive!( decl_derive!( [LintDiagnostic, attributes( // struct attributes - warning, - error, - lint, + diag, help, note, - warn_, + warning, // field attributes skip_arg, primary_span, @@ -168,13 +166,18 @@ decl_derive!( label, help, note, - warn_, + warning, suggestion, suggestion_short, suggestion_hidden, suggestion_verbose, + multipart_suggestion, + multipart_suggestion_short, + multipart_suggestion_hidden, + multipart_suggestion_verbose, // field attributes skip_arg, primary_span, + suggestion_part, applicability)] => diagnostics::session_subdiagnostic_derive ); diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index a69126533..d49926c90 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -1,139 +1,17 @@ use proc_macro::TokenStream; -use proc_macro2::{Delimiter, TokenTree}; use quote::{quote, quote_spanned}; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error, - Expr, Ident, ReturnType, Token, Type, + braced, parenthesized, parse_macro_input, parse_quote, token, AttrStyle, Attribute, Block, + Error, Expr, Ident, Pat, ReturnType, Token, Type, }; mod kw { syn::custom_keyword!(query); } -/// Ident or a wildcard `_`. -struct IdentOrWild(Ident); - -impl Parse for IdentOrWild { - fn parse(input: ParseStream<'_>) -> Result { - Ok(if input.peek(Token![_]) { - let underscore = input.parse::()?; - IdentOrWild(Ident::new("_", underscore.span())) - } else { - IdentOrWild(input.parse()?) - }) - } -} - -/// A modifier for a query -enum QueryModifier { - /// The description of the query. - Desc(Option, Punctuated), - - /// Use this type for the in-memory cache. - Storage(Type), - - /// Cache the query to disk if the `Expr` returns true. - Cache(Option, Block), - - /// Custom code to load the query from disk. - LoadCached(Ident, Ident, Block), - - /// A cycle error for this query aborting the compilation with a fatal error. - FatalCycle(Ident), - - /// A cycle error results in a delay_bug call - CycleDelayBug(Ident), - - /// Don't hash the result, instead just mark a query red if it runs - NoHash(Ident), - - /// Generate a dep node based on the dependencies of the query - Anon(Ident), - - /// Always evaluate the query, ignoring its dependencies - EvalAlways(Ident), - - /// Use a separate query provider for local and extern crates - SeparateProvideExtern(Ident), - - /// Always remap the ParamEnv's constness before hashing and passing to the query provider - RemapEnvConstness(Ident), -} - -impl Parse for QueryModifier { - fn parse(input: ParseStream<'_>) -> Result { - let modifier: Ident = input.parse()?; - if modifier == "desc" { - // Parse a description modifier like: - // `desc { |tcx| "foo {}", tcx.item_path(key) }` - let attr_content; - braced!(attr_content in input); - let tcx = if attr_content.peek(Token![|]) { - attr_content.parse::()?; - let tcx = attr_content.parse()?; - attr_content.parse::()?; - Some(tcx) - } else { - None - }; - let desc = attr_content.parse_terminated(Expr::parse)?; - Ok(QueryModifier::Desc(tcx, desc)) - } else if modifier == "cache_on_disk_if" { - // Parse a cache modifier like: - // `cache(tcx, value) { |tcx| key.is_local() }` - let has_args = if let TokenTree::Group(group) = input.fork().parse()? { - group.delimiter() == Delimiter::Parenthesis - } else { - false - }; - let args = if has_args { - let args; - parenthesized!(args in input); - let tcx = args.parse()?; - Some(tcx) - } else { - None - }; - let block = input.parse()?; - Ok(QueryModifier::Cache(args, block)) - } else if modifier == "load_cached" { - // Parse a load_cached modifier like: - // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }` - let args; - parenthesized!(args in input); - let tcx = args.parse()?; - args.parse::()?; - let id = args.parse()?; - let block = input.parse()?; - Ok(QueryModifier::LoadCached(tcx, id, block)) - } else if modifier == "storage" { - let args; - parenthesized!(args in input); - let ty = args.parse()?; - Ok(QueryModifier::Storage(ty)) - } else if modifier == "fatal_cycle" { - Ok(QueryModifier::FatalCycle(modifier)) - } else if modifier == "cycle_delay_bug" { - Ok(QueryModifier::CycleDelayBug(modifier)) - } else if modifier == "no_hash" { - Ok(QueryModifier::NoHash(modifier)) - } else if modifier == "anon" { - Ok(QueryModifier::Anon(modifier)) - } else if modifier == "eval_always" { - Ok(QueryModifier::EvalAlways(modifier)) - } else if modifier == "separate_provide_extern" { - Ok(QueryModifier::SeparateProvideExtern(modifier)) - } else if modifier == "remap_env_constness" { - Ok(QueryModifier::RemapEnvConstness(modifier)) - } else { - Err(Error::new(modifier.span(), "unknown query modifier")) - } - } -} - /// Ensures only doc comment attributes are used fn check_attributes(attrs: Vec) -> Result> { let inner = |attr: Attribute| { @@ -154,16 +32,16 @@ fn check_attributes(attrs: Vec) -> Result> { /// A compiler query. `query ... { ... }` struct Query { doc_comments: Vec, - modifiers: List, + modifiers: QueryModifiers, name: Ident, - key: IdentOrWild, + key: Pat, arg: Type, result: ReturnType, } impl Parse for Query { fn parse(input: ParseStream<'_>) -> Result { - let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; + let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; @@ -178,7 +56,13 @@ impl Parse for Query { // Parse the query modifiers let content; braced!(content in input); - let modifiers = content.parse()?; + let modifiers = parse_query_modifiers(&content)?; + + // If there are no doc-comments, give at least some idea of what + // it does by showing the query description. + if doc_comments.is_empty() { + doc_comments.push(doc_comment_from_desc(&modifiers.desc.1)?); + } Ok(Query { doc_comments, modifiers, name, key, arg, result }) } @@ -202,13 +86,10 @@ struct QueryModifiers { desc: (Option, Punctuated), /// Use this type for the in-memory cache. - storage: Option, + arena_cache: Option, /// Cache the query to disk if the `Block` returns true. - cache: Option<(Option, Block)>, - - /// Custom code to load the query from disk. - load_cached: Option<(Ident, Ident, Block)>, + cache: Option<(Option, Block)>, /// A cycle error for this query aborting the compilation with a fatal error. fatal_cycle: Option, @@ -222,9 +103,12 @@ struct QueryModifiers { /// Generate a dep node based on the dependencies of the query anon: Option, - // Always evaluate the query, ignoring its dependencies + /// Always evaluate the query, ignoring its dependencies eval_always: Option, + /// Whether the query has a call depth limit + depth_limit: Option, + /// Use a separate query provider for local and extern crates separate_provide_extern: Option, @@ -232,10 +116,8 @@ struct QueryModifiers { remap_env_constness: Option, } -/// Process query modifiers into a struct, erroring on duplicates -fn process_modifiers(query: &mut Query) -> QueryModifiers { - let mut load_cached = None; - let mut storage = None; +fn parse_query_modifiers(input: ParseStream<'_>) -> Result { + let mut arena_cache = None; let mut cache = None; let mut desc = None; let mut fatal_cycle = None; @@ -243,121 +125,77 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { let mut no_hash = None; let mut anon = None; let mut eval_always = None; + let mut depth_limit = None; let mut separate_provide_extern = None; let mut remap_env_constness = None; - for modifier in query.modifiers.0.drain(..) { - match modifier { - QueryModifier::LoadCached(tcx, id, block) => { - if load_cached.is_some() { - panic!("duplicate modifier `load_cached` for query `{}`", query.name); - } - load_cached = Some((tcx, id, block)); - } - QueryModifier::Storage(ty) => { - if storage.is_some() { - panic!("duplicate modifier `storage` for query `{}`", query.name); - } - storage = Some(ty); - } - QueryModifier::Cache(args, expr) => { - if cache.is_some() { - panic!("duplicate modifier `cache` for query `{}`", query.name); - } - cache = Some((args, expr)); - } - QueryModifier::Desc(tcx, list) => { - if desc.is_some() { - panic!("duplicate modifier `desc` for query `{}`", query.name); - } - // If there are no doc-comments, give at least some idea of what - // it does by showing the query description. - if query.doc_comments.is_empty() { - use ::syn::*; - let mut list = list.iter(); - let format_str: String = match list.next() { - Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => { - lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency - } - _ => panic!("Expected a string literal"), - }; - let mut fmt_fragments = format_str.split("{}"); - let mut doc_string = fmt_fragments.next().unwrap().to_string(); - list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each( - |(tts, next_fmt_fragment)| { - use ::core::fmt::Write; - write!( - &mut doc_string, - " `{}` {}", - tts.to_string().replace(" . ", "."), - next_fmt_fragment, - ) - .unwrap(); - }, - ); - let doc_string = format!( - "[query description - consider adding a doc-comment!] {}", - doc_string - ); - let comment = parse_quote! { - #[doc = #doc_string] - }; - query.doc_comments.push(comment); - } - desc = Some((tcx, list)); - } - QueryModifier::FatalCycle(ident) => { - if fatal_cycle.is_some() { - panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name); - } - fatal_cycle = Some(ident); - } - QueryModifier::CycleDelayBug(ident) => { - if cycle_delay_bug.is_some() { - panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name); - } - cycle_delay_bug = Some(ident); - } - QueryModifier::NoHash(ident) => { - if no_hash.is_some() { - panic!("duplicate modifier `no_hash` for query `{}`", query.name); - } - no_hash = Some(ident); - } - QueryModifier::Anon(ident) => { - if anon.is_some() { - panic!("duplicate modifier `anon` for query `{}`", query.name); - } - anon = Some(ident); - } - QueryModifier::EvalAlways(ident) => { - if eval_always.is_some() { - panic!("duplicate modifier `eval_always` for query `{}`", query.name); - } - eval_always = Some(ident); - } - QueryModifier::SeparateProvideExtern(ident) => { - if separate_provide_extern.is_some() { - panic!( - "duplicate modifier `separate_provide_extern` for query `{}`", - query.name - ); - } - separate_provide_extern = Some(ident); - } - QueryModifier::RemapEnvConstness(ident) => { - if remap_env_constness.is_some() { - panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name); + + while !input.is_empty() { + let modifier: Ident = input.parse()?; + + macro_rules! try_insert { + ($name:ident = $expr:expr) => { + if $name.is_some() { + return Err(Error::new(modifier.span(), "duplicate modifier")); } - remap_env_constness = Some(ident) - } + $name = Some($expr); + }; + } + + if modifier == "desc" { + // Parse a description modifier like: + // `desc { |tcx| "foo {}", tcx.item_path(key) }` + let attr_content; + braced!(attr_content in input); + let tcx = if attr_content.peek(Token![|]) { + attr_content.parse::()?; + let tcx = attr_content.parse()?; + attr_content.parse::()?; + Some(tcx) + } else { + None + }; + let list = attr_content.parse_terminated(Expr::parse)?; + try_insert!(desc = (tcx, list)); + } else if modifier == "cache_on_disk_if" { + // Parse a cache modifier like: + // `cache(tcx) { |tcx| key.is_local() }` + let args = if input.peek(token::Paren) { + let args; + parenthesized!(args in input); + let tcx = args.parse()?; + Some(tcx) + } else { + None + }; + let block = input.parse()?; + try_insert!(cache = (args, block)); + } else if modifier == "arena_cache" { + try_insert!(arena_cache = modifier); + } else if modifier == "fatal_cycle" { + try_insert!(fatal_cycle = modifier); + } else if modifier == "cycle_delay_bug" { + try_insert!(cycle_delay_bug = modifier); + } else if modifier == "no_hash" { + try_insert!(no_hash = modifier); + } else if modifier == "anon" { + try_insert!(anon = modifier); + } else if modifier == "eval_always" { + try_insert!(eval_always = modifier); + } else if modifier == "depth_limit" { + try_insert!(depth_limit = modifier); + } else if modifier == "separate_provide_extern" { + try_insert!(separate_provide_extern = modifier); + } else if modifier == "remap_env_constness" { + try_insert!(remap_env_constness = modifier); + } else { + return Err(Error::new(modifier.span(), "unknown query modifier")); } } - let desc = desc.unwrap_or_else(|| { - panic!("no description provided for query `{}`", query.name); - }); - QueryModifiers { - load_cached, - storage, + let Some(desc) = desc else { + return Err(input.error("no description provided")); + }; + Ok(QueryModifiers { + arena_cache, cache, desc, fatal_cycle, @@ -365,43 +203,48 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { no_hash, anon, eval_always, + depth_limit, separate_provide_extern, remap_env_constness, - } + }) +} + +fn doc_comment_from_desc(list: &Punctuated) -> Result { + use ::syn::*; + let mut iter = list.iter(); + let format_str: String = match iter.next() { + Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => { + lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency + } + _ => return Err(Error::new(list.span(), "Expected a string literal")), + }; + let mut fmt_fragments = format_str.split("{}"); + let mut doc_string = fmt_fragments.next().unwrap().to_string(); + iter.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each( + |(tts, next_fmt_fragment)| { + use ::core::fmt::Write; + write!( + &mut doc_string, + " `{}` {}", + tts.to_string().replace(" . ", "."), + next_fmt_fragment, + ) + .unwrap(); + }, + ); + let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string); + Ok(parse_quote! { #[doc = #doc_string] }) } /// Add the impl of QueryDescription for the query to `impls` if one is requested -fn add_query_description_impl( - query: &Query, - modifiers: QueryModifiers, - impls: &mut proc_macro2::TokenStream, -) { +fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) { let name = &query.name; - let key = &query.key.0; + let key = &query.key; + let modifiers = &query.modifiers; // Find out if we should cache the query on disk let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { - let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() { - // Use custom code to load the query from disk - quote! { - const TRY_LOAD_FROM_DISK: Option, SerializedDepNodeIndex) -> Option> - = Some(|#tcx, #id| { #block }); - } - } else { - // Use the default code to load the query from disk - quote! { - const TRY_LOAD_FROM_DISK: Option, SerializedDepNodeIndex) -> Option> - = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)); - } - }; - - let tcx = args - .as_ref() - .map(|t| { - let t = &t.0; - quote! { #t } - }) - .unwrap_or_else(|| quote! { _ }); + let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ }); // expr is a `Block`, meaning that `{ #expr }` gets expanded // to `{ { stmts... } }`, which triggers the `unused_braces` lint. quote! { @@ -410,29 +253,22 @@ fn add_query_description_impl( fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool { #expr } - - #try_load_from_disk } } else { - if modifiers.load_cached.is_some() { - panic!("load_cached modifier on query `{}` without a cache modifier", name); - } quote! { #[inline] fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool { false } - - const TRY_LOAD_FROM_DISK: Option, SerializedDepNodeIndex) -> Option> = None; } }; - let (tcx, desc) = modifiers.desc; + let (tcx, desc) = &modifiers.desc; let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t }); let desc = quote! { #[allow(unused_variables)] - fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String { + fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String { let (#tcx, #key) = (*tcx, key); ::rustc_middle::ty::print::with_no_trimmed_paths!( format!(#desc) @@ -441,7 +277,7 @@ fn add_query_description_impl( }; impls.extend(quote! { - (#name<$tcx:tt>) => { + (#name) => { #desc #cache }; @@ -453,13 +289,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; - let mut dep_node_def_stream = quote! {}; let mut cached_queries = quote! {}; - for mut query in queries.0 { - let modifiers = process_modifiers(&mut query); - let name = &query.name; - let arg = &query.arg; + for query in queries.0 { + let Query { name, arg, modifiers, .. } = &query; let result_full = &query.result; let result = match query.result { ReturnType::Default => quote! { -> () }, @@ -474,38 +307,32 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut attributes = Vec::new(); - // Pass on the fatal_cycle modifier - if let Some(fatal_cycle) = &modifiers.fatal_cycle { - attributes.push(quote! { (#fatal_cycle) }); - }; - // Pass on the storage modifier - if let Some(ref ty) = modifiers.storage { - let span = ty.span(); - attributes.push(quote_spanned! {span=> (storage #ty) }); - }; - // Pass on the cycle_delay_bug modifier - if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug { - attributes.push(quote! { (#cycle_delay_bug) }); - }; - // Pass on the no_hash modifier - if let Some(no_hash) = &modifiers.no_hash { - attributes.push(quote! { (#no_hash) }); - }; - // Pass on the anon modifier - if let Some(anon) = &modifiers.anon { - attributes.push(quote! { (#anon) }); - }; - // Pass on the eval_always modifier - if let Some(eval_always) = &modifiers.eval_always { - attributes.push(quote! { (#eval_always) }); - }; - // Pass on the separate_provide_extern modifier - if let Some(separate_provide_extern) = &modifiers.separate_provide_extern { - attributes.push(quote! { (#separate_provide_extern) }); + macro_rules! passthrough { + ( $( $modifier:ident ),+ $(,)? ) => { + $( if let Some($modifier) = &modifiers.$modifier { + attributes.push(quote! { (#$modifier) }); + }; )+ + } } - // Pass on the remap_env_constness modifier - if let Some(remap_env_constness) = &modifiers.remap_env_constness { - attributes.push(quote! { (#remap_env_constness) }); + + passthrough!( + fatal_cycle, + arena_cache, + cycle_delay_bug, + no_hash, + anon, + eval_always, + depth_limit, + separate_provide_extern, + remap_env_constness, + ); + + if modifiers.cache.is_some() { + attributes.push(quote! { (cache) }); + } + // Pass on the cache modifier + if modifiers.cache.is_some() { + attributes.push(quote! { (cache) }); } // This uses the span of the query definition for the commas, @@ -516,48 +343,27 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // be very useful. let span = name.span(); let attribute_stream = quote_spanned! {span=> #(#attributes),*}; - let doc_comments = query.doc_comments.iter(); + let doc_comments = &query.doc_comments; // Add the query to the group query_stream.extend(quote! { #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, }); - // Create a dep node for the query - dep_node_def_stream.extend(quote! { - [#attribute_stream] #name(#arg), - }); - - add_query_description_impl(&query, modifiers, &mut query_description_stream); + add_query_description_impl(&query, &mut query_description_stream); } TokenStream::from(quote! { #[macro_export] macro_rules! rustc_query_append { - ([$($macro:tt)*][$($other:tt)*]) => { - $($macro)* { - $($other)* - + ($macro:ident! $( [$($other:tt)*] )?) => { + $macro! { + $( $($other)* )? #query_stream - } } } - macro_rules! rustc_dep_node_append { - ([$($macro:tt)*][$($other:tt)*]) => { - $($macro)*( - $($other)* - #dep_node_def_stream - ); - } - } - #[macro_export] - macro_rules! rustc_cached_queries { - ($($macro:tt)*) => { - $($macro)*(#cached_queries); - } - } #[macro_export] macro_rules! rustc_query_description { #query_description_stream diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 1b245f2a7..92590c33b 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -195,10 +195,10 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { #n, }); } - let _ = counter; // for future use let output = quote! { const SYMBOL_DIGITS_BASE: u32 = #digits_base; + const PREINTERNED_SYMBOLS_COUNT: u32 = #counter; #[doc(hidden)] #[allow(non_upper_case_globals)] diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 708d0b1fd..cfcceecbe 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,5 +1,9 @@ //! Validates all used crates and extern libraries and loads their metadata +use crate::errors::{ + ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc, + NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore, +}; use crate::locator::{CrateError, CrateLocator, CratePaths}; use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}; @@ -29,7 +33,6 @@ use proc_macro::bridge::client::ProcMacro; use std::ops::Fn; use std::path::Path; use std::{cmp, env}; -use tracing::{debug, info}; #[derive(Clone)] pub struct CStore { @@ -263,7 +266,7 @@ impl<'a> CrateLoader<'a> { fn existing_match(&self, name: Symbol, hash: Option, kind: PathKind) -> Option { for (cnum, data) in self.cstore.iter_crate_data() { if data.name() != name { - tracing::trace!("{} did not match {}", data.name(), name); + trace!("{} did not match {}", data.name(), name); continue; } @@ -746,15 +749,10 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. if !data.is_panic_runtime() { - self.sess.err(&format!("the crate `{}` is not a panic runtime", name)); + self.sess.emit_err(CrateNotPanicRuntime { crate_name: name }); } if data.required_panic_strategy() != Some(desired_strategy) { - self.sess.err(&format!( - "the crate `{}` does not have the panic \ - strategy `{}`", - name, - desired_strategy.desc() - )); + self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy }); } self.cstore.injected_panic_runtime = Some(cnum); @@ -774,10 +772,7 @@ impl<'a> CrateLoader<'a> { let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) { - self.sess.err( - "`profiler_builtins` crate (required by compiler options) \ - is not compatible with crate attribute `#![no_core]`", - ); + self.sess.emit_err(ProfilerBuiltinsNeedsCore); } let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; }; @@ -785,18 +780,14 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.is_profiler_runtime() { - self.sess.err(&format!("the crate `{}` is not a profiler runtime", name)); + self.sess.emit_err(NotProfilerRuntime { crate_name: name }); } } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) { [span1, span2, ..] => { - self.sess - .struct_span_err(*span2, "cannot define multiple global allocators") - .span_label(*span2, "cannot define a new global allocator") - .span_label(*span1, "previous global allocator defined here") - .emit(); + self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), @@ -832,11 +823,10 @@ impl<'a> CrateLoader<'a> { if data.has_global_allocator() { match global_allocator { Some(other_crate) => { - self.sess.err(&format!( - "the `#[global_allocator]` in {} conflicts with global allocator in: {}", - other_crate, - data.name() - )); + self.sess.emit_err(ConflictingGlobalAlloc { + crate_name: data.name(), + other_crate_name: other_crate, + }); } None => global_allocator = Some(data.name()), } @@ -855,10 +845,7 @@ impl<'a> CrateLoader<'a> { if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { - self.sess.err( - "no global memory allocator found but one is required; link to std or add \ - `#[global_allocator]` to a static item that implements the GlobalAlloc trait", - ); + self.sess.emit_err(GlobalAllocRequired); } self.cstore.allocator_kind = Some(AllocatorKind::Default); } @@ -882,14 +869,11 @@ impl<'a> CrateLoader<'a> { for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) { let data = self.cstore.get_crate_data(dep); if needs_dep(&data) { - self.sess.err(&format!( - "the crate `{}` cannot depend \ - on a crate that needs {}, but \ - it depends on `{}`", - self.cstore.get_crate_data(krate).name(), - what, - data.name() - )); + self.sess.emit_err(NoTransitiveNeedsDep { + crate_name: self.cstore.get_crate_data(krate).name(), + needs_crate_name: what, + deps_crate_name: data.name(), + }); } } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index b765c34f8..6112ec9e4 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -52,6 +52,10 @@ //! than finding a number of solutions (there are normally quite a few). use crate::creader::CStore; +use crate::errors::{ + BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired, + RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes, +}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::CrateNum; @@ -136,11 +140,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if src.rlib.is_some() { continue; } - sess.err(&format!( - "crate `{}` required to be available in rlib format, \ - but was not found in this form", - tcx.crate_name(cnum) - )); + sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) }); } return Vec::new(); } @@ -158,11 +158,11 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let name = tcx.crate_name(cnum); let src = tcx.used_crate_source(cnum); if src.dylib.is_some() { - tracing::info!("adding dylib: {}", name); + info!("adding dylib: {}", name); add_library(tcx, cnum, RequireDynamic, &mut formats); let deps = tcx.dylib_dependency_formats(cnum); for &(depnum, style) in deps.iter() { - tracing::info!("adding {:?}: {}", style, tcx.crate_name(depnum)); + info!("adding {:?}: {}", style, tcx.crate_name(depnum)); add_library(tcx, depnum, style, &mut formats); } } @@ -190,7 +190,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { && tcx.dep_kind(cnum) == CrateDepKind::Explicit { assert!(src.rlib.is_some() || src.rmeta.is_some()); - tracing::info!("adding staticlib: {}", tcx.crate_name(cnum)); + info!("adding staticlib: {}", tcx.crate_name(cnum)); add_library(tcx, cnum, RequireStatic, &mut formats); ret[cnum.as_usize() - 1] = Linkage::Static; } @@ -224,12 +224,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { Linkage::Static => "rlib", _ => "dylib", }; - sess.err(&format!( - "crate `{}` required to be available in {} format, \ - but was not found in this form", - tcx.crate_name(cnum), - kind - )); + sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind }); } } } @@ -253,17 +248,7 @@ fn add_library( // This error is probably a little obscure, but I imagine that it // can be refined over time. if link2 != link || link == RequireStatic { - tcx.sess - .struct_err(&format!( - "cannot satisfy dependencies so `{}` only \ - shows up once", - tcx.crate_name(cnum) - )) - .help( - "having upstream crates all available in one format \ - will likely make this go away", - ) - .emit(); + tcx.sess.emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) }); } } None => { @@ -360,11 +345,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if let Some((prev, _)) = panic_runtime { let prev_name = tcx.crate_name(prev); let cur_name = tcx.crate_name(cnum); - sess.err(&format!( - "cannot link together two \ - panic runtimes: {} and {}", - prev_name, cur_name - )); + sess.emit_err(TwoPanicRuntimes { prev_name, cur_name }); } panic_runtime = Some(( cnum, @@ -384,13 +365,10 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { // First up, validate that our selected panic runtime is indeed exactly // our same strategy. if found_strategy != desired_strategy { - sess.err(&format!( - "the linked panic runtime `{}` is \ - not compiled with this crate's \ - panic strategy `{}`", - tcx.crate_name(runtime_cnum), - desired_strategy.desc() - )); + sess.emit_err(BadPanicStrategy { + runtime: tcx.crate_name(runtime_cnum), + strategy: desired_strategy, + }); } // Next up, verify that all other crates are compatible with this panic @@ -407,28 +385,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { } if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { - sess.err(&format!( - "the crate `{}` requires \ - panic strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_strategy.desc(), - desired_strategy.desc() - )); + sess.emit_err(RequiredPanicStrategy { + crate_name: tcx.crate_name(cnum), + found_strategy, + desired_strategy}); } let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy { - sess.err(&format!( - "the crate `{}` is compiled with the \ - panic-in-drop strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_drop_strategy.desc(), - tcx.sess.opts.unstable_opts.panic_in_drop.desc() - )); + sess.emit_err(IncompatiblePanicInDropStrategy { + crate_name: tcx.crate_name(cnum), + found_strategy: found_drop_strategy, + desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, + }); } } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs new file mode 100644 index 000000000..7d63fad32 --- /dev/null +++ b/compiler/rustc_metadata/src/errors.rs @@ -0,0 +1,679 @@ +use std::{ + io::Error, + path::{Path, PathBuf}, +}; + +use rustc_errors::{error_code, ErrorGuaranteed}; +use rustc_macros::SessionDiagnostic; +use rustc_session::{config, SessionDiagnostic}; +use rustc_span::{sym, Span, Symbol}; +use rustc_target::spec::{PanicStrategy, TargetTriple}; + +use crate::locator::CrateFlavor; + +#[derive(SessionDiagnostic)] +#[diag(metadata::rlib_required)] +pub struct RlibRequired { + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_required)] +pub struct LibRequired<'a> { + pub crate_name: Symbol, + pub kind: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_dep_multiple)] +#[help] +pub struct CrateDepMultiple { + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::two_panic_runtimes)] +pub struct TwoPanicRuntimes { + pub prev_name: Symbol, + pub cur_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::bad_panic_strategy)] +pub struct BadPanicStrategy { + pub runtime: Symbol, + pub strategy: PanicStrategy, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::required_panic_strategy)] +pub struct RequiredPanicStrategy { + pub crate_name: Symbol, + pub found_strategy: PanicStrategy, + pub desired_strategy: PanicStrategy, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_panic_in_drop_strategy)] +pub struct IncompatiblePanicInDropStrategy { + pub crate_name: Symbol, + pub found_strategy: PanicStrategy, + pub desired_strategy: PanicStrategy, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_names_in_link)] +pub struct MultipleNamesInLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_kinds_in_link)] +pub struct MultipleKindsInLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_name_form)] +pub struct LinkNameForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_kind_form)] +pub struct LinkKindForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_modifiers_form)] +pub struct LinkModifiersForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_cfg_form)] +pub struct LinkCfgForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::wasm_import_form)] +pub struct WasmImportForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::empty_link_name, code = "E0454")] +pub struct EmptyLinkName { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_framework_apple, code = "E0455")] +pub struct LinkFrameworkApple { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::framework_only_windows, code = "E0455")] +pub struct FrameworkOnlyWindows { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_link_kind, code = "E0458")] +pub struct UnknownLinkKind<'a> { + #[primary_span] + #[label] + pub span: Span, + pub kind: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_link_modifiers)] +pub struct MultipleLinkModifiers { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_cfgs)] +pub struct MultipleCfgs { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_cfg_single_predicate)] +pub struct LinkCfgSinglePredicate { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_wasm_import)] +pub struct MultipleWasmImport { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unexpected_link_arg)] +pub struct UnexpectedLinkArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::invalid_link_modifier)] +pub struct InvalidLinkModifier { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_modifiers)] +pub struct MultipleModifiers<'a> { + #[primary_span] + pub span: Span, + pub modifier: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::bundle_needs_static)] +pub struct BundleNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::whole_archive_needs_static)] +pub struct WholeArchiveNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::as_needed_compatibility)] +pub struct AsNeededCompatibility { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_link_modifier)] +pub struct UnknownLinkModifier<'a> { + #[primary_span] + pub span: Span, + pub modifier: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_wasm_link)] +pub struct IncompatibleWasmLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_requires_name, code = "E0459")] +pub struct LinkRequiresName { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::raw_dylib_no_nul)] +pub struct RawDylibNoNul { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_ordinal_raw_dylib)] +pub struct LinkOrdinalRawDylib { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_framework_apple)] +pub struct LibFrameworkApple; + +#[derive(SessionDiagnostic)] +#[diag(metadata::empty_renaming_target)] +pub struct EmptyRenamingTarget<'a> { + pub lib_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::renaming_no_link)] +pub struct RenamingNoLink<'a> { + pub lib_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_renamings)] +pub struct MultipleRenamings<'a> { + pub lib_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_link_mod_override)] +pub struct NoLinkModOverride { + #[primary_span] + pub span: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unsupported_abi_i686)] +pub struct UnsupportedAbiI686 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unsupported_abi)] +pub struct UnsupportedAbi { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_create_file_encoder)] +pub struct FailCreateFileEncoder { + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_seek_file)] +pub struct FailSeekFile { + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_write_file)] +pub struct FailWriteFile { + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_not_panic_runtime)] +pub struct CrateNotPanicRuntime { + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_panic_strategy)] +pub struct NoPanicStrategy { + pub crate_name: Symbol, + pub strategy: PanicStrategy, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::profiler_builtins_needs_core)] +pub struct ProfilerBuiltinsNeedsCore; + +#[derive(SessionDiagnostic)] +#[diag(metadata::not_profiler_runtime)] +pub struct NotProfilerRuntime { + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_multiple_global_alloc)] +pub struct NoMultipleGlobalAlloc { + #[primary_span] + #[label] + pub span2: Span, + #[label(metadata::prev_global_alloc)] + pub span1: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::conflicting_global_alloc)] +pub struct ConflictingGlobalAlloc { + pub crate_name: Symbol, + pub other_crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::global_alloc_required)] +pub struct GlobalAllocRequired; + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_transitive_needs_dep)] +pub struct NoTransitiveNeedsDep<'a> { + pub crate_name: Symbol, + pub needs_crate_name: &'a str, + pub deps_crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_write_error)] +pub struct FailedWriteError { + pub filename: PathBuf, + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::missing_native_library)] +pub struct MissingNativeLibrary<'a> { + pub libname: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_tempdir)] +pub struct FailedCreateTempdir { + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_file)] +pub struct FailedCreateFile<'a> { + pub filename: &'a Path, + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_encoded_metadata)] +pub struct FailedCreateEncodedMetadata { + pub err: Error, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::non_ascii_name)] +pub struct NonAsciiName { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::extern_location_not_exist)] +pub struct ExternLocationNotExist<'a> { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub location: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::extern_location_not_file)] +pub struct ExternLocationNotFile<'a> { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub location: &'a Path, +} + +pub(crate) struct MultipleCandidates { + pub span: Span, + pub flavor: CrateFlavor, + pub crate_name: Symbol, + pub candidates: Vec, +} + +impl SessionDiagnostic<'_> for MultipleCandidates { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("flavor", self.flavor); + diag.code(error_code!(E0465)); + diag.set_span(self.span); + for (i, candidate) in self.candidates.iter().enumerate() { + diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display())); + } + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_matching_crates, code = "E0464")] +#[note] +pub struct MultipleMatchingCrates { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub candidates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::symbol_conflicts_current, code = "E0519")] +pub struct SymbolConflictsCurrent { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::symbol_conflicts_others, code = "E0523")] +pub struct SymbolConflictsOthers { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::stable_crate_id_collision)] +pub struct StableCrateIdCollision { + #[primary_span] + pub span: Span, + pub crate_name0: Symbol, + pub crate_name1: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::dl_error)] +pub struct DlError { + #[primary_span] + pub span: Span, + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::newer_crate_version, code = "E0460")] +#[note] +#[note(metadata::found_crate_versions)] +pub struct NewerCrateVersion { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_crate_with_triple, code = "E0461")] +#[note(metadata::found_crate_versions)] +pub struct NoCrateWithTriple<'a> { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub locator_triple: &'a str, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::found_staticlib, code = "E0462")] +#[note(metadata::found_crate_versions)] +#[help] +pub struct FoundStaticlib { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_rustc, code = "E0514")] +#[note(metadata::found_crate_versions)] +#[help] +pub struct IncompatibleRustc { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, + pub add_info: String, + pub found_crates: String, + pub rustc_version: String, +} + +pub struct InvalidMetadataFiles { + pub span: Span, + pub crate_name: Symbol, + pub add_info: String, + pub crate_rejections: Vec, +} + +impl SessionDiagnostic<'_> for InvalidMetadataFiles { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("add_info", self.add_info); + diag.code(error_code!(E0786)); + diag.set_span(self.span); + for crate_rejection in self.crate_rejections { + diag.note(crate_rejection); + } + diag + } +} + +pub struct CannotFindCrate { + pub span: Span, + pub crate_name: Symbol, + pub add_info: String, + pub missing_core: bool, + pub current_crate: String, + pub is_nightly_build: bool, + pub profiler_runtime: Symbol, + pub locator_triple: TargetTriple, +} + +impl SessionDiagnostic<'_> for CannotFindCrate { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("current_crate", self.current_crate); + diag.set_arg("add_info", self.add_info); + diag.set_arg("locator_triple", self.locator_triple.triple()); + diag.code(error_code!(E0463)); + diag.set_span(self.span); + if (self.crate_name == sym::std || self.crate_name == sym::core) + && self.locator_triple != TargetTriple::from_triple(config::host_triple()) + { + if self.missing_core { + diag.note(rustc_errors::fluent::metadata::target_not_installed); + } else { + diag.note(rustc_errors::fluent::metadata::target_no_std_support); + } + // NOTE: this suggests using rustup, even though the user may not have it installed. + // That's because they could choose to install it; or this may give them a hint which + // target they need to install from their distro. + if self.missing_core { + diag.help(rustc_errors::fluent::metadata::consider_downloading_target); + } + // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. + // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. + // If it's not a dummy, that means someone added `extern crate std` explicitly and + // `#![no_std]` won't help. + if !self.missing_core && self.span.is_dummy() { + diag.note(rustc_errors::fluent::metadata::std_required); + } + if self.is_nightly_build { + diag.help(rustc_errors::fluent::metadata::consider_building_std); + } + } else if self.crate_name == self.profiler_runtime { + diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler); + } else if self.crate_name.as_str().starts_with("rustc_") { + diag.help(rustc_errors::fluent::metadata::install_missing_components); + } + diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_dylib_plugin, code = "E0457")] +pub struct NoDylibPlugin { + #[primary_span] + pub span: Span, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_location_unknown_type)] +pub struct CrateLocationUnknownType<'a> { + #[primary_span] + pub span: Span, + pub path: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_filename_form)] +pub struct LibFilenameForm<'a> { + #[primary_span] + pub span: Span, + pub dll_prefix: &'a str, + pub dll_suffix: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_import_name_type)] +pub struct MultipleImportNameType { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_form)] +pub struct ImportNameTypeForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_x86)] +pub struct ImportNameTypeX86 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_import_name_type)] +pub struct UnknownImportNameType<'a> { + #[primary_span] + pub span: Span, + pub import_name_type: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_raw)] +pub struct ImportNameTypeRaw { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index e6072901a..f360a5864 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -1,3 +1,6 @@ +use crate::errors::{ + FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError, +}; use crate::{encode_metadata, EncodedMetadata}; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -23,8 +26,8 @@ pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); let result = fs::write(&out_filename, metadata); - if let Err(e) = result { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + if let Err(err) = result { + sess.emit_fatal(FailedWriteError { filename: out_filename, err }); } out_filename @@ -65,7 +68,7 @@ pub fn encode_and_write_metadata( let metadata_tmpdir = TempFileBuilder::new() .prefix("rmeta") .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err })); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME); @@ -73,12 +76,8 @@ pub fn encode_and_write_metadata( // This simplifies the creation of the output `out_filename` when requested. match metadata_kind { MetadataKind::None => { - std::fs::File::create(&metadata_filename).unwrap_or_else(|e| { - tcx.sess.fatal(&format!( - "failed to create the file {}: {}", - metadata_filename.display(), - e - )) + std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { + tcx.sess.emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); }); } MetadataKind::Uncompressed | MetadataKind::Compressed => { @@ -93,8 +92,8 @@ pub fn encode_and_write_metadata( // this file always exists. let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); let (metadata_filename, metadata_tmpdir) = if need_metadata_file { - if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) { - tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) { + tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err }); } if tcx.sess.opts.json_artifact_notifications { tcx.sess @@ -109,8 +108,8 @@ pub fn encode_and_write_metadata( // Load metadata back to memory: codegen may need to include it in object files. let metadata = - EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| { - tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e)) + EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| { + tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err }); }); let need_metadata_module = metadata_kind == MetadataKind::Compressed; diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 6440f3e39..6f5604b7e 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -2,10 +2,10 @@ #![feature(decl_macro)] #![feature(drain_filter)] #![feature(generators)] -#![feature(generic_associated_types)] +#![cfg_attr(bootstrap, feature(generic_associated_types))] #![feature(iter_from_generator)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(once_cell)] #![feature(proc_macro_internals)] #![feature(macro_metavar_expr)] @@ -16,6 +16,8 @@ #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] extern crate proc_macro; @@ -26,6 +28,9 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_data_structures; +#[macro_use] +extern crate tracing; + pub use rmeta::{provide, provide_extern}; mod dependency_format; @@ -34,8 +39,10 @@ mod native_libs; mod rmeta; pub mod creader; +pub mod errors; pub mod fs; pub mod locator; pub use fs::{emit_metadata, METADATA_FILENAME}; +pub use native_libs::find_native_static_library; pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2c1c84b0b..35f9ef92a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -213,6 +213,13 @@ //! metadata::locator or metadata::creader for all the juicy details! use crate::creader::Library; +use crate::errors::{ + CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist, + ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles, + LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion, + NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent, + SymbolConflictsOthers, +}; use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -220,23 +227,23 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; -use rustc_errors::{struct_span_err, FatalError}; +use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; use snap::read::FrameDecoder; +use std::borrow::Cow; use std::fmt::Write as _; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; use std::{cmp, fmt, fs}; -use tracing::{debug, info}; #[derive(Clone)] pub(crate) struct CrateLocator<'a> { @@ -288,6 +295,16 @@ impl fmt::Display for CrateFlavor { } } +impl IntoDiagnosticArg for CrateFlavor { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + CrateFlavor::Rlib => DiagnosticArgValue::Str(Cow::Borrowed("rlib")), + CrateFlavor::Rmeta => DiagnosticArgValue::Str(Cow::Borrowed("rmeta")), + CrateFlavor::Dylib => DiagnosticArgValue::Str(Cow::Borrowed("dylib")), + } + } +} + impl<'a> CrateLocator<'a> { pub(crate) fn new( sess: &'a Session, @@ -938,41 +955,20 @@ impl fmt::Display for MetadataError<'_> { impl CrateError { pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) { - let mut diag = match self { - CrateError::NonAsciiName(crate_name) => sess.struct_span_err( - span, - &format!("cannot load a crate with a non-ascii name `{}`", crate_name), - ), - CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err( - span, - &format!("extern location for {} does not exist: {}", crate_name, loc.display()), - ), - CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err( - span, - &format!("extern location for {} is not a file: {}", crate_name, loc.display()), - ), + match self { + CrateError::NonAsciiName(crate_name) => { + sess.emit_err(NonAsciiName { span, crate_name }); + } + CrateError::ExternLocationNotExist(crate_name, loc) => { + sess.emit_err(ExternLocationNotExist { span, crate_name, location: &loc }); + } + CrateError::ExternLocationNotFile(crate_name, loc) => { + sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc }); + } CrateError::MultipleCandidates(crate_name, flavor, candidates) => { - let mut err = struct_span_err!( - sess, - span, - E0465, - "multiple {} candidates for `{}` found", - flavor, - crate_name, - ); - for (i, candidate) in candidates.iter().enumerate() { - err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display())); - } - err + sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates }); } CrateError::MultipleMatchingCrates(crate_name, libraries) => { - let mut err = struct_span_err!( - sess, - span, - E0464, - "multiple matching crates for `{}`", - crate_name - ); let mut libraries: Vec<_> = libraries.into_values().collect(); // Make ordering of candidates deterministic. // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`. @@ -1000,223 +996,142 @@ impl CrateError { s }) .collect::(); - err.note(&format!("candidates:{}", candidates)); - err + sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates }); + } + CrateError::SymbolConflictsCurrent(root_name) => { + sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name }); + } + CrateError::SymbolConflictsOthers(root_name) => { + sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name }); } - CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!( - sess, - span, - E0519, - "the current crate is indistinguishable from one of its dependencies: it has the \ - same crate-name `{}` and was compiled with the same `-C metadata` arguments. \ - This will result in symbol conflicts between the two.", - root_name, - ), - CrateError::SymbolConflictsOthers(root_name) => struct_span_err!( - sess, - span, - E0523, - "found two different crates with name `{}` that are not distinguished by differing \ - `-C metadata`. This will result in symbol conflicts between the two.", - root_name, - ), CrateError::StableCrateIdCollision(crate_name0, crate_name1) => { - let msg = format!( - "found crates (`{}` and `{}`) with colliding StableCrateId values.", - crate_name0, crate_name1 - ); - sess.struct_span_err(span, &msg) + sess.emit_err(StableCrateIdCollision { + span, + crate_name0: crate_name0, + crate_name1: crate_name1, + }); + } + CrateError::DlOpen(s) | CrateError::DlSym(s) => { + sess.emit_err(DlError { span, err: s }); } - CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s), CrateError::LocatorCombined(locator) => { let crate_name = locator.crate_name; - let add = match &locator.root { + let add_info = match &locator.root { None => String::new(), Some(r) => format!(" which `{}` depends on", r.name), }; - let mut msg = "the following crate versions were found:".to_string(); - let mut err = if !locator.crate_rejections.via_hash.is_empty() { - let mut err = struct_span_err!( - sess, - span, - E0460, - "found possibly newer version of crate `{}`{}", - crate_name, - add, - ); - err.note("perhaps that crate needs to be recompiled?"); + // FIXME: There are no tests for CrateLocationUnknownType or LibFilenameForm + if !locator.crate_rejections.via_filename.is_empty() { + let mismatches = locator.crate_rejections.via_filename.iter(); + for CrateMismatch { path, .. } in mismatches { + sess.emit_err(CrateLocationUnknownType { span, path: &path }); + sess.emit_err(LibFilenameForm { + span, + dll_prefix: &locator.dll_prefix, + dll_suffix: &locator.dll_suffix, + }); + } + } + let mut found_crates = String::new(); + if !locator.crate_rejections.via_hash.is_empty() { let mismatches = locator.crate_rejections.via_hash.iter(); for CrateMismatch { path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + crate_name, + path.display() + )); } if let Some(r) = locator.root { for path in r.source.paths() { - msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + r.name, + path.display() + )); } } - err.note(&msg); - err - } else if !locator.crate_rejections.via_triple.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(NewerCrateVersion { span, - E0461, - "couldn't find crate `{}` with expected target triple {}{}", - crate_name, - locator.triple, - add, - ); + crate_name: crate_name, + add_info, + found_crates, + }); + } else if !locator.crate_rejections.via_triple.is_empty() { let mismatches = locator.crate_rejections.via_triple.iter(); for CrateMismatch { path, got } in mismatches { - msg.push_str(&format!( + found_crates.push_str(&format!( "\ncrate `{}`, target triple {}: {}", crate_name, got, path.display(), )); } - err.note(&msg); - err - } else if !locator.crate_rejections.via_kind.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(NoCrateWithTriple { span, - E0462, - "found staticlib `{}` instead of rlib or dylib{}", - crate_name, - add, - ); - err.help("please recompile that crate using --crate-type lib"); + crate_name: crate_name, + locator_triple: locator.triple.triple(), + add_info, + found_crates, + }); + } else if !locator.crate_rejections.via_kind.is_empty() { let mismatches = locator.crate_rejections.via_kind.iter(); for CrateMismatch { path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + crate_name, + path.display() + )); } - err.note(&msg); - err + sess.emit_err(FoundStaticlib { span, crate_name, add_info, found_crates }); } else if !locator.crate_rejections.via_version.is_empty() { - let mut err = struct_span_err!( - sess, - span, - E0514, - "found crate `{}` compiled by an incompatible version of rustc{}", - crate_name, - add, - ); - err.help(&format!( - "please recompile that crate using this compiler ({}) \ - (consider running `cargo clean` first)", - rustc_version(), - )); let mismatches = locator.crate_rejections.via_version.iter(); for CrateMismatch { path, got } in mismatches { - msg.push_str(&format!( + found_crates.push_str(&format!( "\ncrate `{}` compiled by {}: {}", crate_name, got, path.display(), )); } - err.note(&msg); - err - } else if !locator.crate_rejections.via_invalid.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(IncompatibleRustc { span, - E0786, - "found invalid metadata files for crate `{}`{}", crate_name, - add, - ); + add_info, + found_crates, + rustc_version: rustc_version(), + }); + } else if !locator.crate_rejections.via_invalid.is_empty() { + let mut crate_rejections = Vec::new(); for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid { - err.note(&got); + crate_rejections.push(got); } - err + sess.emit_err(InvalidMetadataFiles { + span, + crate_name, + add_info, + crate_rejections, + }); } else { - let mut err = struct_span_err!( - sess, + sess.emit_err(CannotFindCrate { span, - E0463, - "can't find crate for `{}`{}", crate_name, - add, - ); - - if (crate_name == sym::std || crate_name == sym::core) - && locator.triple != TargetTriple::from_triple(config::host_triple()) - { - if missing_core { - err.note(&format!( - "the `{}` target may not be installed", - locator.triple - )); - } else { - err.note(&format!( - "the `{}` target may not support the standard library", - locator.triple - )); - } - // NOTE: this suggests using rustup, even though the user may not have it installed. - // That's because they could choose to install it; or this may give them a hint which - // target they need to install from their distro. - if missing_core { - err.help(&format!( - "consider downloading the target with `rustup target add {}`", - locator.triple - )); - } - // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. - // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. - // If it's not a dummy, that means someone added `extern crate std` explicitly and `#![no_std]` won't help. - if !missing_core && span.is_dummy() { - let current_crate = - sess.opts.crate_name.as_deref().unwrap_or(""); - err.note(&format!( - "`std` is required by `{}` because it does not declare `#![no_std]`", - current_crate - )); - } - if sess.is_nightly_build() { - err.help("consider building the standard library from source with `cargo build -Zbuild-std`"); - } - } else if crate_name - == Symbol::intern(&sess.opts.unstable_opts.profiler_runtime) - { - err.note("the compiler may have been built without the profiler runtime"); - } else if crate_name.as_str().starts_with("rustc_") { - err.help( - "maybe you need to install the missing components with: \ - `rustup component add rust-src rustc-dev llvm-tools-preview`", - ); - } - err.span_label(span, "can't find crate"); - err - }; - - if !locator.crate_rejections.via_filename.is_empty() { - let mismatches = locator.crate_rejections.via_filename.iter(); - for CrateMismatch { path, .. } in mismatches { - err.note(&format!( - "extern location for {} is of an unknown type: {}", - crate_name, - path.display(), - )) - .help(&format!( - "file name should be lib*.rlib or {}*.{}", - locator.dll_prefix, locator.dll_suffix - )); - } + add_info, + missing_core, + current_crate: sess + .opts + .crate_name + .clone() + .unwrap_or("".to_string()), + is_nightly_build: sess.is_nightly_build(), + profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), + locator_triple: locator.triple, + }); } - err } - CrateError::NonDylibPlugin(crate_name) => struct_span_err!( - sess, - span, - E0457, - "plugin `{}` only found in rlib format, but must be available in dylib format", - crate_name, - ), - }; - - diag.emit(); + CrateError::NonDylibPlugin(crate_name) => { + sess.emit_err(NoDylibPlugin { span, crate_name }); + } + } } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 9f6079ecb..257741c13 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,17 +1,83 @@ use rustc_ast::{NestedMetaItem, CRATE_NODE_ID}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; -use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib}; +use rustc_session::config::CrateType; +use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType}; use rustc_session::parse::feature_err; +use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::abi::Abi; +use crate::errors::{ + AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget, + FrameworkOnlyWindows, ImportNameTypeForm, ImportNameTypeRaw, ImportNameTypeX86, + IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, LinkCfgForm, + LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, LinkNameForm, + LinkOrdinalRawDylib, LinkRequiresName, MissingNativeLibrary, MultipleCfgs, + MultipleImportNameType, MultipleKindsInLink, MultipleLinkModifiers, MultipleModifiers, + MultipleNamesInLink, MultipleRenamings, MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, + RenamingNoLink, UnexpectedLinkArg, UnknownImportNameType, UnknownLinkKind, UnknownLinkModifier, + UnsupportedAbi, UnsupportedAbiI686, WasmImportForm, WholeArchiveNeedsStatic, +}; + +use std::path::PathBuf; + +pub fn find_native_static_library( + name: &str, + verbatim: Option, + search_paths: &[PathBuf], + sess: &Session, +) -> PathBuf { + let verbatim = verbatim.unwrap_or(false); + // On Windows, static libraries sometimes show up as libfoo.a and other + // times show up as foo.lib + let oslibname = if verbatim { + name.to_string() + } else { + format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix) + }; + let unixlibname = format!("lib{}.a", name); + + for path in search_paths { + let test = path.join(&oslibname); + if test.exists() { + return test; + } + if oslibname != unixlibname { + let test = path.join(&unixlibname); + if test.exists() { + return test; + } + } + } + sess.emit_fatal(MissingNativeLibrary { libname: name }); +} + +fn find_bundled_library( + name: Option, + verbatim: Option, + kind: NativeLibKind, + sess: &Session, +) -> Option { + if sess.opts.unstable_opts.packed_bundled_libs && + sess.crate_types().iter().any(|ct| ct == &CrateType::Rlib || ct == &CrateType::Staticlib) && + let NativeLibKind::Static { bundle: Some(true) | None, .. } = kind { + find_native_static_library( + name.unwrap().as_str(), + verbatim, + &sess.target_filesearch(PathKind::Native).search_path_dirs(), + sess, + ).file_name().and_then(|s| s.to_str()).map(Symbol::intern) + } else { + None + } +} + pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; for id in tcx.hir().items() { @@ -61,36 +127,31 @@ impl<'tcx> Collector<'tcx> { let mut modifiers = None; let mut cfg = None; let mut wasm_import_module = None; + let mut import_name_type = None; for item in items.iter() { match item.name_or_empty() { sym::name => { if name.is_some() { - let msg = "multiple `name` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleNamesInLink { span: item.span() }); continue; } let Some(link_name) = item.value_str() else { - let msg = "link name must be of the form `name = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkNameForm { span: item.span() }); continue; }; let span = item.name_value_literal_span().unwrap(); if link_name.is_empty() { - struct_span_err!(sess, span, E0454, "link name must not be empty") - .span_label(span, "empty link name") - .emit(); + sess.emit_err(EmptyLinkName { span }); } name = Some((link_name, span)); } sym::kind => { if kind.is_some() { - let msg = "multiple `kind` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleKindsInLink { span: item.span() }); continue; } let Some(link_kind) = item.value_str() else { - let msg = "link kind must be of the form `kind = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkKindForm { span: item.span() }); continue; }; @@ -100,44 +161,26 @@ impl<'tcx> Collector<'tcx> { "dylib" => NativeLibKind::Dylib { as_needed: None }, "framework" => { if !sess.target.is_like_osx { - struct_span_err!( - sess, - span, - E0455, - "link kind `framework` is only supported on Apple targets" - ) - .emit(); + sess.emit_err(LinkFrameworkApple { span }); } NativeLibKind::Framework { as_needed: None } } "raw-dylib" => { if !sess.target.is_like_windows { - struct_span_err!( - sess, - span, - E0455, - "link kind `raw-dylib` is only supported on Windows targets" - ) - .emit(); - } else if !features.raw_dylib { + sess.emit_err(FrameworkOnlyWindows { span }); + } else if !features.raw_dylib && sess.target.arch == "x86" { feature_err( &sess.parse_sess, sym::raw_dylib, span, - "link kind `raw-dylib` is unstable", + "link kind `raw-dylib` is unstable on x86", ) .emit(); } NativeLibKind::RawDylib } kind => { - let msg = format!( - "unknown link kind `{kind}`, expected one of: \ - static, dylib, framework, raw-dylib" - ); - struct_span_err!(sess, span, E0458, "{}", msg) - .span_label(span, "unknown link kind") - .emit(); + sess.emit_err(UnknownLinkKind { span, kind }); continue; } }; @@ -145,32 +188,26 @@ impl<'tcx> Collector<'tcx> { } sym::modifiers => { if modifiers.is_some() { - let msg = - "multiple `modifiers` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleLinkModifiers { span: item.span() }); continue; } let Some(link_modifiers) = item.value_str() else { - let msg = "link modifiers must be of the form `modifiers = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkModifiersForm { span: item.span() }); continue; }; modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); } sym::cfg => { if cfg.is_some() { - let msg = "multiple `cfg` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleCfgs { span: item.span() }); continue; } let Some(link_cfg) = item.meta_item_list() else { - let msg = "link cfg must be of the form `cfg(/* predicate */)`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkCfgForm { span: item.span() }); continue; }; let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { - let msg = "link cfg must have a single predicate argument"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkCfgSinglePredicate { span: item.span() }); continue; }; if !features.link_cfg { @@ -186,23 +223,55 @@ impl<'tcx> Collector<'tcx> { } sym::wasm_import_module => { if wasm_import_module.is_some() { - let msg = "multiple `wasm_import_module` arguments \ - in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleWasmImport { span: item.span() }); continue; } let Some(link_wasm_import_module) = item.value_str() else { - let msg = "wasm import module must be of the form \ - `wasm_import_module = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(WasmImportForm { span: item.span() }); continue; }; wasm_import_module = Some((link_wasm_import_module, item.span())); } + sym::import_name_type => { + if import_name_type.is_some() { + sess.emit_err(MultipleImportNameType { span: item.span() }); + continue; + } + let Some(link_import_name_type) = item.value_str() else { + sess.emit_err(ImportNameTypeForm { span: item.span() }); + continue; + }; + if self.tcx.sess.target.arch != "x86" { + sess.emit_err(ImportNameTypeX86 { span: item.span() }); + continue; + } + + let link_import_name_type = match link_import_name_type.as_str() { + "decorated" => PeImportNameType::Decorated, + "noprefix" => PeImportNameType::NoPrefix, + "undecorated" => PeImportNameType::Undecorated, + import_name_type => { + sess.emit_err(UnknownImportNameType { + span: item.span(), + import_name_type, + }); + continue; + } + }; + if !features.raw_dylib { + let span = item.name_value_literal_span().unwrap(); + feature_err( + &sess.parse_sess, + sym::raw_dylib, + span, + "import name type is unstable", + ) + .emit(); + } + import_name_type = Some((link_import_name_type, item.span())); + } _ => { - let msg = "unexpected `#[link]` argument, expected one of: \ - name, kind, modifiers, cfg, wasm_import_module"; - sess.span_err(item.span(), msg); + sess.emit_err(UnexpectedLinkArg { span: item.span() }); } } } @@ -214,11 +283,7 @@ impl<'tcx> Collector<'tcx> { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { Some(m) => (m, modifier.starts_with('+')), None => { - sess.span_err( - span, - "invalid linking modifier syntax, expected '+' or '-' prefix \ - before one of: bundle, verbatim, whole-archive, as-needed", - ); + sess.emit_err(InvalidLinkModifier { span }); continue; } }; @@ -236,10 +301,7 @@ impl<'tcx> Collector<'tcx> { } let assign_modifier = |dst: &mut Option| { if dst.is_some() { - let msg = format!( - "multiple `{modifier}` modifiers in a single `modifiers` argument" - ); - sess.span_err(span, &msg); + sess.emit_err(MultipleModifiers { span, modifier }); } else { *dst = Some(value); } @@ -249,11 +311,7 @@ impl<'tcx> Collector<'tcx> { assign_modifier(bundle) } ("bundle", _) => { - sess.span_err( - span, - "linking modifier `bundle` is only compatible with \ - `static` linking kind", - ); + sess.emit_err(BundleNeedsStatic { span }); } ("verbatim", _) => { @@ -265,11 +323,7 @@ impl<'tcx> Collector<'tcx> { assign_modifier(whole_archive) } ("whole-archive", _) => { - sess.span_err( - span, - "linking modifier `whole-archive` is only compatible with \ - `static` linking kind", - ); + sess.emit_err(WholeArchiveNeedsStatic { span }); } ("as-needed", Some(NativeLibKind::Dylib { as_needed })) @@ -278,21 +332,11 @@ impl<'tcx> Collector<'tcx> { assign_modifier(as_needed) } ("as-needed", _) => { - sess.span_err( - span, - "linking modifier `as-needed` is only compatible with \ - `dylib` and `framework` linking kinds", - ); + sess.emit_err(AsNeededCompatibility { span }); } _ => { - sess.span_err( - span, - format!( - "unknown linking modifier `{modifier}`, expected one of: \ - bundle, verbatim, whole-archive, as-needed" - ), - ); + sess.emit_err(UnknownLinkModifier { span, modifier }); } } } @@ -300,39 +344,66 @@ impl<'tcx> Collector<'tcx> { if let Some((_, span)) = wasm_import_module { if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { - let msg = "`wasm_import_module` is incompatible with \ - other arguments in `#[link]` attributes"; - sess.span_err(span, msg); + sess.emit_err(IncompatibleWasmLink { span }); } } else if name.is_none() { - struct_span_err!( - sess, - m.span, - E0459, - "`#[link]` attribute requires a `name = \"string\"` argument" - ) - .span_label(m.span, "missing `name` argument") - .emit(); + sess.emit_err(LinkRequiresName { span: m.span }); + } + + // Do this outside of the loop so that `import_name_type` can be specified before `kind`. + if let Some((_, span)) = import_name_type { + if kind != Some(NativeLibKind::RawDylib) { + sess.emit_err(ImportNameTypeRaw { span }); + } } let dll_imports = match kind { Some(NativeLibKind::RawDylib) => { if let Some((name, span)) = name && name.as_str().contains('\0') { - sess.span_err( - span, - "link name must not contain NUL characters if link kind is `raw-dylib`", - ); + sess.emit_err(RawDylibNoNul { span }); } foreign_mod_items .iter() - .map(|child_item| self.build_dll_import(abi, child_item)) + .map(|child_item| { + self.build_dll_import( + abi, + import_name_type.map(|(import_name_type, _)| import_name_type), + child_item, + ) + }) .collect() } - _ => Vec::new(), + _ => { + for child_item in foreign_mod_items { + if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs() + && self + .tcx + .codegen_fn_attrs(child_item.id.def_id) + .link_ordinal + .is_some() + { + let link_ordinal_attr = self + .tcx + .hir() + .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id)) + .iter() + .find(|a| a.has_name(sym::link_ordinal)) + .unwrap(); + sess.emit_err(LinkOrdinalRawDylib { span: link_ordinal_attr.span }); + } + } + + Vec::new() + } }; + + let name = name.map(|(name, _)| name); + let kind = kind.unwrap_or(NativeLibKind::Unspecified); + let filename = find_bundled_library(name, verbatim, kind, sess); self.libs.push(NativeLib { - name: name.map(|(name, _)| name), - kind: kind.unwrap_or(NativeLibKind::Unspecified), + name, + filename, + kind, cfg, foreign_module: Some(it.def_id.to_def_id()), wasm_import_module: wasm_import_module.map(|(name, _)| name), @@ -349,7 +420,7 @@ impl<'tcx> Collector<'tcx> { for lib in &self.tcx.sess.opts.libs { if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx { // Cannot check this when parsing options because the target is not yet available. - self.tcx.sess.err("library kind `framework` is only supported on Apple targets"); + self.tcx.sess.emit_err(LibFrameworkApple); } if let Some(ref new_name) = lib.new_name { let any_duplicate = self @@ -358,23 +429,11 @@ impl<'tcx> Collector<'tcx> { .filter_map(|lib| lib.name.as_ref()) .any(|n| n.as_str() == lib.name); if new_name.is_empty() { - self.tcx.sess.err(format!( - "an empty renaming target was specified for library `{}`", - lib.name - )); + self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: &lib.name }); } else if !any_duplicate { - self.tcx.sess.err(format!( - "renaming of the library `{}` was specified, \ - however this crate contains no `#[link(...)]` \ - attributes referencing this library", - lib.name - )); + self.tcx.sess.emit_err(RenamingNoLink { lib_name: &lib.name }); } else if !renames.insert(&lib.name) { - self.tcx.sess.err(format!( - "multiple renamings were \ - specified for library `{}`", - lib.name - )); + self.tcx.sess.emit_err(MultipleRenamings { lib_name: &lib.name }); } } } @@ -399,10 +458,13 @@ impl<'tcx> Collector<'tcx> { // involved or not, library reordering and kind overriding without // explicit `:rename` in particular. if lib.has_modifiers() || passed_lib.has_modifiers() { - let msg = "overriding linking modifiers from command line is not supported"; match lib.foreign_module { - Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg), - None => self.tcx.sess.err(msg), + Some(def_id) => self.tcx.sess.emit_err(NoLinkModOverride { + span: Some(self.tcx.def_span(def_id)), + }), + None => { + self.tcx.sess.emit_err(NoLinkModOverride { span: None }) + } }; } if passed_lib.kind != NativeLibKind::Unspecified { @@ -421,8 +483,13 @@ impl<'tcx> Collector<'tcx> { if existing.is_empty() { // Add if not found let new_name: Option<&str> = passed_lib.new_name.as_deref(); + let name = Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))); + let sess = self.tcx.sess; + let filename = + find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, sess); self.libs.push(NativeLib { - name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))), + name, + filename, kind: passed_lib.kind, cfg: None, foreign_module: None, @@ -462,7 +529,12 @@ impl<'tcx> Collector<'tcx> { .sum() } - fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport { + fn build_dll_import( + &self, + abi: Abi, + import_name_type: Option, + item: &hir::ForeignItemRef, + ) -> DllImport { let calling_convention = if self.tcx.sess.target.arch == "x86" { match abi { Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C, @@ -476,29 +548,29 @@ impl<'tcx> Collector<'tcx> { DllCallingConvention::Vectorcall(self.i686_arg_list_size(item)) } _ => { - self.tcx.sess.span_fatal( - item.span, - r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#, - ); + self.tcx.sess.emit_fatal(UnsupportedAbiI686 { span: item.span }); } } } else { match abi { Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C, _ => { - self.tcx.sess.span_fatal( - item.span, - r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#, - ); + self.tcx.sess.emit_fatal(UnsupportedAbi { span: item.span }); } } }; + let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id); + let import_name_type = codegen_fn_attrs + .link_ordinal + .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord))); + DllImport { - name: item.ident.name, - ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal, + name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name), + import_name_type, calling_convention, span: item.span, + is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(), } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 40dc4fb05..830417eea 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -4,7 +4,6 @@ use crate::creader::{CStore, CrateMetadataRef}; use crate::rmeta::*; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -33,7 +32,7 @@ use rustc_session::cstore::{ use rustc_session::Session; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; @@ -42,7 +41,6 @@ use std::iter::TrustedLen; use std::mem; use std::num::NonZeroUsize; use std::path::Path; -use tracing::debug; pub(super) use cstore_impl::provide; pub use cstore_impl::provide_extern; @@ -99,7 +97,7 @@ pub(crate) struct CrateMetadata { /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. - source_map_import_info: OnceCell>, + source_map_import_info: Lock>>, /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`. def_path_hash_map: DefPathHashMapRef<'static>, /// Likewise for ExpnHash. @@ -143,7 +141,8 @@ pub(crate) struct CrateMetadata { } /// Holds information about a rustc_span::SourceFile imported from another crate. -/// See `imported_source_files()` for more information. +/// See `imported_source_file()` for more information. +#[derive(Clone)] struct ImportedSourceFile { /// This SourceFile's byte-offset within the source_map of its original crate original_start_pos: rustc_span::BytePos, @@ -160,9 +159,6 @@ pub(super) struct DecodeContext<'a, 'tcx> { sess: Option<&'tcx Session>, tcx: Option>, - // Cache the last used source_file for translating spans as an optimization. - last_source_file_index: usize, - lazy_state: LazyState, // Used for decoding interpret::AllocIds in a cached & thread-safe manner. @@ -191,7 +187,6 @@ pub(super) trait Metadata<'a, 'tcx>: Copy { blob: self.blob(), sess: self.sess().or(tcx.map(|tcx| tcx.sess)), tcx, - last_source_file_index: 0, lazy_state: LazyState::NoNode, alloc_decoding_session: self .cdata() @@ -455,6 +450,13 @@ impl<'a, 'tcx> Decodable> for ExpnIndex { } } +impl<'a, 'tcx> Decodable> for ast::AttrId { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ast::AttrId { + let sess = d.sess.expect("can't decode AttrId without Session"); + sess.parse_sess.attr_id_generator.mk_attr_id() + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { let cdata = decoder.cdata(); @@ -527,6 +529,9 @@ impl<'a, 'tcx> Decodable> for Span { bug!("Cannot decode Span without Session.") }; + // Index of the file in the corresponding crate's list of encoded files. + let metadata_index = u32::decode(decoder); + // There are two possibilities here: // 1. This is a 'local span', which is located inside a `SourceFile` // that came from this crate. In this case, we use the source map data @@ -553,10 +558,10 @@ impl<'a, 'tcx> Decodable> for Span { // to be based on the *foreign* crate (e.g. crate C), not the crate // we are writing metadata for (e.g. crate B). This allows us to // treat the 'local' and 'foreign' cases almost identically during deserialization: - // we can call `imported_source_files` for the proper crate, and binary search + // we can call `imported_source_file` for the proper crate, and binary search // through the returned slice using our span. - let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL { - decoder.cdata().imported_source_files(sess) + let source_file = if tag == TAG_VALID_SPAN_LOCAL { + decoder.cdata().imported_source_file(metadata_index, sess) } else { // When we encode a proc-macro crate, all `Span`s should be encoded // with `TAG_VALID_SPAN_LOCAL` @@ -577,66 +582,69 @@ impl<'a, 'tcx> Decodable> for Span { cnum ); - // Decoding 'foreign' spans should be rare enough that it's - // not worth it to maintain a per-CrateNum cache for `last_source_file_index`. - // We just set it to 0, to ensure that we don't try to access something out - // of bounds for our initial 'guess' - decoder.last_source_file_index = 0; - let foreign_data = decoder.cdata().cstore.get_crate_data(cnum); - foreign_data.imported_source_files(sess) - }; - - let source_file = { - // Optimize for the case that most spans within a translated item - // originate from the same source_file. - let last_source_file = &imported_source_files[decoder.last_source_file_index]; - - if lo >= last_source_file.original_start_pos && lo <= last_source_file.original_end_pos - { - last_source_file - } else { - let index = imported_source_files - .binary_search_by_key(&lo, |source_file| source_file.original_start_pos) - .unwrap_or_else(|index| index - 1); - - // Don't try to cache the index for foreign spans, - // as this would require a map from CrateNums to indices - if tag == TAG_VALID_SPAN_LOCAL { - decoder.last_source_file_index = index; - } - &imported_source_files[index] - } + foreign_data.imported_source_file(metadata_index, sess) }; - // Make sure our binary search above is correct. + // Make sure our span is well-formed. debug_assert!( - lo >= source_file.original_start_pos && lo <= source_file.original_end_pos, - "Bad binary search: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + lo + source_file.original_start_pos <= source_file.original_end_pos, + "Malformed encoded span: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", lo, source_file.original_start_pos, source_file.original_end_pos ); - // Make sure we correctly filtered out invalid spans during encoding + // Make sure we correctly filtered out invalid spans during encoding. debug_assert!( - hi >= source_file.original_start_pos && hi <= source_file.original_end_pos, - "Bad binary search: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + hi + source_file.original_start_pos <= source_file.original_end_pos, + "Malformed encoded span: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", hi, source_file.original_start_pos, source_file.original_end_pos ); - let lo = - (lo + source_file.translated_source_file.start_pos) - source_file.original_start_pos; - let hi = - (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos; + let lo = lo + source_file.translated_source_file.start_pos; + let hi = hi + source_file.translated_source_file.start_pos; // Do not try to decode parent for foreign spans. Span::new(lo, hi, ctxt, None) } } +impl<'a, 'tcx> Decodable> for Symbol { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { + let tag = d.read_u8(); + + match tag { + SYMBOL_STR => { + let s = d.read_str(); + Symbol::intern(s) + } + SYMBOL_OFFSET => { + // read str offset + let pos = d.read_usize(); + let old_pos = d.opaque.position(); + + // move to str ofset and read + d.opaque.set_position(pos); + let s = d.read_str(); + let sym = Symbol::intern(s); + + // restore position + d.opaque.set_position(old_pos); + + sym + } + SYMBOL_PREINTERNED => { + let symbol_index = d.read_u32(); + Symbol::new_from_decoded(symbol_index) + } + _ => unreachable!(), + } + } +} + impl<'a, 'tcx> Decodable> for &'tcx [ty::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) @@ -783,26 +791,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } - fn maybe_kind(self, item_id: DefIndex) -> Option { - self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) - } - #[inline] pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum { if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] } } - fn kind(self, item_id: DefIndex) -> EntryKind { - self.maybe_kind(item_id).unwrap_or_else(|| { - bug!( - "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", - item_id, - self.root.name, - self.cnum, - ) - }) - } - fn def_kind(self, item_id: DefIndex) -> DefKind { self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| { bug!( @@ -854,21 +847,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { - let data = match kind { - EntryKind::Variant(data) | EntryKind::Struct(data) | EntryKind::Union(data) => { - data.decode(self) - } - _ => bug!(), - }; - + fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { let adt_kind = match kind { - EntryKind::Variant(_) => ty::AdtKind::Enum, - EntryKind::Struct(..) => ty::AdtKind::Struct, - EntryKind::Union(..) => ty::AdtKind::Union, + DefKind::Variant => ty::AdtKind::Enum, + DefKind::Struct => ty::AdtKind::Struct, + DefKind::Union => ty::AdtKind::Union, _ => bug!(), }; + let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self); + let variant_did = if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; let ctor_did = data.ctor.map(|index| self.local_def_id(index)); @@ -899,13 +887,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> { - let kind = self.kind(item_id); + let kind = self.def_kind(item_id); let did = self.local_def_id(item_id); let adt_kind = match kind { - EntryKind::Enum => ty::AdtKind::Enum, - EntryKind::Struct(_) => ty::AdtKind::Struct, - EntryKind::Union(_) => ty::AdtKind::Union, + DefKind::Enum => ty::AdtKind::Enum, + DefKind::Struct => ty::AdtKind::Struct, + DefKind::Union => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); @@ -917,7 +905,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .get(self, item_id) .unwrap_or_else(LazyArray::empty) .decode(self) - .map(|index| self.get_variant(&self.kind(index), index, did)) + .map(|index| self.get_variant(&self.def_kind(index), index, did)) .collect() } else { std::iter::once(self.get_variant(&kind, item_id, did)).collect() @@ -930,8 +918,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess)) } - fn get_visibility(self, id: DefIndex) -> ty::Visibility { - self.root.tables.visibility.get(self, id).unwrap().decode(self) + fn get_visibility(self, id: DefIndex) -> ty::Visibility { + self.root + .tables + .visibility + .get(self, id) + .unwrap() + .decode(self) + .map_id(|index| self.local_def_id(index)) } fn get_trait_item_def_id(self, id: DefIndex) -> Option { @@ -1027,10 +1021,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(child_index); let span = self.get_span(child_index, sess); let macro_rules = match kind { - DefKind::Macro(..) => match self.kind(child_index) { - EntryKind::MacroDef(_, macro_rules) => macro_rules, - _ => unreachable!(), - }, + DefKind::Macro(..) => { + self.root.tables.macro_rules.get(self, child_index).is_some() + } _ => false, }; @@ -1084,14 +1077,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - match self.kind(id) { - EntryKind::Mod(exports) => { - for exp in exports.decode((self, sess)) { - callback(exp); - } + if let Some(exports) = self.root.tables.module_reexports.get(self, id) { + for exp in exports.decode((self, sess)) { + callback(exp); } - EntryKind::Enum | EntryKind::Trait => {} - _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)), } } @@ -1104,19 +1093,21 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { - match self.kind(id) { - EntryKind::Mod(_) | EntryKind::Enum | EntryKind::Trait => { - self.get_expn_that_defined(id, sess) - } + match self.def_kind(id) { + DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess), _ => panic!("Expected module, found {:?}", self.local_def_id(id)), } } - fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { - match self.kind(id) { - EntryKind::AssocFn { has_self, .. } => has_self, - _ => false, - } + fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { + self.root + .tables + .fn_arg_names + .get(self, id) + .unwrap_or_else(LazyArray::empty) + .decode((self, sess)) + .nth(0) + .map_or(false, |ident| ident.name == kw::SelfLower) } fn get_associated_item_def_ids( @@ -1133,15 +1124,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map(move |child_index| self.local_def_id(child_index)) } - fn get_associated_item(self, id: DefIndex) -> ty::AssocItem { + fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { let name = self.item_name(id); - let (kind, container, has_self) = match self.kind(id) { - EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false), - EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self), - EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false), - _ => bug!("cannot get associated-item of `{:?}`", id), + let kind = match self.def_kind(id) { + DefKind::AssocConst => ty::AssocKind::Const, + DefKind::AssocFn => ty::AssocKind::Fn, + DefKind::AssocTy => ty::AssocKind::Type, + _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; + let has_self = self.get_fn_has_self_parameter(id, sess); + let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { name, @@ -1154,9 +1147,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { - match self.kind(node_id) { - EntryKind::Struct(data) | EntryKind::Variant(data) => { - let vdata = data.decode(self); + match self.def_kind(node_id) { + DefKind::Struct | DefKind::Variant => { + let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self); vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind)) } _ => None, @@ -1202,7 +1195,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map(move |index| respan(self.get_span(index, sess), self.item_name(index))) } - fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator + 'a { + fn get_struct_field_visibilities( + self, + id: DefIndex, + ) -> impl Iterator> + 'a { self.root .tables .children @@ -1344,18 +1340,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { - match self.kind(id) { - EntryKind::MacroDef(mac_args, macro_rules) => { - ast::MacroDef { body: P(mac_args.decode((self, sess))), macro_rules } + match self.def_kind(id) { + DefKind::Macro(_) => { + let macro_rules = self.root.tables.macro_rules.get(self, id).is_some(); + let body = + self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); + ast::MacroDef { macro_rules, body: ast::ptr::P(body) } } _ => bug!(), } } fn is_foreign_item(self, id: DefIndex) -> bool { - match self.kind(id) { - EntryKind::ForeignStatic | EntryKind::ForeignFn => true, - _ => false, + if let Some(parent) = self.def_key(id).parent { + matches!(self.def_kind(parent), DefKind::ForeignMod) + } else { + false } } @@ -1453,7 +1453,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] { + fn imported_source_file(self, source_file_index: u32, sess: &Session) -> ImportedSourceFile { fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> { path.filter(|_| { // Only spend time on further checks if we have what to translate *to*. @@ -1541,90 +1541,96 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } }; - self.cdata.source_map_import_info.get_or_init(|| { - let external_source_map = self.root.source_map.decode(self); - - external_source_map - .map(|source_file_to_import| { - // We can't reuse an existing SourceFile, so allocate a new one - // containing the information we need. - let rustc_span::SourceFile { - mut name, - src_hash, - start_pos, - end_pos, - lines, - multibyte_chars, - non_narrow_chars, - normalized_pos, - name_hash, - .. - } = source_file_to_import; - - // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped - // during rust bootstrapping by `remap-debuginfo = true`, and the user - // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, - // then we change `name` to a similar state as if the rust was bootstrapped - // with `remap-debuginfo = true`. - // This is useful for testing so that tests about the effects of - // `try_to_translate_virtual_to_real` don't have to worry about how the - // compiler is bootstrapped. - if let Some(virtual_dir) = - &sess.opts.unstable_opts.simulate_remapped_rust_src_base - { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - if let rustc_span::FileName::Real(ref mut old_name) = name { - if let rustc_span::RealFileName::LocalPath(local) = old_name { - if let Ok(rest) = local.strip_prefix(real_dir) { - *old_name = rustc_span::RealFileName::Remapped { - local_path: None, - virtual_name: virtual_dir.join(rest), - }; - } + let mut import_info = self.cdata.source_map_import_info.lock(); + for _ in import_info.len()..=(source_file_index as usize) { + import_info.push(None); + } + import_info[source_file_index as usize] + .get_or_insert_with(|| { + let source_file_to_import = self + .root + .source_map + .get(self, source_file_index) + .expect("missing source file") + .decode(self); + + // We can't reuse an existing SourceFile, so allocate a new one + // containing the information we need. + let rustc_span::SourceFile { + mut name, + src_hash, + start_pos, + end_pos, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, + name_hash, + .. + } = source_file_to_import; + + // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped + // during rust bootstrapping by `remap-debuginfo = true`, and the user + // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, + // then we change `name` to a similar state as if the rust was bootstrapped + // with `remap-debuginfo = true`. + // This is useful for testing so that tests about the effects of + // `try_to_translate_virtual_to_real` don't have to worry about how the + // compiler is bootstrapped. + if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base + { + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { + if let rustc_span::FileName::Real(ref mut old_name) = name { + if let rustc_span::RealFileName::LocalPath(local) = old_name { + if let Ok(rest) = local.strip_prefix(real_dir) { + *old_name = rustc_span::RealFileName::Remapped { + local_path: None, + virtual_name: virtual_dir.join(rest), + }; } } } } + } - // If this file's path has been remapped to `/rustc/$hash`, - // we might be able to reverse that (also see comments above, - // on `try_to_translate_virtual_to_real`). - try_to_translate_virtual_to_real(&mut name); - - let source_length = (end_pos - start_pos).to_usize(); - - let local_version = sess.source_map().new_imported_source_file( - name, - src_hash, - name_hash, - source_length, - self.cnum, - lines, - multibyte_chars, - non_narrow_chars, - normalized_pos, - start_pos, - end_pos, - ); - debug!( - "CrateMetaData::imported_source_files alloc \ + // If this file's path has been remapped to `/rustc/$hash`, + // we might be able to reverse that (also see comments above, + // on `try_to_translate_virtual_to_real`). + try_to_translate_virtual_to_real(&mut name); + + let source_length = (end_pos - start_pos).to_usize(); + + let local_version = sess.source_map().new_imported_source_file( + name, + src_hash, + name_hash, + source_length, + self.cnum, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, + start_pos, + source_file_index, + ); + debug!( + "CrateMetaData::imported_source_files alloc \ source_file {:?} original (start_pos {:?} end_pos {:?}) \ translated (start_pos {:?} end_pos {:?})", - local_version.name, - start_pos, - end_pos, - local_version.start_pos, - local_version.end_pos - ); + local_version.name, + start_pos, + end_pos, + local_version.start_pos, + local_version.end_pos + ); - ImportedSourceFile { - original_start_pos: start_pos, - original_end_pos: end_pos, - translated_source_file: local_version, - } - }) - .collect() - }) + ImportedSourceFile { + original_start_pos: start_pos, + original_end_pos: end_pos, + translated_source_file: local_version, + } + }) + .clone() } fn get_generator_diagnostic_data( @@ -1687,7 +1693,7 @@ impl CrateMetadata { trait_impls, incoherent_impls: Default::default(), raw_proc_macros, - source_map_import_info: OnceCell::new(), + source_map_import_info: Lock::new(Vec::new()), def_path_hash_map, expn_hash_map: Default::default(), alloc_decoding_state, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 38ce50e83..dede1b212 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -76,9 +76,9 @@ impl ProcessQueryValue<'_, Option> for Option { } macro_rules! provide_one { - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => { provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { + $tcx, $def_id, $other, $cdata, $name => { $cdata .root .tables @@ -89,9 +89,9 @@ macro_rules! provide_one { } } }; - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { + $tcx, $def_id, $other, $cdata, $name => { // We don't decode `table_direct`, since it's not a Lazy, but an actual value $cdata .root @@ -102,11 +102,11 @@ macro_rules! provide_one { } } }; - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { - fn $name<$lt>( - $tcx: TyCtxt<$lt>, - def_id_arg: ty::query::query_keys::$name<$lt>, - ) -> ty::query::query_values::$name<$lt> { + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { + fn $name<'tcx>( + $tcx: TyCtxt<'tcx>, + def_id_arg: ty::query::query_keys::$name<'tcx>, + ) -> ty::query::query_values::$name<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); @@ -130,11 +130,11 @@ macro_rules! provide_one { } macro_rules! provide { - (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $($name:ident => { $($compute:tt)* })*) => { pub fn provide_extern(providers: &mut ExternProviders) { $(provide_one! { - <$lt> $tcx, $def_id, $other, $cdata, $name => { $($compute)* } + $tcx, $def_id, $other, $cdata, $name => { $($compute)* } })* *providers = ExternProviders { @@ -187,7 +187,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) { } } -provide! { <'tcx> tcx, def_id, other, cdata, +provide! { tcx, def_id, other, cdata, explicit_item_bounds => { table } explicit_predicates_of => { table } generics_of => { table } @@ -199,6 +199,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, codegen_fn_attrs => { table } impl_trait_ref => { table } const_param_default => { table } + object_lifetime_default => { table } thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } @@ -207,8 +208,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, def_ident_span => { table } lookup_stability => { table } lookup_const_stability => { table } + lookup_default_body_stability => { table } lookup_deprecation_entry => { table } - visibility => { table } unused_generic_params => { table } opt_def_kind => { table_direct } impl_parent => { table } @@ -223,6 +224,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } + visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; @@ -231,7 +233,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, associated_item_def_ids => { tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess)) } - associated_item => { cdata.get_associated_item(def_id.index) } + associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } @@ -340,7 +342,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); false }, - native_library_kind: |tcx, id| { + native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind), + native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() .filter(|lib| native_libs::relevant_lib(&tcx.sess, lib)) @@ -354,7 +357,6 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .foreign_items .contains(&id) }) - .map(|l| l.kind) }, native_libraries: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); @@ -483,7 +485,7 @@ impl CStore { pub fn struct_field_visibilities_untracked( &self, def: DefId, - ) -> impl Iterator + '_ { + ) -> impl Iterator> + '_ { self.get_crate_data(def.krate).get_struct_field_visibilities(def.index) } @@ -491,7 +493,7 @@ impl CStore { self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index) } - pub fn visibility_untracked(&self, def: DefId) -> Visibility { + pub fn visibility_untracked(&self, def: DefId) -> Visibility { self.get_crate_data(def.krate).get_visibility(def.index) } @@ -533,8 +535,8 @@ impl CStore { ) } - pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool { - self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index) + pub fn fn_has_self_parameter_untracked(&self, def: DefId, sess: &Session) -> bool { + self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index, sess) } pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc { @@ -675,6 +677,9 @@ impl CrateStore for CStore { } fn import_source_files(&self, sess: &Session, cnum: CrateNum) { - self.get_crate_data(cnum).imported_source_files(sess); + let cdata = self.get_crate_data(cnum); + for file_index in 0..cdata.root.source_map.size() { + cdata.imported_source_file(file_index as u32, sess); + } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 33278367c..5a60ea794 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,3 +1,4 @@ +use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile}; use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; @@ -16,8 +17,6 @@ use rustc_hir::def_id::{ use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items; -use rustc_hir::{AnonConst, GenericParamKind}; -use rustc_index::bit_set::GrowableBitSet; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -39,12 +38,12 @@ use rustc_span::{ }; use rustc_target::abi::VariantIdx; use std::borrow::Borrow; +use std::collections::hash_map::Entry; use std::hash::Hash; use std::io::{Read, Seek, Write}; use std::iter; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; -use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::FileEncoder, @@ -66,15 +65,13 @@ pub(super) struct EncodeContext<'a, 'tcx> { // The indices (into the `SourceMap`'s `MonotonicVec`) // of all of the `SourceFiles` that we need to serialize. // When we serialize a `Span`, we insert the index of its - // `SourceFile` into the `GrowableBitSet`. - // - // This needs to be a `GrowableBitSet` and not a - // regular `BitSet` because we may actually import new `SourceFiles` - // during metadata encoding, due to executing a query - // with a result containing a foreign `Span`. - required_source_files: Option>, + // `SourceFile` into the `FxIndexSet`. + // The order inside the `FxIndexSet` is used as on-disk + // order of `SourceFiles`, and encoded inside `Span`s. + required_source_files: Option>, is_proc_macro: bool, hygiene_ctxt: &'a HygieneEncodeContext, + symbol_table: FxHashMap, } /// If the current crate is a proc-macro, returns early with `Lazy:empty()`. @@ -238,17 +235,15 @@ impl<'a, 'tcx> Encodable> for Span { s.source_file_cache = (source_map.files()[source_file_index].clone(), source_file_index); } + let (ref source_file, source_file_index) = s.source_file_cache; + debug_assert!(source_file.contains(span.lo)); - if !s.source_file_cache.0.contains(span.hi) { + if !source_file.contains(span.hi) { // Unfortunately, macro expansion still sometimes generates Spans // that malformed in this way. return TAG_PARTIAL_SPAN.encode(s); } - let source_files = s.required_source_files.as_mut().expect("Already encoded SourceMap!"); - // Record the fact that we need to encode the data for this `SourceFile` - source_files.insert(s.source_file_cache.1); - // There are two possible cases here: // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the // crate we are writing metadata for. When the metadata for *this* crate gets @@ -265,7 +260,7 @@ impl<'a, 'tcx> Encodable> for Span { // if we're a proc-macro crate. // This allows us to avoid loading the dependencies of proc-macro crates: all of // the information we need to decode `Span`s is stored in the proc-macro crate. - let (tag, lo, hi) = if s.source_file_cache.0.is_imported() && !s.is_proc_macro { + let (tag, metadata_index) = if source_file.is_imported() && !s.is_proc_macro { // To simplify deserialization, we 'rebase' this span onto the crate it originally came from // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values // are relative to the source map information for the 'foreign' crate whose CrateNum @@ -275,29 +270,41 @@ impl<'a, 'tcx> Encodable> for Span { // // All of this logic ensures that the final result of deserialization is a 'normal' // Span that can be used without any additional trouble. - let external_start_pos = { + let metadata_index = { // Introduce a new scope so that we drop the 'lock()' temporary - match &*s.source_file_cache.0.external_src.lock() { - ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos, + match &*source_file.external_src.lock() { + ExternalSource::Foreign { metadata_index, .. } => *metadata_index, src => panic!("Unexpected external source {:?}", src), } }; - let lo = (span.lo - s.source_file_cache.0.start_pos) + external_start_pos; - let hi = (span.hi - s.source_file_cache.0.start_pos) + external_start_pos; - (TAG_VALID_SPAN_FOREIGN, lo, hi) + (TAG_VALID_SPAN_FOREIGN, metadata_index) } else { - (TAG_VALID_SPAN_LOCAL, span.lo, span.hi) + // Record the fact that we need to encode the data for this `SourceFile` + let source_files = + s.required_source_files.as_mut().expect("Already encoded SourceMap!"); + let (metadata_index, _) = source_files.insert_full(source_file_index); + let metadata_index: u32 = + metadata_index.try_into().expect("cannot export more than U32_MAX files"); + + (TAG_VALID_SPAN_LOCAL, metadata_index) }; - tag.encode(s); - lo.encode(s); + // Encode the start position relative to the file start, so we profit more from the + // variable-length integer encoding. + let lo = span.lo - source_file.start_pos; // Encode length which is usually less than span.hi and profits more // from the variable-length integer encoding that we use. - let len = hi - lo; + let len = span.hi - span.lo; + + tag.encode(s); + lo.encode(s); len.encode(s); + // Encode the index of the `SourceFile` for the span, in order to make decoding faster. + metadata_index.encode(s); + if tag == TAG_VALID_SPAN_FOREIGN { // This needs to be two lines to avoid holding the `s.source_file_cache` // while calling `cnum.encode(s)` @@ -307,6 +314,31 @@ impl<'a, 'tcx> Encodable> for Span { } } +impl<'a, 'tcx> Encodable> for Symbol { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { + // if symbol preinterned, emit tag and symbol index + if self.is_preinterned() { + s.opaque.emit_u8(SYMBOL_PREINTERNED); + s.opaque.emit_u32(self.as_u32()); + } else { + // otherwise write it as string or as offset to it + match s.symbol_table.entry(*self) { + Entry::Vacant(o) => { + s.opaque.emit_u8(SYMBOL_STR); + let pos = s.opaque.position(); + o.insert(pos); + s.emit_str(self.as_str()); + } + Entry::Occupied(o) => { + let x = o.get().clone(); + s.emit_u8(SYMBOL_OFFSET); + s.emit_usize(x); + } + } + } + } +} + impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; @@ -449,7 +481,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map())) } - fn encode_source_map(&mut self) -> LazyArray { + fn encode_source_map(&mut self) -> LazyTable> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -460,66 +492,64 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let working_directory = &self.tcx.sess.opts.working_dir; - let adapted = all_source_files - .iter() - .enumerate() - .filter(|(idx, source_file)| { - // Only serialize `SourceFile`s that were used - // during the encoding of a `Span` - required_source_files.contains(*idx) && - // Don't serialize imported `SourceFile`s, unless - // we're in a proc-macro crate. - (!source_file.is_imported() || self.is_proc_macro) - }) - .map(|(_, source_file)| { - // At export time we expand all source file paths to absolute paths because - // downstream compilation sessions can have a different compiler working - // directory, so relative paths from this or any other upstream crate - // won't be valid anymore. - // - // At this point we also erase the actual on-disk path and only keep - // the remapped version -- as is necessary for reproducible builds. - match source_file.name { - FileName::Real(ref original_file_name) => { - let adapted_file_name = - source_map.path_mapping().to_embeddable_absolute_path( - original_file_name.clone(), - working_directory, - ); - - if adapted_file_name != *original_file_name { - let mut adapted: SourceFile = (**source_file).clone(); - adapted.name = FileName::Real(adapted_file_name); - adapted.name_hash = { - let mut hasher: StableHasher = StableHasher::new(); - adapted.name.hash(&mut hasher); - hasher.finish::() - }; - Lrc::new(adapted) - } else { - // Nothing to adapt - source_file.clone() - } + let mut adapted = TableBuilder::default(); + + // Only serialize `SourceFile`s that were used during the encoding of a `Span`. + // + // The order in which we encode source files is important here: the on-disk format for + // `Span` contains the index of the corresponding `SourceFile`. + for (on_disk_index, &source_file_index) in required_source_files.iter().enumerate() { + let source_file = &all_source_files[source_file_index]; + // Don't serialize imported `SourceFile`s, unless we're in a proc-macro crate. + assert!(!source_file.is_imported() || self.is_proc_macro); + + // At export time we expand all source file paths to absolute paths because + // downstream compilation sessions can have a different compiler working + // directory, so relative paths from this or any other upstream crate + // won't be valid anymore. + // + // At this point we also erase the actual on-disk path and only keep + // the remapped version -- as is necessary for reproducible builds. + let mut source_file = match source_file.name { + FileName::Real(ref original_file_name) => { + let adapted_file_name = source_map + .path_mapping() + .to_embeddable_absolute_path(original_file_name.clone(), working_directory); + + if adapted_file_name != *original_file_name { + let mut adapted: SourceFile = (**source_file).clone(); + adapted.name = FileName::Real(adapted_file_name); + adapted.name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + adapted.name.hash(&mut hasher); + hasher.finish::() + }; + Lrc::new(adapted) + } else { + // Nothing to adapt + source_file.clone() } - // expanded code, not from a file - _ => source_file.clone(), - } - }) - .map(|mut source_file| { - // We're serializing this `SourceFile` into our crate metadata, - // so mark it as coming from this crate. - // This also ensures that we don't try to deserialize the - // `CrateNum` for a proc-macro dependency - since proc macro - // dependencies aren't loaded when we deserialize a proc-macro, - // trying to remap the `CrateNum` would fail. - if self.is_proc_macro { - Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; } - source_file - }) - .collect::>(); + // expanded code, not from a file + _ => source_file.clone(), + }; + + // We're serializing this `SourceFile` into our crate metadata, + // so mark it as coming from this crate. + // This also ensures that we don't try to deserialize the + // `CrateNum` for a proc-macro dependency - since proc macro + // dependencies aren't loaded when we deserialize a proc-macro, + // trying to remap the `CrateNum` would fail. + if self.is_proc_macro { + Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; + } + + let on_disk_index: u32 = + on_disk_index.try_into().expect("cannot export more than U32_MAX files"); + adapted.set(on_disk_index, self.lazy(source_file)); + } - self.lazy_array(adapted.iter().map(|rc| &**rc)) + adapted.encode(&mut self.opaque) } fn encode_crate_root(&mut self) -> LazyValue { @@ -817,6 +847,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::ForeignMod | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Field => true, DefKind::TyParam @@ -849,6 +880,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::ForeignMod | DefKind::TyAlias | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Enum | DefKind::Union | DefKind::Impl @@ -937,6 +969,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::ForeignMod | DefKind::TyAlias | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Trait | DefKind::TraitAlias @@ -973,6 +1006,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Impl | DefKind::Field | DefKind::TyParam @@ -989,6 +1023,103 @@ fn should_encode_generics(def_kind: DefKind) -> bool { } } +fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> bool { + match def_kind { + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(..) + | DefKind::Field + | DefKind::Fn + | DefKind::Const + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ForeignTy + | DefKind::Impl + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::InlineConst => true, + + DefKind::ImplTraitPlaceholder => { + let parent_def_id = tcx.impl_trait_in_trait_parent(def_id.to_def_id()); + let assoc_item = tcx.associated_item(parent_def_id); + match assoc_item.container { + // Always encode an RPIT in an impl fn, since it always has a body + ty::AssocItemContainer::ImplContainer => true, + ty::AssocItemContainer::TraitContainer => { + // Encode an RPIT for a trait only if the trait has a default body + assoc_item.defaultness(tcx).has_value() + } + } + } + + DefKind::AssocTy => { + let assoc_item = tcx.associated_item(def_id); + match assoc_item.container { + ty::AssocItemContainer::ImplContainer => true, + ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(), + } + } + DefKind::TyParam => { + let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(def_id) else { bug!() }; + let hir::GenericParamKind::Type { default, .. } = param.kind else { bug!() }; + default.is_some() + } + + DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + +fn should_encode_const(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(..) + | DefKind::Field + | DefKind::Fn + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::ForeignTy + | DefKind::Impl + | DefKind::AssocFn + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let mut attrs = self @@ -1014,7 +1145,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_kind = tcx.opt_def_kind(local_id); let Some(def_kind) = def_kind else { continue }; self.tables.opt_def_kind.set(def_id.index, def_kind); - record!(self.tables.def_span[def_id] <- tcx.def_span(def_id)); + let def_span = tcx.def_span(local_id); + record!(self.tables.def_span[def_id] <- def_span); self.encode_attrs(local_id); record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); if let Some(ident_span) = tcx.def_ident_span(def_id) { @@ -1024,11 +1156,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); } if should_encode_visibility(def_kind) { - record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + let vis = + self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index); + record!(self.tables.visibility[def_id] <- vis); } if should_encode_stability(def_kind) { self.encode_stability(def_id); self.encode_const_stability(def_id); + self.encode_default_body_stability(def_id); self.encode_deprecation(def_id); } if should_encode_variances(def_kind) { @@ -1044,6 +1179,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } + if should_encode_type(tcx, local_id, def_kind) { + record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); + } + if let DefKind::TyParam = def_kind { + let default = self.tcx.object_lifetime_default(def_id); + record!(self.tables.object_lifetime_default[def_id] <- default); + } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } @@ -1060,11 +1202,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_item_type(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_item_type({:?})", def_id); - record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); - } - fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { let tcx = self.tcx; let variant = &def.variant(index); @@ -1078,13 +1215,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; - record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.variant_data[def_id] <- data); self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. if let Some(ctor_def_id) = variant.ctor_def_id { @@ -1107,9 +1243,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; - record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.variant_data[def_id] <- data); self.tables.constness.set(def_id.index, hir::Constness::Const); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1126,15 +1261,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // code uses it). However, we skip encoding anything relating to child // items - we encode information about proc-macros later on. let reexports = if !self.is_proc_macro { - match tcx.module_reexports(local_def_id) { - Some(exports) => self.lazy_array(exports), - _ => LazyArray::empty(), - } + tcx.module_reexports(local_def_id).unwrap_or(&[]) } else { - LazyArray::empty() + &[] }; - record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports)); + record_array!(self.tables.module_reexports[def_id] <- reexports); if self.is_proc_macro { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); @@ -1162,22 +1294,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_field( - &mut self, - adt_def: ty::AdtDef<'tcx>, - variant_index: VariantIdx, - field_index: usize, - ) { - let variant = &adt_def.variant(variant_index); - let field = &variant.fields[field_index]; - - let def_id = field.did; - debug!("EncodeContext::encode_field({:?})", def_id); - - record!(self.tables.kind[def_id] <- EntryKind::Field); - self.encode_item_type(def_id); - } - fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) { debug!("EncodeContext::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; @@ -1191,9 +1307,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.repr_options[def_id] <- adt_def.repr()); + record!(self.tables.variant_data[def_id] <- data); self.tables.constness.set(def_id.index, hir::Constness::Const); - record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data))); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1214,18 +1329,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = tcx.hir().expect_trait_item(def_id.expect_local()); self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); let trait_item = tcx.associated_item(def_id); + self.tables.assoc_container.set(def_id.index, trait_item.container); match trait_item.kind { - ty::AssocKind::Const => { - let rendered = rustc_hir_pretty::to_string( - &(&self.tcx.hir() as &dyn intravisit::Map<'_>), - |s| s.print_trait_item(ast_item), - ); - - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer)); - record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default()); - record!(self.tables.rendered_const[def_id] <- rendered); - } + ty::AssocKind::Const => {} ty::AssocKind::Fn => { let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() }; match *m { @@ -1238,24 +1345,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); self.tables.constness.set(def_id.index, hir::Constness::NotConst); - record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - container: ty::AssocItemContainer::TraitContainer, - has_self: trait_item.fn_has_self_parameter, - }); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); - record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer)); - } - } - match trait_item.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => { - self.encode_item_type(def_id); - } - ty::AssocKind::Type => { - if ast_item.defaultness.has_value() { - self.encode_item_type(def_id); - } } } if trait_item.kind == ty::AssocKind::Fn { @@ -1270,20 +1362,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local()); self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); let impl_item = self.tcx.associated_item(def_id); + self.tables.assoc_container.set(def_id.index, impl_item.container); match impl_item.kind { - ty::AssocKind::Const => { - if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind { - let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer)); - record!(self.tables.mir_const_qualif[def_id] <- qualifs); - record!(self.tables.rendered_const[def_id] <- const_data); - } else { - bug!() - } - } ty::AssocKind::Fn => { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); @@ -1295,16 +1376,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Constness::NotConst }; self.tables.constness.set(def_id.index, constness); - record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - container: ty::AssocItemContainer::ImplContainer, - has_self: impl_item.fn_has_self_parameter, - }); - } - ty::AssocKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer)); } + ty::AssocKind::Const | ty::AssocKind::Type => {} } - self.encode_item_type(def_id); if let Some(trait_item_def_id) = impl_item.trait_item_def_id { self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); } @@ -1321,40 +1395,43 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - let keys_and_jobs = self - .tcx - .mir_keys(()) - .iter() - .filter_map(|&def_id| { - let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id); - if encode_const || encode_opt { - Some((def_id, encode_const, encode_opt)) - } else { - None - } - }) - .collect::>(); - for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() { + let tcx = self.tcx; + + let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| { + let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); + if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None } + }); + for (def_id, encode_const, encode_opt) in keys_and_jobs { debug_assert!(encode_const || encode_opt); debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { - record!(self.tables.optimized_mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id)); + record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); } if encode_const { - record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); + record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` - let abstract_const = self.tcx.thir_abstract_const(def_id); + let abstract_const = tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { record!(self.tables.thir_abstract_const[def_id.to_def_id()] <- abstract_const); } + + if should_encode_const(tcx.def_kind(def_id)) { + let qualifs = tcx.mir_const_qualif(def_id); + record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); + let body_id = tcx.hir().maybe_body_owned_by(def_id); + if let Some(body_id) = body_id { + let const_data = self.encode_rendered_const_for_body(body_id); + record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); + } + } } - record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); + record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); - let unused = self.tcx.unused_generic_params(instance); + let unused = tcx.unused_generic_params(instance); if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } @@ -1385,6 +1462,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_default_body_stability(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_default_body_stability({:?})", def_id); + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { + record!(self.tables.lookup_default_body_stability[def_id] <- stab) + } + } + } + fn encode_deprecation(&mut self, def_id: DefId) { debug!("EncodeContext::encode_deprecation({:?})", def_id); if let Some(depr) = self.tcx.lookup_deprecation(def_id) { @@ -1405,38 +1494,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_info_for_item({:?})", def_id); - let entry_kind = match item.kind { - hir::ItemKind::Static(..) => EntryKind::Static, - hir::ItemKind::Const(_, body_id) => { - let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - record!(self.tables.mir_const_qualif[def_id] <- qualifs); - record!(self.tables.rendered_const[def_id] <- const_data); - EntryKind::Const - } + match item.kind { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); self.tables.constness.set(def_id.index, sig.header.constness); - EntryKind::Fn } hir::ItemKind::Macro(ref macro_def, _) => { - EntryKind::MacroDef(self.lazy(&*macro_def.body), macro_def.macro_rules) + if macro_def.macro_rules { + self.tables.macro_rules.set(def_id.index, ()); + } + record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); } - hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod, - hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, - hir::ItemKind::TyAlias(..) => EntryKind::Type, hir::ItemKind::OpaqueTy(..) => { self.encode_explicit_item_bounds(def_id); - EntryKind::OpaqueTy } hir::ItemKind::Enum(..) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); - EntryKind::Enum } hir::ItemKind::Struct(ref struct_def, _) => { let adt_def = self.tcx.adt_def(def_id); @@ -1451,24 +1529,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index); let variant = adt_def.non_enum_variant(); - EntryKind::Struct(self.lazy(VariantData { + record!(self.tables.variant_data[def_id] <- VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor, is_non_exhaustive: variant.is_field_list_non_exhaustive(), - })) + }); } hir::ItemKind::Union(..) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); let variant = adt_def.non_enum_variant(); - EntryKind::Union(self.lazy(VariantData { + record!(self.tables.variant_data[def_id] <- VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: None, is_non_exhaustive: variant.is_field_list_non_exhaustive(), - })) + }); } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); @@ -1494,26 +1572,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let polarity = self.tcx.impl_polarity(def_id); self.tables.impl_polarity.set(def_id.index, polarity); - - EntryKind::Impl } hir::ItemKind::Trait(..) => { let trait_def = self.tcx.trait_def(def_id); record!(self.tables.trait_def[def_id] <- trait_def); - - EntryKind::Trait } hir::ItemKind::TraitAlias(..) => { let trait_def = self.tcx.trait_def(def_id); record!(self.tables.trait_def[def_id] <- trait_def); - - EntryKind::TraitAlias } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => { bug!("cannot encode info for item {:?}", item) } + hir::ItemKind::Static(..) + | hir::ItemKind::Const(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::TyAlias(..) => {} }; - record!(self.tables.kind[def_id] <- entry_kind); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <- @@ -1541,18 +1617,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } _ => {} } - match item.kind { - hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::Impl { .. } => self.encode_item_type(def_id), - _ => {} - } if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { @@ -1564,12 +1628,43 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.impl_trait_ref[def_id] <- trait_ref); } } - } + // In some cases, along with the item itself, we also + // encode some sub-items. Usually we want some info from the item + // so it's easier to do that here then to wait until we would encounter + // normally in the visitor walk. + match item.kind { + hir::ItemKind::Enum(..) => { + let def = self.tcx.adt_def(item.def_id.to_def_id()); + for (i, variant) in def.variants().iter_enumerated() { + self.encode_enum_variant_info(def, i); - fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) { - record!(self.tables.kind[def_id] <- kind); - if encode_type { - self.encode_item_type(def_id); + if let Some(_ctor_def_id) = variant.ctor_def_id { + self.encode_enum_variant_ctor(def, i); + } + } + } + hir::ItemKind::Struct(ref struct_def, _) => { + let def = self.tcx.adt_def(item.def_id.to_def_id()); + // If the struct has a constructor, encode it. + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); + self.encode_struct_ctor(def, ctor_def_id.to_def_id()); + } + } + hir::ItemKind::Impl { .. } => { + for &trait_item_def_id in + self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + { + self.encode_info_for_impl_item(trait_item_def_id); + } + } + hir::ItemKind::Trait(..) => { + for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + { + self.encode_info_for_trait_item(item_def_id); + } + } + _ => {} } } @@ -1584,34 +1679,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Generator(..) => { let data = self.tcx.generator_kind(def_id).unwrap(); let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator); record!(self.tables.generator_kind[def_id.to_def_id()] <- data); record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); } - ty::Closure(..) => { - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure); + ty::Closure(_, substs) => { + record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); } _ => bug!("closure that is neither generator nor closure"), } - self.encode_item_type(def_id.to_def_id()); - if let ty::Closure(def_id, substs) = *ty.kind() { - record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig()); - } - } - - fn encode_info_for_anon_const(&mut self, id: hir::HirId) { - let def_id = self.tcx.hir().local_def_id(id); - debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id); - let body_id = self.tcx.hir().body_owned_by(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - let qualifs = self.tcx.mir_const_qualif(def_id); - - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst); - record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); - record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); - self.encode_item_type(def_id.to_def_id()); } fn encode_native_libraries(&mut self) -> LazyArray { @@ -1670,7 +1747,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); - record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id())); + let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index); + record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- vis); if let Some(stability) = stability { record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability); } @@ -1709,7 +1787,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = id.to_def_id(); self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); - record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); + self.tables.proc_macro.set(def_id.index, macro_kind); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_ident_span[def_id] <- span); @@ -1947,18 +2025,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Constness::NotConst }; self.tables.constness.set(def_id.index, constness); - record!(self.tables.kind[def_id] <- EntryKind::ForeignFn); - } - hir::ForeignItemKind::Static(..) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic); - } - hir::ForeignItemKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignType); + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} } - self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { self.tables.is_intrinsic.set(def_id.index, ()); } @@ -1977,17 +2048,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_expr(self, ex); self.encode_info_for_expr(ex); } - fn visit_anon_const(&mut self, c: &'tcx AnonConst) { - intravisit::walk_anon_const(self, c); - self.encode_info_for_anon_const(c.hir_id); - } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { intravisit::walk_item(self, item); match item.kind { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these _ => self.encode_info_for_item(item.def_id.to_def_id(), item), } - self.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { intravisit::walk_foreign_item(self, ni); @@ -2000,29 +2066,13 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) { - for (variant_index, variant) in adt_def.variants().iter_enumerated() { - for (field_index, _field) in variant.fields.iter().enumerate() { - self.encode_field(adt_def, variant_index, field_index); - } - } - } - fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) { for param in generics.params { let def_id = self.tcx.hir().local_def_id(param.hir_id); match param.kind { - GenericParamKind::Lifetime { .. } => continue, - GenericParamKind::Type { default, .. } => { - self.encode_info_for_generic_param( - def_id.to_def_id(), - EntryKind::TypeParam, - default.is_some(), - ); - } - GenericParamKind::Const { ref default, .. } => { + hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {} + hir::GenericParamKind::Const { ref default, .. } => { let def_id = def_id.to_def_id(); - self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true); if default.is_some() { record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id)) } @@ -2036,68 +2086,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_info_for_closure(expr.hir_id); } } - - /// In some cases, along with the item itself, we also - /// encode some sub-items. Usually we want some info from the item - /// so it's easier to do that here then to wait until we would encounter - /// normally in the visitor walk. - fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) { - match item.kind { - hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TraitAlias(..) => { - // no sub-item recording needed in these cases - } - hir::ItemKind::Enum(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - - for (i, variant) in def.variants().iter_enumerated() { - self.encode_enum_variant_info(def, i); - - if let Some(_ctor_def_id) = variant.ctor_def_id { - self.encode_enum_variant_ctor(def, i); - } - } - } - hir::ItemKind::Struct(ref struct_def, _) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - - // If the struct has a constructor, encode it. - if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { - let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); - self.encode_struct_ctor(def, ctor_def_id.to_def_id()); - } - } - hir::ItemKind::Union(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - } - hir::ItemKind::Impl { .. } => { - for &trait_item_def_id in - self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() - { - self.encode_info_for_impl_item(trait_item_def_id); - } - } - hir::ItemKind::Trait(..) => { - for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() - { - self.encode_info_for_trait_item(item_def_id); - } - } - } - } } /// Used to prefetch queries which will be needed later by metadata encoding. @@ -2220,7 +2208,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let mut encoder = opaque::FileEncoder::new(path) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err })); encoder.emit_raw_bytes(METADATA_HEADER); // Will be filled with the root position after encoding everything. @@ -2228,7 +2216,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let source_map_files = tcx.sess.source_map().files(); let source_file_cache = (source_map_files[0].clone(), 0); - let required_source_files = Some(GrowableBitSet::with_capacity(source_map_files.len())); + let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); let hygiene_ctxt = HygieneEncodeContext::default(); @@ -2246,6 +2234,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { required_source_files, is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro), hygiene_ctxt: &hygiene_ctxt, + symbol_table: Default::default(), }; // Encode the rustc version string in a predictable location. @@ -2264,10 +2253,10 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { // Encode the root position. let header = METADATA_HEADER.len(); file.seek(std::io::SeekFrom::Start(header as u64)) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err })); let pos = root.position.get(); file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8]) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err })); // Return to the position where we are before writing the root position. file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 66bdecc30..748b3afec 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; @@ -249,7 +250,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue>, - source_map: LazyArray, + source_map: LazyTable>, compiler_builtins: bool, needs_allocator: bool, @@ -333,16 +334,16 @@ macro_rules! define_tables { } define_tables! { - kind: Table>, attributes: Table>, children: Table>, opt_def_kind: Table, - visibility: Table>, + visibility: Table>>, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, lookup_const_stability: Table>, + lookup_default_body_stability: Table>, lookup_deprecation_entry: Table>, // As an optimization, a missing entry indicates an empty `&[]`. explicit_item_bounds: Table, Span)>>, @@ -357,6 +358,7 @@ define_tables! { codegen_fn_attrs: Table>, impl_trait_ref: Table>>, const_param_default: Table>>, + object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, promoted_mir: Table>>>, @@ -390,39 +392,13 @@ define_tables! { proc_macro_quoted_spans: Table>, generator_diagnostic_data: Table>>, may_have_doc_links: Table, -} - -#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] -enum EntryKind { - AnonConst, - Const, - Static, - ForeignStatic, - ForeignMod, - ForeignType, - GlobalAsm, - Type, - TypeParam, - ConstParam, - OpaqueTy, - Enum, - Field, - Variant(LazyValue), - Struct(LazyValue), - Union(LazyValue), - Fn, - ForeignFn, - Mod(LazyArray), - MacroDef(LazyValue, /*macro_rules*/ bool), - ProcMacro(MacroKind), - Closure, - Generator, - Trait, - Impl, - AssocFn { container: ty::AssocItemContainer, has_self: bool }, - AssocType(ty::AssocItemContainer), - AssocConst(ty::AssocItemContainer), - TraitAlias, + variant_data: Table>, + assoc_container: Table, + // Slot is full when macro is macro_rules. + macro_rules: Table, + macro_definition: Table>, + proc_macro: Table, + module_reexports: Table>, } #[derive(TyEncodable, TyDecodable)] @@ -444,6 +420,11 @@ const TAG_VALID_SPAN_LOCAL: u8 = 0; const TAG_VALID_SPAN_FOREIGN: u8 = 1; const TAG_PARTIAL_SPAN: u8 = 2; +// Tags for encoding Symbol's +const SYMBOL_STR: u8 = 0; +const SYMBOL_OFFSET: u8 = 1; +const SYMBOL_PREINTERNED: u8 = 2; + pub fn provide(providers: &mut Providers) { encoder::provide(providers); decoder::provide(providers); @@ -451,7 +432,6 @@ pub fn provide(providers: &mut Providers) { trivially_parameterized_over_tcx! { VariantData, - EntryKind, RawDefId, TraitImpls, IncoherentImpls, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 21841ae25..e7c1abd12 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -10,7 +10,6 @@ use rustc_span::hygiene::MacroKind; use std::convert::TryInto; use std::marker::PhantomData; use std::num::NonZeroUsize; -use tracing::debug; /// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Used mainly for Lazy positions and lengths. @@ -51,7 +50,7 @@ macro_rules! fixed_size_enum { } match b[0] - 1 { $(${index()} => Some($($pat)*),)* - _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]), + _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]), } } @@ -91,6 +90,7 @@ fixed_size_enum! { ( AnonConst ) ( InlineConst ) ( OpaqueTy ) + ( ImplTraitPlaceholder ) ( Field ) ( LifetimeParam ) ( GlobalAsm ) @@ -141,6 +141,21 @@ fixed_size_enum! { } } +fixed_size_enum! { + ty::AssocItemContainer { + ( TraitContainer ) + ( ImplContainer ) + } +} + +fixed_size_enum! { + MacroKind { + ( Attr ) + ( Bang ) + ( Derive ) + } +} + // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. impl FixedSizeEncoding for Option { type ByteArray = [u8; 16]; diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 008d2c709..cca17a4ec 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -7,34 +7,35 @@ edition = "2021" doctest = false [dependencies] -rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" +chalk-ir = "0.80.0" either = "1.5.0" gsgdt = "0.1.2" -tracing = "0.1" -rustc-rayon = { version = "0.4.0", optional = true } -rustc-rayon-core = { version = "0.4.0", optional = true } polonius-engine = "0.13.0" +rand = "0.8.4" +rand_xoshiro = "0.6.0" rustc_apfloat = { path = "../rustc_apfloat" } +rustc_arena = { path = "../rustc_arena" } +rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } -rustc_feature = { path = "../rustc_feature" } -rustc_hir = { path = "../rustc_hir" } -rustc_target = { path = "../rustc_target" } -rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_query_system = { path = "../rustc_query_system" } rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } rustc_graphviz = { path = "../rustc_graphviz" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_query_system = { path = "../rustc_query_system" } +rustc-rayon-core = { version = "0.4.0", optional = true } +rustc-rayon = { version = "0.4.0", optional = true } rustc_serialize = { path = "../rustc_serialize" } -rustc_ast = { path = "../rustc_ast" } -rustc_span = { path = "../rustc_span" } -chalk-ir = "0.80.0" -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } rustc_type_ir = { path = "../rustc_type_ir" } -rand = "0.8.4" -rand_xoshiro = "0.6.0" +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +thin-vec = "0.2.8" +tracing = "0.1" [features] rustc_use_parallel_compiler = ["rustc-rayon", "rustc-rayon-core"] diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index b94de537d..6bdf5a023 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -100,7 +100,9 @@ macro_rules! arena_types { [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, - [] dep_kind: rustc_middle::dep_graph::DepKindStruct, + [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, + + [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>, ]); ) } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 2d095438f..1fa0c6bab 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -74,7 +74,7 @@ pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; /// Information is retrieved by indexing the `DEP_KINDS` array using the integer value /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual /// jump table instead of large matches. -pub struct DepKindStruct { +pub struct DepKindStruct<'tcx> { /// Anonymous queries cannot be replayed from one compiler invocation to the next. /// When their result is needed, it is recomputed. They are useful for fine-grained /// dependency tracking, and caching within one compiler invocation. @@ -124,10 +124,10 @@ pub struct DepKindStruct { /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// is actually a `DefPathHash`, and can therefore just look up the corresponding /// `DefId` in `tcx.def_path_hash_to_def_id`. - pub force_from_dep_node: Option, dep_node: DepNode) -> bool>, + pub force_from_dep_node: Option, dep_node: DepNode) -> bool>, /// Invoke a query to put the on-disk cached value in memory. - pub try_load_from_on_disk_cache: Option, DepNode)>, + pub try_load_from_on_disk_cache: Option, DepNode)>, } impl DepKind { @@ -143,12 +143,10 @@ impl DepKind { } macro_rules! define_dep_nodes { - (<$tcx:tt> - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* - ) => ( + ( + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty,)*) => { + #[macro_export] macro_rules! make_dep_kind_array { ($mod:ident) => {[ $($mod::$variant()),* ]}; @@ -158,7 +156,7 @@ macro_rules! define_dep_nodes { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[allow(non_camel_case_types)] pub enum DepKind { - $($variant),* + $( $( #[$attr] )* $variant),* } fn dep_kind_from_label_string(label: &str) -> Result { @@ -176,24 +174,17 @@ macro_rules! define_dep_nodes { pub const $variant: &str = stringify!($variant); )* } - ); + }; } -rustc_dep_node_append!([define_dep_nodes!][ <'tcx> - // We use this for most things when incr. comp. is turned off. - [] Null, - - // We use this to create a forever-red node. - [] Red, - - [anon] TraitSelect, - - // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. - [] CompileCodegenUnit(Symbol), - - // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item` below. - // Only used by rustc_codegen_cranelift - [] CompileMonoItem(MonoItem), +rustc_query_append!(define_dep_nodes![ + /// We use this for most things when incr. comp. is turned off. + [] fn Null() -> (), + /// We use this to create a forever-red node. + [] fn Red() -> (), + [] fn TraitSelect() -> (), + [] fn CompileCodegenUnit() -> (), + [] fn CompileMonoItem() -> (), ]); // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs new file mode 100644 index 000000000..18b31a75b --- /dev/null +++ b/compiler/rustc_middle/src/error.rs @@ -0,0 +1,50 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +use crate::ty::Ty; + +#[derive(SessionDiagnostic)] +#[diag(middle::drop_check_overflow, code = "E0320")] +#[note] +pub struct DropCheckOverflow<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub overflow_ty: Ty<'tcx>, +} + +#[derive(SessionDiagnostic)] +#[diag(middle::opaque_hidden_type_mismatch)] +pub struct OpaqueHiddenTypeMismatch<'tcx> { + pub self_ty: Ty<'tcx>, + pub other_ty: Ty<'tcx>, + #[primary_span] + #[label] + pub other_span: Span, + #[subdiagnostic] + pub sub: TypeMismatchReason, +} + +#[derive(SessionSubdiagnostic)] +pub enum TypeMismatchReason { + #[label(middle::conflict_types)] + ConflictType { + #[primary_span] + span: Span, + }, + #[note(middle::previous_use_here)] + PreviousUse { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionDiagnostic)] +#[diag(middle::limit_invalid)] +pub struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 47b04c33e..30a23c342 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -17,28 +17,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; -fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { - match node { - Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) - | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) - | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl), - Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => { - Some(fn_decl) - } - _ => None, - } -} - -pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { - match &node { - Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) - | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) - | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(sig), - _ => None, - } -} - #[inline] pub fn associated_body<'hir>(node: Node<'hir>) -> Option { match node { @@ -146,10 +124,12 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { } impl<'hir> Map<'hir> { + #[inline] pub fn krate(self) -> &'hir Crate<'hir> { self.tcx.hir_crate(()) } + #[inline] pub fn root_module(self) -> &'hir Mod<'hir> { match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) { Some(OwnerNode::Crate(item)) => item, @@ -157,14 +137,17 @@ impl<'hir> Map<'hir> { } } + #[inline] pub fn items(self) -> impl Iterator + 'hir { self.tcx.hir_crate_items(()).items.iter().copied() } + #[inline] pub fn module_items(self, module: LocalDefId) -> impl Iterator + 'hir { self.tcx.hir_module_items(module).items() } + #[inline] pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); } @@ -229,7 +212,13 @@ impl<'hir> Map<'hir> { ItemKind::Fn(..) => DefKind::Fn, ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, - ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, + ItemKind::OpaqueTy(ref opaque) => { + if opaque.in_trait { + DefKind::ImplTraitPlaceholder + } else { + DefKind::OpaqueTy + } + } ItemKind::TyAlias(..) => DefKind::TyAlias, ItemKind::Enum(..) => DefKind::Enum, ItemKind::Struct(..) => DefKind::Struct, @@ -297,6 +286,8 @@ impl<'hir> Map<'hir> { | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) + | Node::PatField(_) + | Node::ExprField(_) | Node::Local(_) | Node::Param(_) | Node::Arm(_) @@ -306,6 +297,9 @@ impl<'hir> Map<'hir> { Some(def_kind) } + /// Finds the id of the parent node to this one. + /// + /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. pub fn find_parent_node(self, id: HirId) -> Option { if id.local_id == ItemLocalId::from_u32(0) { Some(self.tcx.hir_owner_parent(id.owner)) @@ -313,6 +307,8 @@ impl<'hir> Map<'hir> { let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?; let node = owner.nodes[id.local_id].as_ref()?; let hir_id = HirId { owner: id.owner, local_id: node.parent }; + // HIR indexing should have checked that. + debug_assert_ne!(id.local_id, node.parent); Some(hir_id) } } @@ -382,7 +378,7 @@ impl<'hir> Map<'hir> { pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { if let Some(node) = self.find(hir_id) { - fn_decl(node) + node.fn_decl() } else { bug!("no node for hir_id `{}`", hir_id) } @@ -390,7 +386,7 @@ impl<'hir> Map<'hir> { pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> { if let Some(node) = self.find(hir_id) { - fn_sig(node) + node.fn_sig() } else { bug!("no node for hir_id `{}`", hir_id) } @@ -487,11 +483,13 @@ impl<'hir> Map<'hir> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. + #[inline] pub fn body_owners(self) -> impl Iterator + 'hir { self.tcx.hir_crate_items(()).body_owners.iter().copied() } - pub fn par_body_owners(self, f: F) { + #[inline] + pub fn par_body_owners(self, f: impl Fn(LocalDefId) + Sync + Send) { par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } @@ -499,7 +497,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => def_id, - DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id), + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { + self.tcx.local_parent(def_id) + } _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), } } @@ -508,7 +508,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, - DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()), + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { + self.tcx.item_name(def_id.to_def_id()) + } _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), } } @@ -624,35 +626,22 @@ impl<'hir> Map<'hir> { } } - #[cfg(not(parallel_compiler))] #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId)) { - self.for_each_module(f) - } - - #[cfg(parallel_compiler)] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync) { - use rustc_data_structures::sync::{par_iter, ParallelIterator}; - par_iter_submodules(self.tcx, CRATE_DEF_ID, &f); - - fn par_iter_submodules(tcx: TyCtxt<'_>, module: LocalDefId, f: &F) - where - F: Fn(LocalDefId) + Sync, - { - (*f)(module); - let items = tcx.hir_module_items(module); - par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f)); - } + pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) { + let crate_items = self.tcx.hir_crate_items(()); + par_for_each_in(&crate_items.submodules[..], |module| f(*module)) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. + #[inline] pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> { ParentHirIterator { current_id, map: self } } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. + #[inline] pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { ParentOwnerIterator { current_id, map: self } } @@ -1020,6 +1009,7 @@ impl<'hir> Map<'hir> { Node::Field(field) => field.span, Node::AnonConst(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, + Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, Node::PathSegment(seg) => { let ident_span = seg.ident.span; @@ -1030,6 +1020,7 @@ impl<'hir> Map<'hir> { Node::TypeBinding(tb) => tb.span, Node::TraitRef(tr) => tr.path.span, Node::Pat(pat) => pat.span, + Node::PatField(field) => field.span, Node::Arm(arm) => arm.span, Node::Block(block) => block.span, Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)), @@ -1204,7 +1195,13 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::TyAlias(..) => "ty", - ItemKind::OpaqueTy(..) => "opaque type", + ItemKind::OpaqueTy(ref opaque) => { + if opaque.in_trait { + "opaque type in trait" + } else { + "opaque type" + } + } ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -1241,12 +1238,14 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { } Some(Node::AnonConst(_)) => node_str("const"), Some(Node::Expr(_)) => node_str("expr"), + Some(Node::ExprField(_)) => node_str("expr field"), Some(Node::Stmt(_)) => node_str("stmt"), Some(Node::PathSegment(_)) => node_str("path segment"), Some(Node::Ty(_)) => node_str("type"), Some(Node::TypeBinding(_)) => node_str("type binding"), Some(Node::TraitRef(_)) => node_str("trait ref"), Some(Node::Pat(_)) => node_str("pat"), + Some(Node::PatField(_)) => node_str("pattern field"), Some(Node::Param(_)) => node_str("param"), Some(Node::Arm(_)) => node_str("arm"), Some(Node::Block(_)) => node_str("block"), diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 200de9079..d3cf519b6 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -22,6 +22,7 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::MemberConstraint; +use crate::mir::ConstraintCategory; use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_index::vec::IndexVec; @@ -43,6 +44,15 @@ pub struct Canonical<'tcx, V> { pub type CanonicalVarInfos<'tcx> = &'tcx List>; +impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> { + fn try_fold_with>( + self, + folder: &mut F, + ) -> Result { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_canonical_var_infos(v)) + } +} + /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to /// `canonical_value.substitute` to substitute them into the canonical @@ -89,6 +99,7 @@ impl<'tcx> Default for OriginalQueryValues<'tcx> { /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct CanonicalVarInfo<'tcx> { pub kind: CanonicalVarKind<'tcx>, } @@ -114,6 +125,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> { /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum CanonicalVarKind<'tcx> { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), @@ -290,20 +302,15 @@ impl<'tcx, V> Canonical<'tcx, V> { } } -pub type QueryOutlivesConstraint<'tcx> = - ty::Binder<'tcx, ty::OutlivesPredicate, Region<'tcx>>>; +pub type QueryOutlivesConstraint<'tcx> = ( + ty::Binder<'tcx, ty::OutlivesPredicate, Region<'tcx>>>, + ConstraintCategory<'tcx>, +); TrivialTypeTraversalAndLiftImpls! { for <'tcx> { crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalVarInfo<'tcx>, - crate::infer::canonical::CanonicalVarKind<'tcx>, - } -} - -TrivialTypeTraversalImpls! { - for <'tcx> { - crate::infer::canonical::CanonicalVarInfos<'tcx>, + crate::infer::canonical::CanonicalTyVarKind, } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ef06c457b..01b9277b9 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -26,13 +26,12 @@ #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] -#![feature(backtrace)] #![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(get_mut_unchecked)] -#![feature(generic_associated_types)] +#![cfg_attr(bootstrap, feature(generic_associated_types))] #![feature(if_let_guard)] #![feature(map_first_last)] #![feature(negative_impls)] @@ -41,7 +40,7 @@ #![feature(new_uninit)] #![feature(once_cell)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(type_alias_impl_trait)] @@ -87,6 +86,7 @@ pub mod query; pub mod arena; #[macro_use] pub mod dep_graph; +pub(crate) mod error; pub mod hir; pub mod infer; pub mod lint; @@ -96,6 +96,7 @@ pub mod mir; pub mod thir; pub mod traits; pub mod ty; +mod values; pub mod util { pub mod bug; diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index c8e78747d..5ff014c78 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -2,6 +2,7 @@ use crate::ty; use rustc_hir::def::Res; use rustc_macros::HashStable; +use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -18,7 +19,7 @@ pub struct ModChild { /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. pub res: Res, /// Visibility of the item. - pub vis: ty::Visibility, + pub vis: ty::Visibility, /// Span of the item. pub span: Span, /// A proper `macro_rules` item (not a reexport). diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index cc9706f2d..31c20fa14 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -18,11 +18,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { - self.lang_items().require(lang_item).unwrap_or_else(|msg| { + self.lang_items().require(lang_item).unwrap_or_else(|err| { if let Some(span) = span { - self.sess.span_fatal(span, &msg) + self.sess.span_fatal(span, err.to_string()) } else { - self.sess.fatal(&msg) + self.sess.fatal(err.to_string()) } }) } diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index acced0492..53c4d9267 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -10,6 +10,7 @@ //! just peeks and looks for that attribute. use crate::bug; +use crate::error::LimitInvalid; use crate::ty; use rustc_ast::Attribute; use rustc_session::Session; @@ -56,9 +57,6 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u match s.as_str().parse() { Ok(n) => return Limit::new(n), Err(e) => { - let mut err = - sess.struct_span_err(attr.span, "`limit` must be a non-negative integer"); - let value_span = attr .meta() .and_then(|meta| meta.name_value_literal_span()) @@ -74,9 +72,7 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u IntErrorKind::Zero => bug!("zero is a valid `limit`"), kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), }; - - err.span_label(value_span, error_str); - err.emit(); + sess.emit_err(LimitInvalid { span: attr.span, value_span, error_str }); } } } diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 9b2f44567..a171f5711 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -10,7 +10,7 @@ use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId), + EarlyBound(/* lifetime decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId), Free(DefId, /* lifetime decl */ DefId), } @@ -35,7 +35,13 @@ impl Set1 { } } -pub type ObjectLifetimeDefault = Set1; +#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] +pub enum ObjectLifetimeDefault { + Empty, + Static, + Ambiguous, + Param(DefId), +} /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 414912dd0..d182929c4 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -5,7 +5,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, DefIdTree, TyCtxt}; use rustc_ast::NodeId; -use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; +use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; @@ -61,6 +61,7 @@ pub struct Index { /// are filled by the annotator. pub stab_map: FxHashMap, pub const_stab_map: FxHashMap, + pub default_body_stab_map: FxHashMap, pub depr_map: FxHashMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -86,6 +87,10 @@ impl Index { self.const_stab_map.get(&def_id).copied() } + pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { + self.default_body_stab_map.get(&def_id).copied() + } + pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { self.depr_map.get(&def_id).cloned() } @@ -288,7 +293,7 @@ fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // These are not visible outside crate; therefore // stability markers are irrelevant, if even present. - ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true, + ty::Visibility::Restricted(..) => true, } } @@ -416,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + let stability = self.lookup_stability(def_id); debug!( "stability: \ @@ -423,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> { def_id, span, stability ); - // Only the cross-crate scenario matters when checking unstable APIs - let cross_crate = !def_id.is_local(); - if !cross_crate { - return EvalResult::Allow; - } - // Issue #38412: private items lack stability markers. if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; @@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Evaluates the default-impl stability of an item. + /// + /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding + /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending + /// unstable feature otherwise. + pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult { + let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some(); + if !is_staged_api { + return EvalResult::Allow; + } + + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + + let stability = self.lookup_default_body_stability(def_id); + debug!( + "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" + ); + + // Issue #38412: private items lack stability markers. + if skip_stability_check_due_to_privacy(self, def_id) { + return EvalResult::Allow; + } + + match stability { + Some(DefaultBodyStability { + level: attr::Unstable { reason, issue, is_soft, .. }, + feature, + }) => { + if span.allows_unstable(feature) { + debug!("body stability: skipping span={:?} since it is internal", span); + return EvalResult::Allow; + } + if self.features().active(feature) { + return EvalResult::Allow; + } + + EvalResult::Deny { + feature, + reason: reason.to_opt_reason(), + issue, + suggestion: None, + is_soft, + } + } + Some(_) => { + // Stable APIs are always ok to call + EvalResult::Allow + } + None => EvalResult::Unmarked, + } + } + /// Checks if an item is stable or error out. /// /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 78080fcd5..752cbdeae 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -86,7 +86,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`]. /// All other methods that allow you to mutate the basic blocks also call this method - /// themselves, thereby avoiding any risk of accidentaly cache invalidation. + /// themselves, thereby avoiding any risk of accidentally cache invalidation. pub fn invalidate_cfg_cache(&mut self) { self.predecessor_cache.invalidate(); self.switch_source_cache.invalidate(); diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index f3621cd99..d1f3561c0 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -12,14 +12,14 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Grap // Nodes let nodes: Vec = body - .basic_blocks() + .basic_blocks .iter_enumerated() .map(|(block, _)| bb_to_graph_node(block, body, dark_mode)) .collect(); // Edges let mut edges = Vec::new(); - for (source, _) in body.basic_blocks().iter_enumerated() { + for (source, _) in body.basic_blocks.iter_enumerated() { let def_id = body.source.def_id(); let terminator = body[source].terminator(); let labels = terminator.kind.fmt_successor_labels(); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index db7e0fb8a..37ec04b07 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -16,8 +16,8 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance, - ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, ScalarSizeMismatch, UndefinedBehaviorInfo, - UninitBytesAccess, UnsupportedOpInfo, + ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, + UnsupportedOpInfo, }; use crate::ty; @@ -34,11 +34,11 @@ pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. bytes: Box<[u8]>, - /// Maps from byte addresses to extra data for each pointer. + /// Maps from byte addresses to extra provenance data for each pointer. /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting /// at the given offset. - relocations: Relocations, + provenance: ProvenanceMap, /// Denotes which part of this allocation is initialized. init_mask: InitMask, /// The alignment of the allocation to detect unaligned reads. @@ -84,7 +84,7 @@ impl hash::Hash for Allocation { } // Hash the other fields as usual. - self.relocations.hash(state); + self.provenance.hash(state); self.init_mask.hash(state); self.align.hash(state); self.mutability.hash(state); @@ -130,6 +130,8 @@ pub enum AllocError { ReadPointerAsBytes, /// Partially overwriting a pointer. PartialPointerOverwrite(Size), + /// Partially copying a pointer. + PartialPointerCopy(Size), /// Using uninitialized data where it is not allowed. InvalidUninitBytes(Option), } @@ -152,6 +154,9 @@ impl AllocError { PartialPointerOverwrite(offset) => InterpError::Unsupported( UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)), ), + PartialPointerCopy(offset) => InterpError::Unsupported( + UnsupportedOpInfo::PartialPointerCopy(Pointer::new(alloc_id, offset)), + ), InvalidUninitBytes(info) => InterpError::UndefinedBehavior( UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))), ), @@ -211,7 +216,7 @@ impl Allocation { let size = Size::from_bytes(bytes.len()); Self { bytes, - relocations: Relocations::new(), + provenance: ProvenanceMap::new(), init_mask: InitMask::new(size, true), align, mutability, @@ -246,7 +251,7 @@ impl Allocation { let bytes = unsafe { bytes.assume_init() }; Ok(Allocation { bytes, - relocations: Relocations::new(), + provenance: ProvenanceMap::new(), init_mask: InitMask::new(size, false), align, mutability: Mutability::Mut, @@ -266,22 +271,22 @@ impl Allocation { ) -> Result, Err> { // Compute new pointer provenance, which also adjusts the bytes. let mut bytes = self.bytes; - let mut new_relocations = Vec::with_capacity(self.relocations.0.len()); + let mut new_provenance = Vec::with_capacity(self.provenance.0.len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); let endian = cx.data_layout().endian; - for &(offset, alloc_id) in self.relocations.iter() { + for &(offset, alloc_id) in self.provenance.iter() { let idx = offset.bytes_usize(); let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); let (ptr_prov, ptr_offset) = adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); - new_relocations.push((offset, ptr_prov)); + new_provenance.push((offset, ptr_prov)); } // Create allocation. Ok(Allocation { bytes, - relocations: Relocations::from_presorted(new_relocations), + provenance: ProvenanceMap::from_presorted(new_provenance), init_mask: self.init_mask, align: self.align, mutability: self.mutability, @@ -300,8 +305,8 @@ impl Allocation { Size::from_bytes(self.len()) } - /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs - /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the + /// Looks at a slice which may contain uninitialized bytes or provenance. This differs + /// from `get_bytes_with_uninit_and_ptr` in that it does no provenance checks (even on the /// edges) at all. /// This must not be used for reads affecting the interpreter execution. pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range) -> &[u8] { @@ -313,74 +318,47 @@ impl Allocation { &self.init_mask } - /// Returns the relocation list. - pub fn relocations(&self) -> &Relocations { - &self.relocations + /// Returns the provenance map. + pub fn provenance(&self) -> &ProvenanceMap { + &self.provenance } } /// Byte accessors. impl Allocation { /// This is the entirely abstraction-violating way to just grab the raw bytes without - /// caring about relocations. It just deduplicates some code between `read_scalar` - /// and `get_bytes_internal`. - fn get_bytes_even_more_internal(&self, range: AllocRange) -> &[u8] { - &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()] - } - - /// The last argument controls whether we error out when there are uninitialized or pointer - /// bytes. However, we *always* error when there are relocations overlapping the edges of the - /// range. - /// - /// You should never call this, call `get_bytes` or `get_bytes_with_uninit_and_ptr` instead, + /// caring about provenance or initialization. /// /// This function also guarantees that the resulting pointer will remain stable /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies /// on that. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - fn get_bytes_internal( - &self, - cx: &impl HasDataLayout, - range: AllocRange, - check_init_and_ptr: bool, - ) -> AllocResult<&[u8]> { - if check_init_and_ptr { - self.check_init(range)?; - self.check_relocations(cx, range)?; - } else { - // We still don't want relocations on the *edges*. - self.check_relocation_edges(cx, range)?; - } - - Ok(self.get_bytes_even_more_internal(range)) + #[inline] + pub fn get_bytes_unchecked(&self, range: AllocRange) -> &[u8] { + &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()] } - /// Checks that these bytes are initialized and not pointer bytes, and then return them - /// as a slice. + /// Checks that these bytes are initialized, and then strip provenance (if possible) and return + /// them. /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods /// on `InterpCx` instead. #[inline] - pub fn get_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult<&[u8]> { - self.get_bytes_internal(cx, range, true) - } - - /// It is the caller's responsibility to handle uninitialized and pointer bytes. - /// However, this still checks that there are no relocations on the *edges*. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - #[inline] - pub fn get_bytes_with_uninit_and_ptr( + pub fn get_bytes_strip_provenance( &self, cx: &impl HasDataLayout, range: AllocRange, ) -> AllocResult<&[u8]> { - self.get_bytes_internal(cx, range, false) + self.check_init(range)?; + if !Prov::OFFSET_IS_ADDR { + if self.range_has_provenance(cx, range) { + return Err(AllocError::ReadPointerAsBytes); + } + } + Ok(self.get_bytes_unchecked(range)) } - /// Just calling this already marks everything as defined and removes relocations, + /// Just calling this already marks everything as defined and removes provenance, /// so be sure to actually put data there! /// /// It is the caller's responsibility to check bounds and alignment beforehand. @@ -392,7 +370,7 @@ impl Allocation { range: AllocRange, ) -> AllocResult<&mut [u8]> { self.mark_init(range, true); - self.clear_relocations(cx, range)?; + self.clear_provenance(cx, range)?; Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]) } @@ -404,7 +382,7 @@ impl Allocation { range: AllocRange, ) -> AllocResult<*mut [u8]> { self.mark_init(range, true); - self.clear_relocations(cx, range)?; + self.clear_provenance(cx, range)?; assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); @@ -415,28 +393,6 @@ impl Allocation { /// Reading and writing. impl Allocation { - /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a - /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the - /// given range contains no uninitialized bytes/relocations. - pub fn check_bytes( - &self, - cx: &impl HasDataLayout, - range: AllocRange, - allow_uninit: bool, - allow_ptr: bool, - ) -> AllocResult { - // Check bounds and relocations on the edges. - self.get_bytes_with_uninit_and_ptr(cx, range)?; - // Check uninit and ptr. - if !allow_uninit { - self.check_init(range)?; - } - if !allow_ptr { - self.check_relocations(cx, range)?; - } - Ok(()) - } - /// Reads a *non-ZST* scalar. /// /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine @@ -452,47 +408,55 @@ impl Allocation { cx: &impl HasDataLayout, range: AllocRange, read_provenance: bool, - ) -> AllocResult> { - if read_provenance { - assert_eq!(range.size, cx.data_layout().pointer_size); - } - + ) -> AllocResult> { // First and foremost, if anything is uninit, bail. if self.is_init(range).is_err() { - // This inflates uninitialized bytes to the entire scalar, even if only a few - // bytes are uninitialized. - return Ok(ScalarMaybeUninit::Uninit); + return Err(AllocError::InvalidUninitBytes(None)); } - // If we are doing a pointer read, and there is a relocation exactly where we - // are reading, then we can put data and relocation back together and return that. - if read_provenance && let Some(&prov) = self.relocations.get(&range.start) { - // We already checked init and relocations, so we can use this function. - let bytes = self.get_bytes_even_more_internal(range); - let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - let ptr = Pointer::new(prov, Size::from_bytes(bits)); - return Ok(ScalarMaybeUninit::from_pointer(ptr, cx)); - } + // Get the integer part of the result. We HAVE TO check provenance before returning this! + let bytes = self.get_bytes_unchecked(range); + let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - // If we are *not* reading a pointer, and we can just ignore relocations, - // then do exactly that. - if !read_provenance && Prov::OFFSET_IS_ADDR { - // We just strip provenance. - let bytes = self.get_bytes_even_more_internal(range); - let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - return Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size))); + if read_provenance { + assert_eq!(range.size, cx.data_layout().pointer_size); + + // When reading data with provenance, the easy case is finding provenance exactly where we + // are reading, then we can put data and provenance back together and return that. + if let Some(&prov) = self.provenance.get(&range.start) { + // Now we can return the bits, with their appropriate provenance. + let ptr = Pointer::new(prov, Size::from_bytes(bits)); + return Ok(Scalar::from_pointer(ptr, cx)); + } + + // If we can work on pointers byte-wise, join the byte-wise provenances. + if Prov::OFFSET_IS_ADDR { + let mut prov = self.offset_get_provenance(cx, range.start); + for offset in 1..range.size.bytes() { + let this_prov = + self.offset_get_provenance(cx, range.start + Size::from_bytes(offset)); + prov = Prov::join(prov, this_prov); + } + // Now use this provenance. + let ptr = Pointer::new(prov, Size::from_bytes(bits)); + return Ok(Scalar::from_maybe_pointer(ptr, cx)); + } + } else { + // We are *not* reading a pointer. + // If we can just ignore provenance, do exactly that. + if Prov::OFFSET_IS_ADDR { + // We just strip provenance. + return Ok(Scalar::from_uint(bits, range.size)); + } } - // It's complicated. Better make sure there is no provenance anywhere. - // FIXME: If !OFFSET_IS_ADDR, this is the best we can do. But if OFFSET_IS_ADDR, then - // `read_pointer` is true and we ideally would distinguish the following two cases: - // - The entire `range` is covered by 2 relocations for the same provenance. - // Then we should return a pointer with that provenance. - // - The range has inhomogeneous provenance. Then we should return just the - // underlying bits. - let bytes = self.get_bytes(cx, range)?; - let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size))) + // Fallback path for when we cannot treat provenance bytewise or ignore it. + assert!(!Prov::OFFSET_IS_ADDR); + if self.range_has_provenance(cx, range) { + return Err(AllocError::ReadPointerAsBytes); + } + // There is no provenance, we can just return the bits. + Ok(Scalar::from_uint(bits, range.size)) } /// Writes a *non-ZST* scalar. @@ -507,17 +471,10 @@ impl Allocation { &mut self, cx: &impl HasDataLayout, range: AllocRange, - val: ScalarMaybeUninit, + val: Scalar, ) -> AllocResult { assert!(self.mutability == Mutability::Mut); - let val = match val { - ScalarMaybeUninit::Scalar(scalar) => scalar, - ScalarMaybeUninit::Uninit => { - return self.write_uninit(cx, range); - } - }; - // `to_bits_or_ptr_internal` is the right method because we just want to store this data // as-is into memory. let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { @@ -532,9 +489,9 @@ impl Allocation { let dst = self.get_bytes_mut(cx, range)?; write_target_uint(endian, dst, bytes).unwrap(); - // See if we have to also write a relocation. + // See if we have to also store some provenance. if let Some(provenance) = provenance { - self.relocations.0.insert(range.start, provenance); + self.provenance.0.insert(range.start, provenance); } Ok(()) @@ -543,64 +500,65 @@ impl Allocation { /// Write "uninit" to the given memory range. pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { self.mark_init(range, false); - self.clear_relocations(cx, range)?; + self.clear_provenance(cx, range)?; return Ok(()); } } -/// Relocations. +/// Provenance. impl Allocation { - /// Returns all relocations overlapping with the given pointer-offset pair. - fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] { + /// Returns all provenance overlapping with the given pointer-offset pair. + fn range_get_provenance(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); - self.relocations.range(Size::from_bytes(start)..range.end()) + self.provenance.range(Size::from_bytes(start)..range.end()) } - /// Returns whether this allocation has relocations overlapping with the given range. - /// - /// Note: this function exists to allow `get_relocations` to be private, in order to somewhat - /// limit access to relocations outside of the `Allocation` abstraction. - /// - pub fn has_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool { - !self.get_relocations(cx, range).is_empty() + /// Get the provenance of a single byte. + fn offset_get_provenance(&self, cx: &impl HasDataLayout, offset: Size) -> Option { + let prov = self.range_get_provenance(cx, alloc_range(offset, Size::from_bytes(1))); + assert!(prov.len() <= 1); + prov.first().map(|(_offset, prov)| *prov) } - /// Checks that there are no relocations overlapping with the given range. - #[inline(always)] - fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { - if self.has_relocations(cx, range) { Err(AllocError::ReadPointerAsBytes) } else { Ok(()) } + /// Returns whether this allocation has progrnance overlapping with the given range. + /// + /// Note: this function exists to allow `range_get_provenance` to be private, in order to somewhat + /// limit access to provenance outside of the `Allocation` abstraction. + /// + pub fn range_has_provenance(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool { + !self.range_get_provenance(cx, range).is_empty() } - /// Removes all relocations inside the given range. - /// If there are relocations overlapping with the edges, they + /// Removes all provenance inside the given range. + /// If there is provenance overlapping with the edges, it /// are removed as well *and* the bytes they cover are marked as /// uninitialized. This is a somewhat odd "spooky action at a distance", /// but it allows strictly more code to run than if we would just error /// immediately in that case. - fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult + fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult where Prov: Provenance, { - // Find the start and end of the given range and its outermost relocations. + // Find the start and end of the given range and its outermost provenance. let (first, last) = { - // Find all relocations overlapping the given range. - let relocations = self.get_relocations(cx, range); - if relocations.is_empty() { + // Find all provenance overlapping the given range. + let provenance = self.range_get_provenance(cx, range); + if provenance.is_empty() { return Ok(()); } ( - relocations.first().unwrap().0, - relocations.last().unwrap().0 + cx.data_layout().pointer_size, + provenance.first().unwrap().0, + provenance.last().unwrap().0 + cx.data_layout().pointer_size, ) }; let start = range.start; let end = range.end(); - // We need to handle clearing the relocations from parts of a pointer. - // FIXME: Miri should preserve partial relocations; see + // We need to handle clearing the provenance from parts of a pointer. + // FIXME: Miri should preserve partial provenance; see // https://github.com/rust-lang/miri/issues/2181. if first < start { if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE { @@ -623,41 +581,32 @@ impl Allocation { self.init_mask.set_range(end, last, false); } - // Forget all the relocations. - // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine, - // i.e., this will not remove any other relocations just after the ones we care about. - self.relocations.0.remove_range(first..last); + // Forget all the provenance. + // Since provenance do not overlap, we know that removing until `last` (exclusive) is fine, + // i.e., this will not remove any other provenance just after the ones we care about. + self.provenance.0.remove_range(first..last); Ok(()) } - - /// Errors if there are relocations overlapping with the edges of the - /// given memory range. - #[inline] - fn check_relocation_edges(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { - self.check_relocations(cx, alloc_range(range.start, Size::ZERO))?; - self.check_relocations(cx, alloc_range(range.end(), Size::ZERO))?; - Ok(()) - } } -/// "Relocations" stores the provenance information of pointers stored in memory. +/// Stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -pub struct Relocations(SortedMap); +pub struct ProvenanceMap(SortedMap); -impl Relocations { +impl ProvenanceMap { pub fn new() -> Self { - Relocations(SortedMap::new()) + ProvenanceMap(SortedMap::new()) } - // The caller must guarantee that the given relocations are already sorted + // The caller must guarantee that the given provenance list is already sorted // by address and contain no duplicates. pub fn from_presorted(r: Vec<(Size, Prov)>) -> Self { - Relocations(SortedMap::from_presorted_elements(r)) + ProvenanceMap(SortedMap::from_presorted_elements(r)) } } -impl Deref for Relocations { +impl Deref for ProvenanceMap { type Target = SortedMap; fn deref(&self) -> &Self::Target { @@ -665,36 +614,36 @@ impl Deref for Relocations { } } -/// A partial, owned list of relocations to transfer into another allocation. +/// A partial, owned list of provenance to transfer into another allocation. /// /// Offsets are already adjusted to the destination allocation. -pub struct AllocationRelocations { - dest_relocations: Vec<(Size, Prov)>, +pub struct AllocationProvenance { + dest_provenance: Vec<(Size, Prov)>, } impl Allocation { - pub fn prepare_relocation_copy( + pub fn prepare_provenance_copy( &self, cx: &impl HasDataLayout, src: AllocRange, dest: Size, count: u64, - ) -> AllocationRelocations { - let relocations = self.get_relocations(cx, src); - if relocations.is_empty() { - return AllocationRelocations { dest_relocations: Vec::new() }; + ) -> AllocationProvenance { + let provenance = self.range_get_provenance(cx, src); + if provenance.is_empty() { + return AllocationProvenance { dest_provenance: Vec::new() }; } let size = src.size; - let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize)); + let mut new_provenance = Vec::with_capacity(provenance.len() * (count as usize)); // If `count` is large, this is rather wasteful -- we are allocating a big array here, which // is mostly filled with redundant information since it's just N copies of the same `Prov`s - // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range` + // at slightly adjusted offsets. The reason we do this is so that in `mark_provenance_range` // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces - // the right sequence of relocations for all N copies. + // the right sequence of provenance for all N copies. for i in 0..count { - new_relocations.extend(relocations.iter().map(|&(offset, reloc)| { + new_provenance.extend(provenance.iter().map(|&(offset, reloc)| { // compute offset for current repetition let dest_offset = dest + size * i; // `Size` operations ( @@ -705,17 +654,17 @@ impl Allocation { })); } - AllocationRelocations { dest_relocations: new_relocations } + AllocationProvenance { dest_provenance: new_provenance } } - /// Applies a relocation copy. - /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected - /// to be clear of relocations. + /// Applies a provenance copy. + /// The affected range, as defined in the parameters to `prepare_provenance_copy` is expected + /// to be clear of provenance. /// /// This is dangerous to use as it can violate internal `Allocation` invariants! /// It only exists to support an efficient implementation of `mem_copy_repeatedly`. - pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations) { - self.relocations.0.insert_presorted(relocations.dest_relocations); + pub fn mark_provenance_range(&mut self, provenance: AllocationProvenance) { + self.provenance.0.insert_presorted(provenance.dest_provenance); } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index cecb55578..e4039cc7c 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -401,14 +401,18 @@ impl fmt::Display for UndefinedBehaviorInfo { pub enum UnsupportedOpInfo { /// Free-form case. Only for errors that are never caught! Unsupported(String), - /// Encountered a pointer where we needed raw bytes. - ReadPointerAsBytes, /// Overwriting parts of a pointer; the resulting state cannot be represented in our /// `Allocation` data structure. See . PartialPointerOverwrite(Pointer), + /// Attempting to `copy` parts of a pointer to somewhere else; the resulting state cannot be + /// represented in our `Allocation` data structure. See + /// . + PartialPointerCopy(Pointer), // // The variants below are only reachable from CTFE/const prop, miri will never emit them. // + /// Encountered a pointer where we needed raw bytes. + ReadPointerAsBytes, /// Accessing thread local statics ThreadLocalStatic(DefId), /// Accessing an unsupported extern static. @@ -420,10 +424,13 @@ impl fmt::Display for UnsupportedOpInfo { use UnsupportedOpInfo::*; match self { Unsupported(ref msg) => write!(f, "{msg}"), - ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"), PartialPointerOverwrite(ptr) => { write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}") } + PartialPointerCopy(ptr) => { + write!(f, "unable to copy parts of a pointer from memory at {ptr:?}") + } + ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"), ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"), ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"), } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 967f8ece1..5e3dfcbcc 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -124,11 +124,11 @@ pub use self::error::{ UninitBytesAccess, UnsupportedOpInfo, }; -pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; +pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; pub use self::allocation::{ alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask, - Relocations, + ProvenanceMap, }; pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; @@ -137,7 +137,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; /// - A constant /// - A static #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, Lift)] +#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct GlobalId<'tcx> { /// For a constant or static, the `Instance` of the item itself. /// For a promoted global, the `Instance` of the function they belong to. diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 384954cbb..95e52e391 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -107,8 +107,12 @@ impl PointerArithmetic for T {} /// pointer), but `derive` adds some unnecessary bounds. pub trait Provenance: Copy + fmt::Debug { /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address. - /// If `true, ptr-to-int casts work by simply discarding the provenance. - /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case. + /// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are + /// different from what the Abstract Machine prescribes, so the interpreter must prevent any + /// operation that would inspect the underlying bytes of a pointer, such as ptr-to-int + /// transmutation. A `ReadPointerAsBytes` error will be raised in such situations. + /// - If `true`, the interpreter will permit operations to inspect the underlying bytes of a + /// pointer, and implement ptr-to-int transmutation by stripping provenance. const OFFSET_IS_ADDR: bool; /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten @@ -125,6 +129,9 @@ pub trait Provenance: Copy + fmt::Debug { /// Otherwise this function is best-effort (but must agree with `Machine::ptr_get_alloc`). /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.) fn get_alloc_id(self) -> Option; + + /// Defines the 'join' of provenance: what happens when doing a pointer load and different bytes have different provenance. + fn join(left: Option, right: Option) -> Option; } impl Provenance for AllocId { @@ -152,6 +159,10 @@ impl Provenance for AllocId { fn get_alloc_id(self) -> Option { Some(self) } + + fn join(_left: Option, _right: Option) -> Option { + panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false") + } } /// Represents a pointer in the Miri engine. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 786927e2d..4207988d7 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -63,7 +63,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_eval_resolve_for_typeck( self, param_env: ty::ParamEnv<'tcx>, - ct: ty::Unevaluated<'tcx>, + ct: ty::Unevaluated<'tcx, ()>, span: Option, ) -> EvalToValTreeResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference @@ -78,7 +78,7 @@ impl<'tcx> TyCtxt<'tcx> { match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { Ok(Some(instance)) => { - let cid = GlobalId { instance, promoted: ct.promoted }; + let cid = GlobalId { instance, promoted: None }; self.const_eval_global_id_for_typeck(param_env, cid, span) } Ok(None) => Err(ErrorHandled::TooGeneric), diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 834c114ee..ac5fddb7a 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -8,7 +8,7 @@ use rustc_apfloat::{ use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; -use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; +use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; use super::{ AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance, @@ -27,7 +27,7 @@ pub struct ConstAlloc<'tcx> { /// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for /// array length computations, enum discriminants and the pattern matching logic. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] -#[derive(HashStable)] +#[derive(HashStable, Lift)] pub enum ConstValue<'tcx> { /// Used only for types with `layout::abi::Scalar` ABI. /// @@ -53,22 +53,6 @@ pub enum ConstValue<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ConstValue<'_>, 32); -impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { - type Lifted = ConstValue<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - Some(match self { - ConstValue::Scalar(s) => ConstValue::Scalar(s), - ConstValue::ZeroSized => ConstValue::ZeroSized, - ConstValue::Slice { data, start, end } => { - ConstValue::Slice { data: tcx.lift(data)?, start, end } - } - ConstValue::ByRef { alloc, offset } => { - ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset } - } - }) - } -} - impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option> { @@ -79,7 +63,7 @@ impl<'tcx> ConstValue<'tcx> { } pub fn try_to_scalar_int(&self) -> Option { - Some(self.try_to_scalar()?.assert_int()) + self.try_to_scalar()?.try_to_int().ok() } pub fn try_to_bits(&self, size: Size) -> Option { @@ -130,9 +114,7 @@ pub enum Scalar { /// The raw bytes of a simple value. Int(ScalarInt), - /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of - /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the - /// relocation and its associated offset together as a `Pointer` here. + /// A pointer. /// /// We also store the size of the pointer, such that a `Scalar` always knows how big it is. /// The size is always the pointer size of the current target, but this is not information @@ -368,6 +350,7 @@ impl<'tcx, Prov: Provenance> Scalar { } #[inline(always)] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn assert_int(self) -> ScalarInt { self.try_to_int().unwrap() } @@ -389,6 +372,7 @@ impl<'tcx, Prov: Provenance> Scalar { } #[inline(always)] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn assert_bits(self, target_size: Size) -> u128 { self.to_bits(target_size).unwrap() } @@ -502,145 +486,12 @@ impl<'tcx, Prov: Provenance> Scalar { } } -#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] -pub enum ScalarMaybeUninit { - Scalar(Scalar), - Uninit, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ScalarMaybeUninit, 24); - -impl From> for ScalarMaybeUninit { - #[inline(always)] - fn from(s: Scalar) -> Self { - ScalarMaybeUninit::Scalar(s) - } -} - -// We want the `Debug` output to be readable as it is used by `derive(Debug)` for -// all the Miri types. -impl fmt::Debug for ScalarMaybeUninit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUninit::Uninit => write!(f, ""), - ScalarMaybeUninit::Scalar(s) => write!(f, "{:?}", s), - } - } -} - -impl fmt::LowerHex for ScalarMaybeUninit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), - ScalarMaybeUninit::Scalar(s) => write!(f, "{:x}", s), - } - } -} - -impl ScalarMaybeUninit { - #[inline] - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { - ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx)) - } - - #[inline] - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { - ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx)) - } - - #[inline] - pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { - match self { - ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), - ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), - } - } -} - -impl<'tcx, Prov: Provenance> ScalarMaybeUninit { - #[inline(always)] - pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer>> { - self.check_init()?.to_pointer(cx) - } - - #[inline(always)] - pub fn to_bool(self) -> InterpResult<'tcx, bool> { - self.check_init()?.to_bool() - } - - #[inline(always)] - pub fn to_char(self) -> InterpResult<'tcx, char> { - self.check_init()?.to_char() - } - - #[inline(always)] - pub fn to_f32(self) -> InterpResult<'tcx, Single> { - self.check_init()?.to_f32() - } - - #[inline(always)] - pub fn to_f64(self) -> InterpResult<'tcx, Double> { - self.check_init()?.to_f64() - } - - #[inline(always)] - pub fn to_u8(self) -> InterpResult<'tcx, u8> { - self.check_init()?.to_u8() - } - - #[inline(always)] - pub fn to_u16(self) -> InterpResult<'tcx, u16> { - self.check_init()?.to_u16() - } - - #[inline(always)] - pub fn to_u32(self) -> InterpResult<'tcx, u32> { - self.check_init()?.to_u32() - } - - #[inline(always)] - pub fn to_u64(self) -> InterpResult<'tcx, u64> { - self.check_init()?.to_u64() - } - - #[inline(always)] - pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { - self.check_init()?.to_machine_usize(cx) - } - - #[inline(always)] - pub fn to_i8(self) -> InterpResult<'tcx, i8> { - self.check_init()?.to_i8() - } - - #[inline(always)] - pub fn to_i16(self) -> InterpResult<'tcx, i16> { - self.check_init()?.to_i16() - } - - #[inline(always)] - pub fn to_i32(self) -> InterpResult<'tcx, i32> { - self.check_init()?.to_i32() - } - - #[inline(always)] - pub fn to_i64(self) -> InterpResult<'tcx, i64> { - self.check_init()?.to_i64() - } - - #[inline(always)] - pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { - self.check_init()?.to_machine_isize(cx) - } -} - /// Gets the bytes of a constant slice value. pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { if let ConstValue::Slice { data, start, end } = val { let len = end - start; data.inner() - .get_bytes( + .get_bytes_strip_provenance( cx, AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) }, ) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7ab71f900..3d7a6230e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::interpret::{ - AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar, + AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, LitToConstInput, Scalar, }; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -18,7 +18,7 @@ use rustc_data_structures::captures::Captures; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_hir::{self, GeneratorKind}; +use rustc_hir::{self, GeneratorKind, ImplicitSelfKind}; use rustc_hir::{self as hir, HirId}; use rustc_session::Session; use rustc_target::abi::{Size, VariantIdx}; @@ -128,8 +128,20 @@ pub trait MirPass<'tcx> { impl MirPhase { /// Gets the index of the current MirPhase within the set of all `MirPhase`s. + /// + /// FIXME(JakobDegen): Return a `(usize, usize)` instead. pub fn phase_index(&self) -> usize { - *self as usize + const BUILT_PHASE_COUNT: usize = 1; + const ANALYSIS_PHASE_COUNT: usize = 2; + match self { + MirPhase::Built => 1, + MirPhase::Analysis(analysis_phase) => { + 1 + BUILT_PHASE_COUNT + (*analysis_phase as usize) + } + MirPhase::Runtime(runtime_phase) => { + 1 + BUILT_PHASE_COUNT + ANALYSIS_PHASE_COUNT + (*runtime_phase as usize) + } + } } } @@ -331,11 +343,6 @@ impl<'tcx> Body<'tcx> { body } - #[inline] - pub fn basic_blocks(&self) -> &IndexVec> { - &self.basic_blocks - } - #[inline] pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { self.basic_blocks.as_mut() @@ -490,7 +497,7 @@ impl<'tcx> Index for Body<'tcx> { #[inline] fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { - &self.basic_blocks()[index] + &self.basic_blocks[index] } } @@ -646,22 +653,6 @@ pub enum BindingForm<'tcx> { RefForGuard, } -/// Represents what type of implicit self a function has, if any. -#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -pub enum ImplicitSelfKind { - /// Represents a `fn x(self);`. - Imm, - /// Represents a `fn x(mut self);`. - Mut, - /// Represents a `fn x(&self);`. - ImmRef, - /// Represents a `fn x(&mut self);`. - MutRef, - /// Represents when a function does not have a self argument or - /// when a function has a `self: X` argument. - None, -} - TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { @@ -832,10 +823,6 @@ pub struct LocalDecl<'tcx> { pub source_info: SourceInfo, } -// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(LocalDecl<'_>, 56); - /// Extra information about a some locals that's used for diagnostics and for /// classifying variables into local variables, statics, etc, which is needed e.g. /// for unsafety checking. @@ -1310,10 +1297,6 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } -// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Statement<'_>, 32); - impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. @@ -1363,13 +1346,7 @@ impl Debug for Statement<'_> { write!(fmt, "Coverage::{:?} for {:?}", kind, rgn) } Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind), - CopyNonOverlapping(box crate::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { - write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count) - } + Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), Nop => write!(fmt, "nop"), } } @@ -1450,7 +1427,7 @@ pub struct PlaceRef<'tcx> { // Once we stop implementing `Ord` for `DefId`, // this impl will be unnecessary. Until then, we'll // leave this impl in place to prevent re-adding a -// dependnecy on the `Ord` impl for `DefId` +// dependency on the `Ord` impl for `DefId` impl<'tcx> !PartialOrd for PlaceRef<'tcx> {} impl<'tcx> Place<'tcx> { @@ -1471,7 +1448,9 @@ impl<'tcx> Place<'tcx> { /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { // To make sure this is not accidently used in wrong mir phase - debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref)); + debug_assert!( + self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) + ); self.projection.first() == Some(&PlaceElem::Deref) } @@ -1531,6 +1510,7 @@ impl<'tcx> Place<'tcx> { } impl From for Place<'_> { + #[inline] fn from(local: Local) -> Self { Place { local, projection: List::empty() } } @@ -1838,6 +1818,7 @@ impl<'tcx> Rvalue<'tcx> { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, + Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) @@ -2047,6 +2028,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct Constant<'tcx> { pub span: Span, @@ -2065,6 +2047,10 @@ pub struct Constant<'tcx> { pub enum ConstantKind<'tcx> { /// This constant came from the type system Ty(ty::Const<'tcx>), + + /// An unevaluated mir constant which is not part of the type system. + Unevaluated(ty::Unevaluated<'tcx, Option>, Ty<'tcx>), + /// This constant cannot go back into the type system, as it represents /// something the type system cannot handle (e.g. pointers). Val(interpret::ConstValue<'tcx>, Ty<'tcx>), @@ -2090,20 +2076,11 @@ impl<'tcx> Constant<'tcx> { } impl<'tcx> ConstantKind<'tcx> { - /// Returns `None` if the constant is not trivially safe for use in the type system. - #[inline] - pub fn const_for_ty(&self) -> Option> { - match self { - ConstantKind::Ty(c) => Some(*c), - ConstantKind::Val(..) => None, - } - } - #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { ConstantKind::Ty(c) => c.ty(), - ConstantKind::Val(_, ty) => *ty, + ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty, } } @@ -2115,6 +2092,7 @@ impl<'tcx> ConstantKind<'tcx> { _ => None, }, ConstantKind::Val(val, _) => Some(val), + ConstantKind::Unevaluated(..) => None, } } @@ -2129,6 +2107,7 @@ impl<'tcx> ConstantKind<'tcx> { _ => None, }, ConstantKind::Val(val, _) => val.try_to_scalar(), + ConstantKind::Unevaluated(..) => None, } } @@ -2161,6 +2140,14 @@ impl<'tcx> ConstantKind<'tcx> { } } Self::Val(_, _) => self, + Self::Unevaluated(uneval, ty) => { + // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` + match tcx.const_eval_resolve(param_env, uneval, None) { + Ok(val) => Self::Val(val, ty), + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self, + Err(_) => Self::Ty(tcx.const_error(ty)), + } + } } } @@ -2186,6 +2173,18 @@ impl<'tcx> ConstantKind<'tcx> { tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; val.try_to_bits(size) } + Self::Unevaluated(uneval, ty) => { + match tcx.const_eval_resolve(param_env, *uneval, None) { + Ok(val) => { + let size = tcx + .layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty)) + .ok()? + .size; + val.try_to_bits(size) + } + Err(_) => None, + } + } } } @@ -2194,6 +2193,12 @@ impl<'tcx> ConstantKind<'tcx> { match self { Self::Ty(ct) => ct.try_eval_bool(tcx, param_env), Self::Val(val, _) => val.try_to_bool(), + Self::Unevaluated(uneval, _) => { + match tcx.const_eval_resolve(param_env, *uneval, None) { + Ok(val) => val.try_to_bool(), + Err(_) => None, + } + } } } @@ -2202,6 +2207,12 @@ impl<'tcx> ConstantKind<'tcx> { match self { Self::Ty(ct) => ct.try_eval_usize(tcx, param_env), Self::Val(val, _) => val.try_to_machine_usize(tcx), + Self::Unevaluated(uneval, _) => { + match tcx.const_eval_resolve(param_env, *uneval, None) { + Ok(val) => val.try_to_machine_usize(tcx), + Err(_) => None, + } + } } } @@ -2259,7 +2270,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) } - #[instrument(skip(tcx), level = "debug")] + #[instrument(skip(tcx), level = "debug", ret)] pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = match tcx.hir().get(hir_id) { @@ -2297,21 +2308,19 @@ impl<'tcx> ConstantKind<'tcx> { let substs = ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) .substs; - let uneval_const = tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id).to_global(), - substs, - promoted: None, - }), - ty, - }); - debug!(?uneval_const); - debug_assert!(!uneval_const.has_free_regions()); - Self::Ty(uneval_const) + let uneval = ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id).to_global(), + substs, + promoted: None, + }; + + debug_assert!(!uneval.has_free_regions()); + + Self::Unevaluated(uneval, ty) } - #[instrument(skip(tcx), level = "debug")] + #[instrument(skip(tcx), level = "debug", ret)] fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -2394,24 +2403,21 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, Some(span)) { Ok(val) => { - debug!("evaluated const value: {:?}", val); + debug!("evaluated const value"); Self::Val(val, ty) } Err(_) => { debug!("error encountered during evaluation"); // Error was handled in `const_eval_resolve`. Here we just create a // new unevaluated const and error hard later in codegen - let ty_const = tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { + Self::Unevaluated( + ty::Unevaluated { def: def.to_global(), substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), promoted: None, - }), + }, ty, - }); - debug!(?ty_const); - - Self::Ty(ty_const) + ) } } } @@ -2422,6 +2428,7 @@ impl<'tcx> ConstantKind<'tcx> { let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); Self::Val(const_val, c.ty()) } + ty::ConstKind::Unevaluated(uv) => Self::Unevaluated(uv.expand(), c.ty()), _ => Self::Ty(c), } } @@ -2576,8 +2583,6 @@ impl UserTypeProjection { } } -TrivialTypeTraversalAndLiftImpls! { ProjectionKind, } - impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { fn try_fold_with>(self, folder: &mut F) -> Result { Ok(UserTypeProjection { @@ -2622,6 +2627,11 @@ impl<'tcx> Display for ConstantKind<'tcx> { match *self { ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + // FIXME(valtrees): Correctly print mir constants. + ConstantKind::Unevaluated(..) => { + fmt.write_str("_")?; + Ok(()) + } } } } @@ -2643,15 +2653,7 @@ fn pretty_print_const<'tcx>( } fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result { - fmt.write_str("b\"")?; - for &c in byte_str { - for e in std::ascii::escape_default(c) { - fmt.write_char(e as char)?; - } - } - fmt.write_str("\"")?; - - Ok(()) + write!(fmt, "b\"{}\"", byte_str.escape_ascii()) } fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec>) -> fmt::Result { @@ -2691,8 +2693,8 @@ fn pretty_print_const_value<'tcx>( match inner.kind() { ty::Slice(t) => { if *t == u8_type { - // The `inspect` here is okay since we checked the bounds, and there are - // no relocations (we have an active slice reference here). We don't use + // The `inspect` here is okay since we checked the bounds, and `u8` carries + // no provenance (we have an active slice reference here). We don't use // this result to affect interpreter execution. let byte_str = data .inner() @@ -2702,8 +2704,8 @@ fn pretty_print_const_value<'tcx>( } } ty::Str => { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this + // The `inspect` here is okay since we checked the bounds, and `str` carries + // no provenance (we have an active `str` reference here). We don't use this // result to affect interpreter execution. let slice = data .inner() @@ -2718,7 +2720,7 @@ fn pretty_print_const_value<'tcx>( let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap(); // cast is ok because we already checked for pointer size (32 or 64 bit) above let range = AllocRange { start: offset, size: Size::from_bytes(n) }; - let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap(); + let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap(); fmt.write_str("*")?; pretty_print_byte_str(fmt, byte_str)?; return Ok(()); @@ -2898,3 +2900,17 @@ impl Location { } } } + +// 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; + // These are in alphabetical order, which is easy to maintain. + static_assert_size!(BasicBlockData<'_>, 144); + static_assert_size!(LocalDecl<'_>, 56); + static_assert_size!(Statement<'_>, 32); + static_assert_size!(StatementKind<'_>, 16); + static_assert_size!(Terminator<'_>, 112); + static_assert_size!(TerminatorKind<'_>, 96); +} diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 15496842d..24fe3b472 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -19,7 +19,7 @@ pub struct MirPatch<'tcx> { impl<'tcx> MirPatch<'tcx> { pub fn new(body: &Body<'tcx>) -> Self { let mut result = MirPatch { - patch_map: IndexVec::from_elem(None, body.basic_blocks()), + patch_map: IndexVec::from_elem(None, &body.basic_blocks), new_blocks: vec![], new_statements: vec![], new_locals: vec![], @@ -29,7 +29,7 @@ impl<'tcx> MirPatch<'tcx> { }; // Check if we already have a resume block - for (bb, block) in body.basic_blocks().iter_enumerated() { + for (bb, block) in body.basic_blocks.iter_enumerated() { if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() { result.resume_block = Some(bb); break; @@ -61,14 +61,14 @@ impl<'tcx> MirPatch<'tcx> { } pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(body.basic_blocks().len()) { + let offset = match bb.index().checked_sub(body.basic_blocks.len()) { Some(index) => self.new_blocks[index].statements.len(), None => body[bb].statements.len(), }; Location { block: bb, statement_index: offset } } - pub fn new_local_with_info( + pub fn new_internal_with_info( &mut self, ty: Ty<'tcx>, span: Span, @@ -76,14 +76,17 @@ impl<'tcx> MirPatch<'tcx> { ) -> Local { let index = self.next_local; self.next_local += 1; - let mut new_decl = LocalDecl::new(ty, span); + let mut new_decl = LocalDecl::new(ty, span).internal(); new_decl.local_info = local_info; self.new_locals.push(new_decl); Local::new(index as usize) } pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { - self.new_local_with_info(ty, span, None) + let index = self.next_local; + self.next_local += 1; + self.new_locals.push(LocalDecl::new(ty, span)); + Local::new(index as usize) } pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { @@ -126,7 +129,7 @@ impl<'tcx> MirPatch<'tcx> { debug!( "MirPatch: {} new blocks, starting from index {}", self.new_blocks.len(), - body.basic_blocks().len() + body.basic_blocks.len() ); let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() { body.basic_blocks.as_mut_preserves_cfg() @@ -147,7 +150,6 @@ impl<'tcx> MirPatch<'tcx> { let mut delta = 0; let mut last_bb = START_BLOCK; - let mut stmts_and_targets: Vec<(Statement<'_>, BasicBlock)> = Vec::new(); for (mut loc, stmt) in new_statements { if loc.block != last_bb { delta = 0; @@ -156,27 +158,11 @@ impl<'tcx> MirPatch<'tcx> { debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); loc.statement_index += delta; let source_info = Self::source_info_for_index(&body[loc.block], loc); - - // For mir-opt `Derefer` to work in all cases we need to - // get terminator's targets and apply the statement to all of them. - if loc.statement_index > body[loc.block].statements.len() { - let term = body[loc.block].terminator(); - for i in term.successors() { - stmts_and_targets.push((Statement { source_info, kind: stmt.clone() }, i)); - } - delta += 1; - continue; - } - body[loc.block] .statements .insert(loc.statement_index, Statement { source_info, kind: stmt }); delta += 1; } - - for (stmt, target) in stmts_and_targets.into_iter().rev() { - body[target].statements.insert(0, stmt); - } } pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { @@ -187,7 +173,7 @@ impl<'tcx> MirPatch<'tcx> { } pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(body.basic_blocks().len()) { + let data = match loc.block.index().checked_sub(body.basic_blocks.len()) { Some(new) => &self.new_blocks[new], None => &body[loc.block], }; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 0ce41337b..0b42137d4 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -318,10 +318,10 @@ where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { write_mir_intro(tcx, body, w)?; - for block in body.basic_blocks().indices() { + for block in body.basic_blocks.indices() { extra_data(PassWhere::BeforeBlock(block), w)?; write_basic_block(tcx, block, body, extra_data, w)?; - if block.index() + 1 != body.basic_blocks().len() { + if block.index() + 1 != body.basic_blocks.len() { writeln!(w)?; } } @@ -464,12 +464,14 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { let val = match literal { ConstantKind::Ty(ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("Param({})", p), - ty::ConstKind::Unevaluated(uv) => format!( - "Unevaluated({}, {:?}, {:?})", - self.tcx.def_path_str(uv.def.did), - uv.substs, - uv.promoted, - ), + ty::ConstKind::Unevaluated(uv) => { + format!( + "Unevaluated({}, {:?}, {:?})", + self.tcx.def_path_str(uv.def.did), + uv.substs, + uv.promoted, + ) + } ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)), ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. @@ -477,6 +479,14 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { | ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal), }, + ConstantKind::Unevaluated(uv, _) => { + format!( + "Unevaluated({}, {:?}, {:?})", + self.tcx.def_path_str(uv.def.did), + uv.substs, + uv.promoted, + ) + } // To keep the diffs small, we render this like we render `ty::Const::Value`. // // This changes once `ty::Const::Value` is represented using valtrees. @@ -676,7 +686,7 @@ pub fn write_allocations<'tcx>( fn alloc_ids_from_alloc( alloc: ConstAllocation<'_>, ) -> impl DoubleEndedIterator + '_ { - alloc.inner().relocations().values().map(|id| *id) + alloc.inner().provenance().values().map(|id| *id) } fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator + '_ { @@ -696,9 +706,9 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) { + fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) { match c.literal { - ConstantKind::Ty(c) => self.visit_const(c, loc), + ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {} ConstantKind::Val(val, _) => { self.0.extend(alloc_ids_from_const_val(val)); } @@ -778,7 +788,7 @@ pub fn write_allocations<'tcx>( /// If the allocation is small enough to fit into a single line, no start address is given. /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` -/// This also prints relocations adequately. +/// This also prints provenance adequately. pub fn display_allocation<'a, 'tcx, Prov, Extra>( tcx: TyCtxt<'tcx>, alloc: &'a Allocation, @@ -873,34 +883,34 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( if i != line_start { write!(w, " ")?; } - if let Some(&prov) = alloc.relocations().get(&i) { - // Memory with a relocation must be defined + if let Some(&prov) = alloc.provenance().get(&i) { + // Memory with provenance must be defined assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok()); let j = i.bytes_usize(); let offset = alloc .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); let offset = Size::from_bytes(offset); - let relocation_width = |bytes| bytes * 3; + let provenance_width = |bytes| bytes * 3; let ptr = Pointer::new(prov, offset); let mut target = format!("{:?}", ptr); - if target.len() > relocation_width(ptr_size.bytes_usize() - 1) { + if target.len() > provenance_width(ptr_size.bytes_usize() - 1) { // This is too long, try to save some space. target = format!("{:#?}", ptr); } if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE { - // This branch handles the situation where a relocation starts in the current line + // This branch handles the situation where a provenance starts in the current line // but ends in the next one. let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start); let overflow = ptr_size - remainder; - let remainder_width = relocation_width(remainder.bytes_usize()) - 2; - let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1; + let remainder_width = provenance_width(remainder.bytes_usize()) - 2; + let overflow_width = provenance_width(overflow.bytes_usize() - 1) + 1; ascii.push('╾'); for _ in 0..remainder.bytes() - 1 { ascii.push('─'); } if overflow_width > remainder_width && overflow_width >= target.len() { - // The case where the relocation fits into the part in the next line + // The case where the provenance fits into the part in the next line write!(w, "╾{0:─^1$}", "", remainder_width)?; line_start = write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?; @@ -921,11 +931,11 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( i += ptr_size; continue; } else { - // This branch handles a relocation that starts and ends in the current line. - let relocation_width = relocation_width(ptr_size.bytes_usize() - 1); - oversized_ptr(&mut target, relocation_width); + // This branch handles a provenance that starts and ends in the current line. + let provenance_width = provenance_width(ptr_size.bytes_usize() - 1); + oversized_ptr(&mut target, provenance_width); ascii.push('╾'); - write!(w, "╾{0:─^1$}╼", target, relocation_width)?; + write!(w, "╾{0:─^1$}╼", target, provenance_width)?; for _ in 0..ptr_size.bytes() - 2 { ascii.push('─'); } @@ -935,7 +945,7 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( } else if alloc.init_mask().is_range_initialized(i, i + Size::from_bytes(1)).is_ok() { let j = i.bytes_usize(); - // Checked definedness (and thus range) and relocations. This access also doesn't + // Checked definedness (and thus range) and provenance. This access also doesn't // influence interpreter execution but is only for debugging. let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; write!(w, "{:02x}", c)?; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index dd9f8795f..d89efe2b3 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,7 +2,7 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -115,21 +115,6 @@ pub enum UnusedUnsafe { /// `unsafe` block nested under another (used) `unsafe` block /// > ``… because it's nested under this `unsafe` block`` InUnsafeBlock(hir::HirId), - /// `unsafe` block nested under `unsafe fn` - /// > ``… because it's nested under this `unsafe fn` `` - /// - /// the second HirId here indicates the first usage of the `unsafe` block, - /// which allows retrieval of the LintLevelSource for why that operation would - /// have been permitted without the block - InUnsafeFn(hir::HirId, hir::HirId), -} - -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] -pub enum UsedUnsafeBlockData { - SomeDisallowedInUnsafeFn, - // the HirId here indicates the first usage of the `unsafe` block - // (i.e. the one that's first encountered in the MIR traversal of the unsafety check) - AllAllowedInUnsafeFn(hir::HirId), } #[derive(TyEncodable, TyDecodable, HashStable, Debug)] @@ -138,10 +123,7 @@ pub struct UnsafetyCheckResult { pub violations: Vec, /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint. - /// - /// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether - /// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`. - pub used_unsafe_blocks: FxHashMap, + pub used_unsafe_blocks: FxHashSet, /// This is `Some` iff the item is not a closure. pub unused_unsafes: Option>, @@ -345,7 +327,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] +#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, @@ -387,7 +369,7 @@ pub enum ConstraintCategory<'tcx> { } #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ReturnConstraint { Normal, ClosureUpvar(Field), diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 4418b848e..4e06d9101 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -105,7 +105,7 @@ where } let body_span = hir_body.unwrap().value.span; let mut span_viewables = Vec::new(); - for (bb, data) in body.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks.iter_enumerated() { match spanview { MirSpanview::Statement => { for (i, statement) in data.statements.iter().enumerate() { @@ -249,7 +249,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { Retag(..) => "Retag", AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", - CopyNonOverlapping(..) => "CopyNonOverlapping", + Intrinsic(..) => "Intrinsic", Nop => "Nop", } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index eb90169d0..c7d0283aa 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -23,75 +23,110 @@ use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::asm::InlineAsmRegOrRegClass; -/// The various "big phases" that MIR goes through. +/// Represents the "flavors" of MIR. /// -/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the -/// dialects forbid certain variants or values in certain phases. The sections below summarize the -/// changes, but do not document them thoroughly. The full documentation is found in the appropriate -/// documentation for the thing the change is affecting. +/// All flavors of MIR use the same data structure, but there are some important differences. These +/// differences come in two forms: Dialects and phases. /// -/// Warning: ordering of variants is significant. +/// Dialects represent a stronger distinction than phases. This is because the transitions between +/// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In +/// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but +/// have different semantic meaning and different behavior at runtime. +/// +/// Each dialect additionally has a number of phases. However, phase changes never involve semantic +/// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed +/// that it has the same semantic meaning. In this sense, phase changes can only add additional +/// restrictions on what MIR is well-formed. +/// +/// When adding phases, remember to update [`MirPhase::phase_index`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] pub enum MirPhase { - /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also - /// the MIR that analysis such as borrowck uses. - /// - /// One important thing to remember about the behavior of this section of MIR is that drop terminators - /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each - /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop - /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize - /// when things are initialized and when things are de-initialized. That means any code running on this - /// version of MIR must be sure to produce output that drop elaboration can reason about. See the - /// section on the drop terminatorss for more details. - Built = 0, - // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). - // We used to have this for pre-miri MIR based const eval. - Const = 1, - /// This phase checks the MIR for promotable elements and takes them out of the main MIR body - /// by creating a new MIR body per promoted element. After this phase (and thus the termination - /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` - /// query. - ConstsPromoted = 2, - /// After this projections may only contain deref projections as the first element. - Derefered = 3, - /// Beginning with this phase, the following variants are disallowed: - /// * [`TerminatorKind::DropAndReplace`] + /// The MIR that is generated by MIR building. + /// + /// The only things that operate on this dialect are unsafeck, the various MIR lints, and const + /// qualifs. + /// + /// This has no distinct phases. + Built, + /// The MIR used for most analysis. + /// + /// The only semantic change between analysis and built MIR is constant promotion. In built MIR, + /// sequences of statements that would generally be subject to constant promotion are + /// semantically constants, while in analysis MIR all constants are explicit. + /// + /// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries. + /// + /// This is the version of MIR used by borrowck and friends. + Analysis(AnalysisPhase), + /// The MIR used for CTFE, optimizations, and codegen. + /// + /// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows: + /// + /// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking, + /// if dataflow analysis determines that the place being dropped is uninitialized, the drop will + /// not be executed. The exact semantics of this aren't written down anywhere, which means they + /// are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional; + /// when a `Drop` terminator is reached, if the type has drop glue that drop glue is always + /// executed. This may be UB if the underlying place is not initialized. + /// - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception + /// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned + /// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such + /// rules, and dropping a misaligned place is simply UB. + /// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime + /// MIR, this is UB. + /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way + /// that Rust itself has them. Where exactly these are is generally subject to change, and so we + /// don't document this here. Runtime MIR has all retags explicit. + /// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has + /// access to. This occurs in generator bodies. Such locals do not behave like other locals, + /// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals - + /// all generator bodies are lowered and so all places that look like locals really are locals. + /// - Const prop lints: The lint pass which reports eg `200_u8 + 200_u8` as an error is run as a + /// part of analysis to runtime MIR lowering. This means that transformations which may supress + /// such errors may not run on analysis MIR. + Runtime(RuntimePhase), +} + +/// See [`MirPhase::Analysis`]. +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(HashStable)] +pub enum AnalysisPhase { + Initial = 0, + /// Beginning in this phase, the following variants are disallowed: /// * [`TerminatorKind::FalseUnwind`] /// * [`TerminatorKind::FalseEdge`] /// * [`StatementKind::FakeRead`] /// * [`StatementKind::AscribeUserType`] /// * [`Rvalue::Ref`] with `BorrowKind::Shallow` /// - /// And the following variant is allowed: - /// * [`StatementKind::Retag`] - /// - /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` - /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands - /// are allowed for non-`Copy` types. - DropsLowered = 4, - /// Beginning with this phase, the following variant is disallowed: + /// Furthermore, `Deref` projections must be the first projection within any place (if they + /// appear at all) + PostCleanup = 1, +} + +/// See [`MirPhase::Runtime`]. +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(HashStable)] +pub enum RuntimePhase { + /// In addition to the semantic changes, beginning with this phase, the following variants are + /// disallowed: + /// * [`TerminatorKind::DropAndReplace`] + /// * [`TerminatorKind::Yield`] + /// * [`TerminatorKind::GeneratorDrop`] /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` /// - /// And the following variant is allowed: + /// And the following variants are allowed: + /// * [`StatementKind::Retag`] /// * [`StatementKind::SetDiscriminant`] - Deaggregated = 5, - /// Before this phase, generators are in the "source code" form, featuring `yield` statements - /// and such. With this phase change, they are transformed into a proper state machine. Running - /// optimizations before this change can be potentially dangerous because the source code is to - /// some extent a "lie." In particular, `yield` terminators effectively make the value of all - /// locals visible to the caller. This means that dead store elimination before them, or code - /// motion across them, is not correct in general. This is also exasperated by type checking - /// having pre-computed a list of the types that it thinks are ok to be live across a yield - /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new - /// types across a yield point will lead to ICEs becaues of this. - /// - /// Beginning with this phase, the following variants are disallowed: - /// * [`TerminatorKind::Yield`] - /// * [`TerminatorKind::GeneratorDrop`] + /// * [`StatementKind::Deinit`] + /// + /// Furthermore, `Copy` operands are allowed for non-`Copy` types. + Initial = 0, + /// Beginning with this phase, the following variant is disallowed: /// * [`ProjectionElem::Deref`] of `Box` - GeneratorsLowered = 6, - Optimized = 7, + PostCleanup = 1, + Optimized = 2, } /////////////////////////////////////////////////////////////////////////// @@ -292,12 +327,40 @@ pub enum StatementKind<'tcx> { /// executed. Coverage(Box), + /// Denotes a call to an intrinsic that does not require an unwind path and always returns. + /// This avoids adding a new block and a terminator for simple intrinsics. + Intrinsic(Box>), + + /// No-op. Useful for deleting instructions without affecting statement indices. + Nop, +} + +#[derive( + Clone, + TyEncodable, + TyDecodable, + Debug, + PartialEq, + Hash, + HashStable, + TypeFoldable, + TypeVisitable +)] +pub enum NonDivergingIntrinsic<'tcx> { + /// Denotes a call to the intrinsic function `assume`. + /// + /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its + /// computation to infer information about other variables. So if the boolean came from a + /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. + /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. + Assume(Operand<'tcx>), + /// Denotes a call to the intrinsic function `copy_nonoverlapping`. /// /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and /// `dest` are dereferenced, and `count * size_of::()` bytes beginning with the first byte of - /// the `src` place are copied to the continguous range of bytes beginning with the first byte + /// the `src` place are copied to the contiguous range of bytes beginning with the first byte /// of `dest`. /// /// **Needs clarification**: In what order are operands computed and dereferenced? It should @@ -305,10 +368,18 @@ pub enum StatementKind<'tcx> { /// /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? /// I vaguely remember Ralf saying somewhere that he thought it should not be. - CopyNonOverlapping(Box>), + CopyNonOverlapping(CopyNonOverlapping<'tcx>), +} - /// No-op. Useful for deleting instructions without affecting statement indices. - Nop, +impl std::fmt::Display for NonDivergingIntrinsic<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Assume(op) => write!(f, "assume({op:?})"), + Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") + } + } + } } /// Describes what kind of retag is to be performed. @@ -343,7 +414,7 @@ pub enum FakeReadCause { /// Some(closure_def_id). /// Otherwise, the value of the optional LocalDefId will be None. // - // We can use LocaDefId here since fake read statements are removed + // We can use LocalDefId here since fake read statements are removed // before codegen in the `CleanupNonCodegenStatements` pass. ForMatchedPlace(Option), @@ -417,7 +488,7 @@ pub struct CopyNonOverlapping<'tcx> { /// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// still an error to have such an edge in the CFG even if it's known that it won't be taken at /// runtime. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum TerminatorKind<'tcx> { /// Block has one successor; we continue execution there. Goto { target: BasicBlock }, @@ -670,7 +741,7 @@ pub enum TerminatorKind<'tcx> { } /// Information about an assertion failure. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum AssertKind { BoundsCheck { len: O, index: O }, Overflow(BinOp, O, O), @@ -792,7 +863,7 @@ pub type AssertMessage<'tcx> = AssertKind>; /// /// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken /// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Place<'tcx> { pub local: Local, @@ -801,7 +872,7 @@ pub struct Place<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum ProjectionElem { Deref, Field(Field, T), @@ -884,7 +955,7 @@ pub type PlaceElem<'tcx> = ProjectionElem>; /// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri /// currently implements it, but it seems like this may be something to check against in the /// validator. -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum Operand<'tcx> { /// Creates a value by loading the given place. /// @@ -915,7 +986,7 @@ pub enum Operand<'tcx> { /// Computing any rvalue begins by evaluating the places and operands in some order (**Needs /// clarification**: Which order?). These are then used to produce a "value" - the same kind of /// value that an [`Operand`] produces. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum Rvalue<'tcx> { /// Yields the operand unchanged Use(Operand<'tcx>), @@ -1068,11 +1139,14 @@ pub enum CastKind { /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. Pointer(PointerCast), + /// Cast into a dyn* object. + DynStar, /// Remaining unclassified casts. Misc, } #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum AggregateKind<'tcx> { /// The type is of the element Array(Ty<'tcx>), @@ -1160,7 +1234,8 @@ pub enum BinOp { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - static_assert_size!(AggregateKind<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(AggregateKind<'_>, 40); static_assert_size!(Operand<'_>, 24); static_assert_size!(Place<'_>, 16); static_assert_size!(PlaceElem<'_>, 24); diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 9ccf5aea6..4ea333cff 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -14,7 +14,7 @@ use std::slice; pub use super::query::*; -#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] +#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. @@ -102,7 +102,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> { impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {} -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Terminator<'tcx> { pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx>, diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 627dc32f3..55b2c5927 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -37,7 +37,7 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> { Preorder { body, - visited: BitSet::new_empty(body.basic_blocks().len()), + visited: BitSet::new_empty(body.basic_blocks.len()), worklist, root_is_start_block: root == START_BLOCK, } @@ -71,7 +71,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks().len() - self.visited.count(); + let upper = self.body.basic_blocks.len() - self.visited.count(); let lower = if self.root_is_start_block { // We will visit all remaining blocks exactly once. diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 82a6b0c50..9d098c808 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -1,8 +1,9 @@ //! `TypeFoldable` implementations for MIR types +use rustc_ast::InlineAsmTemplatePiece; + use super::*; use crate::ty; -use rustc_data_structures::functor::IdFunctor; TrivialTypeTraversalAndLiftImpls! { BlockTailInfo, @@ -13,96 +14,27 @@ TrivialTypeTraversalAndLiftImpls! { SourceScope, SourceScopeLocalData, UserTypeAnnotationIndex, + BorrowKind, + CastKind, + BinOp, + NullOp, + UnOp, + hir::Movability, + BasicBlock, + SwitchTargets, + GeneratorKind, + GeneratorSavedLocal, } -impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - use crate::mir::TerminatorKind::*; - - let kind = match self.kind { - Goto { target } => Goto { target }, - SwitchInt { discr, switch_ty, targets } => SwitchInt { - discr: discr.try_fold_with(folder)?, - switch_ty: switch_ty.try_fold_with(folder)?, - targets, - }, - Drop { place, target, unwind } => { - Drop { place: place.try_fold_with(folder)?, target, unwind } - } - DropAndReplace { place, value, target, unwind } => DropAndReplace { - place: place.try_fold_with(folder)?, - value: value.try_fold_with(folder)?, - target, - unwind, - }, - Yield { value, resume, resume_arg, drop } => Yield { - value: value.try_fold_with(folder)?, - resume, - resume_arg: resume_arg.try_fold_with(folder)?, - drop, - }, - Call { func, args, destination, target, cleanup, from_hir_call, fn_span } => Call { - func: func.try_fold_with(folder)?, - args: args.try_fold_with(folder)?, - destination: destination.try_fold_with(folder)?, - target, - cleanup, - from_hir_call, - fn_span, - }, - Assert { cond, expected, msg, target, cleanup } => { - use AssertKind::*; - let msg = match msg { - BoundsCheck { len, index } => BoundsCheck { - len: len.try_fold_with(folder)?, - index: index.try_fold_with(folder)?, - }, - Overflow(op, l, r) => { - Overflow(op, l.try_fold_with(folder)?, r.try_fold_with(folder)?) - } - OverflowNeg(op) => OverflowNeg(op.try_fold_with(folder)?), - DivisionByZero(op) => DivisionByZero(op.try_fold_with(folder)?), - RemainderByZero(op) => RemainderByZero(op.try_fold_with(folder)?), - ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg, - }; - Assert { cond: cond.try_fold_with(folder)?, expected, msg, target, cleanup } - } - GeneratorDrop => GeneratorDrop, - Resume => Resume, - Abort => Abort, - Return => Return, - Unreachable => Unreachable, - FalseEdge { real_target, imaginary_target } => { - FalseEdge { real_target, imaginary_target } - } - FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - InlineAsm { template, operands, options, line_spans, destination, cleanup } => { - InlineAsm { - template, - operands: operands.try_fold_with(folder)?, - options, - line_spans, - destination, - cleanup, - } - } - }; - Ok(Terminator { source_info: self.source_info, kind }) - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn try_fold_with>(self, _: &mut F) -> Result { +impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] { + fn try_fold_with>(self, _folder: &mut F) -> Result { Ok(self) } } -impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(Place { - local: self.local.try_fold_with(folder)?, - projection: self.projection.try_fold_with(folder)?, - }) +impl<'tcx> TypeFoldable<'tcx> for &'tcx [Span] { + fn try_fold_with>(self, _folder: &mut F) -> Result { + Ok(self) } } @@ -112,114 +44,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - use crate::mir::Rvalue::*; - Ok(match self { - Use(op) => Use(op.try_fold_with(folder)?), - Repeat(op, len) => Repeat(op.try_fold_with(folder)?, len.try_fold_with(folder)?), - ThreadLocalRef(did) => ThreadLocalRef(did.try_fold_with(folder)?), - Ref(region, bk, place) => { - Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?) - } - CopyForDeref(place) => CopyForDeref(place.try_fold_with(folder)?), - AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?), - Len(place) => Len(place.try_fold_with(folder)?), - Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?), - BinaryOp(op, box (rhs, lhs)) => { - BinaryOp(op, Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?))) - } - CheckedBinaryOp(op, box (rhs, lhs)) => CheckedBinaryOp( - op, - Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)), - ), - UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?), - Discriminant(place) => Discriminant(place.try_fold_with(folder)?), - NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?), - Aggregate(kind, fields) => { - let kind = kind.try_map_id(|kind| { - Ok(match kind { - AggregateKind::Array(ty) => AggregateKind::Array(ty.try_fold_with(folder)?), - AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( - def, - v, - substs.try_fold_with(folder)?, - user_ty.try_fold_with(folder)?, - n, - ), - AggregateKind::Closure(id, substs) => { - AggregateKind::Closure(id, substs.try_fold_with(folder)?) - } - AggregateKind::Generator(id, substs, movablity) => { - AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity) - } - }) - })?; - Aggregate(kind, fields.try_fold_with(folder)?) - } - ShallowInitBox(op, ty) => { - ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - }) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?), - Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?), - Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?), - }) - } -} - -impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - use crate::mir::ProjectionElem::*; - - Ok(match self { - Deref => Deref, - Field(f, ty) => Field(f, ty.try_fold_with(folder)?), - Index(v) => Index(v.try_fold_with(folder)?), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - }) - } -} - -impl<'tcx> TypeFoldable<'tcx> for Field { - fn try_fold_with>(self, _: &mut F) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn try_fold_with>(self, _: &mut F) -> Result { - Ok(self) - } -} - impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { fn try_fold_with>(self, _: &mut F) -> Result { Ok(self) } } -impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(Constant { - span: self.span, - user_ty: self.user_ty.try_fold_with(folder)?, - literal: self.literal.try_fold_with(folder)?, - }) - } -} - impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { #[inline(always)] fn try_fold_with>(self, folder: &mut F) -> Result { @@ -235,6 +65,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> { match self { ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)), ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)), + ConstantKind::Unevaluated(uv, t) => { + Ok(ConstantKind::Unevaluated(uv.try_fold_with(folder)?, t.try_fold_with(folder)?)) + } } } } diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs index 6a0801cb0..be19bb486 100644 --- a/compiler/rustc_middle/src/mir/type_visitable.rs +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -1,165 +1,6 @@ //! `TypeVisitable` implementations for MIR types use super::*; -use crate::ty; - -impl<'tcx> TypeVisitable<'tcx> for Terminator<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - use crate::mir::TerminatorKind::*; - - match self.kind { - SwitchInt { ref discr, switch_ty, .. } => { - discr.visit_with(visitor)?; - switch_ty.visit_with(visitor) - } - Drop { ref place, .. } => place.visit_with(visitor), - DropAndReplace { ref place, ref value, .. } => { - place.visit_with(visitor)?; - value.visit_with(visitor) - } - Yield { ref value, .. } => value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { - destination.visit_with(visitor)?; - func.visit_with(visitor)?; - args.visit_with(visitor) - } - Assert { ref cond, ref msg, .. } => { - cond.visit_with(visitor)?; - use AssertKind::*; - match msg { - BoundsCheck { ref len, ref index } => { - len.visit_with(visitor)?; - index.visit_with(visitor) - } - Overflow(_, l, r) => { - l.visit_with(visitor)?; - r.visit_with(visitor) - } - OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { - op.visit_with(visitor) - } - ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE, - } - } - InlineAsm { ref operands, .. } => operands.visit_with(visitor), - Goto { .. } - | Resume - | Abort - | Return - | GeneratorDrop - | Unreachable - | FalseEdge { .. } - | FalseUnwind { .. } => ControlFlow::CONTINUE, - } - } -} - -impl<'tcx> TypeVisitable<'tcx> for GeneratorKind { - fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE - } -} - -impl<'tcx> TypeVisitable<'tcx> for Place<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.local.visit_with(visitor)?; - self.projection.visit_with(visitor) - } -} - -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeVisitable<'tcx> for Rvalue<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => op.visit_with(visitor), - CopyForDeref(ref place) => { - let op = &Operand::Copy(*place); - op.visit_with(visitor) - } - Repeat(ref op, _) => op.visit_with(visitor), - ThreadLocalRef(did) => did.visit_with(visitor), - Ref(region, _, ref place) => { - region.visit_with(visitor)?; - place.visit_with(visitor) - } - AddressOf(_, ref place) => place.visit_with(visitor), - Len(ref place) => place.visit_with(visitor), - Cast(_, ref op, ty) => { - op.visit_with(visitor)?; - ty.visit_with(visitor) - } - BinaryOp(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (ref rhs, ref lhs)) => { - rhs.visit_with(visitor)?; - lhs.visit_with(visitor) - } - UnaryOp(_, ref val) => val.visit_with(visitor), - Discriminant(ref place) => place.visit_with(visitor), - NullaryOp(_, ty) => ty.visit_with(visitor), - Aggregate(ref kind, ref fields) => { - match **kind { - AggregateKind::Array(ty) => { - ty.visit_with(visitor)?; - } - AggregateKind::Tuple => {} - AggregateKind::Adt(_, _, substs, user_ty, _) => { - substs.visit_with(visitor)?; - user_ty.visit_with(visitor)?; - } - AggregateKind::Closure(_, substs) => { - substs.visit_with(visitor)?; - } - AggregateKind::Generator(_, substs, _) => { - substs.visit_with(visitor)?; - } - } - fields.visit_with(visitor) - } - ShallowInitBox(ref op, ty) => { - op.visit_with(visitor)?; - ty.visit_with(visitor) - } - } - } -} - -impl<'tcx> TypeVisitable<'tcx> for Operand<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - match *self { - Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), - Operand::Constant(ref c) => c.visit_with(visitor), - } - } -} - -impl<'tcx> TypeVisitable<'tcx> for PlaceElem<'tcx> { - fn visit_with>(&self, visitor: &mut Vs) -> ControlFlow { - use crate::mir::ProjectionElem::*; - - match self { - Field(_, ty) => ty.visit_with(visitor), - Index(v) => v.visit_with(visitor), - _ => ControlFlow::CONTINUE, - } - } -} - -impl<'tcx> TypeVisitable<'tcx> for Field { - fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE - } -} - -impl<'tcx> TypeVisitable<'tcx> for GeneratorSavedLocal { - fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE - } -} impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix { fn visit_with>(&self, _: &mut V) -> ControlFlow { @@ -167,13 +8,6 @@ impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix { } } -impl<'tcx> TypeVisitable<'tcx> for Constant<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.literal.visit_with(visitor)?; - self.user_ty.visit_with(visitor) - } -} - impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> { fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_mir_const(*self) @@ -185,6 +19,10 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> { match *self { ConstantKind::Ty(c) => c.visit_with(visitor), ConstantKind::Val(_, t) => t.visit_with(visitor), + ConstantKind::Unevaluated(uv, t) => { + uv.visit_with(visitor)?; + t.visit_with(visitor) + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 891608764..d9b24566b 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -80,6 +80,8 @@ macro_rules! make_mir_visitor { self.super_body(body); } + extra_body_methods!($($mutability)?); + fn visit_basic_block_data( &mut self, block: BasicBlock, @@ -235,14 +237,6 @@ macro_rules! make_mir_visitor { self.super_region(region); } - fn visit_const( - &mut self, - constant: $(& $mutability)? ty::Const<'tcx>, - _: Location, - ) { - self.super_const(constant); - } - fn visit_substs( &mut self, substs: & $($mutability)? SubstsRef<'tcx>, @@ -287,63 +281,7 @@ macro_rules! make_mir_visitor { &mut self, body: &$($mutability)? Body<'tcx>, ) { - let span = body.span; - if let Some(gen) = &$($mutability)? body.generator { - if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { - self.visit_ty( - yield_ty, - TyContext::YieldTy(SourceInfo::outermost(span)) - ); - } - } - - // for best performance, we want to use an iterator rather - // than a for-loop, to avoid calling `body::Body::invalidate` for - // each basic block. - #[allow(unused_macro_rules)] - macro_rules! basic_blocks { - (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); - () => (body.basic_blocks().iter_enumerated()); - } - for (bb, data) in basic_blocks!($($mutability)?) { - self.visit_basic_block_data(bb, data); - } - - for scope in &$($mutability)? body.source_scopes { - self.visit_source_scope_data(scope); - } - - self.visit_ty( - $(& $mutability)? body.return_ty(), - TyContext::ReturnTy(SourceInfo::outermost(body.span)) - ); - - for local in body.local_decls.indices() { - self.visit_local_decl(local, & $($mutability)? body.local_decls[local]); - } - - #[allow(unused_macro_rules)] - macro_rules! type_annotations { - (mut) => (body.user_type_annotations.iter_enumerated_mut()); - () => (body.user_type_annotations.iter_enumerated()); - } - - for (index, annotation) in type_annotations!($($mutability)?) { - self.visit_user_type_annotation( - index, annotation - ); - } - - for var_debug_info in &$($mutability)? body.var_debug_info { - self.visit_var_debug_info(var_debug_info); - } - - self.visit_span($(& $mutability)? body.span); - - for const_ in &$($mutability)? body.required_consts { - let location = START_BLOCK.start_location(); - self.visit_constant(const_, location); - } + super_body!(self, body, $($mutability, true)?); } fn super_basic_block_data(&mut self, @@ -479,14 +417,15 @@ macro_rules! make_mir_visitor { location ) } - StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{ - src, - dst, - count, - }) => { - self.visit_operand(src, location); - self.visit_operand(dst, location); - self.visit_operand(count, location) + StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { + match intrinsic { + NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + self.visit_operand(src, location); + self.visit_operand(dst, location); + self.visit_operand(count, location); + } + } } StatementKind::Nop => {} } @@ -930,8 +869,9 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); drop(user_ty); // no visit method for this match literal { - ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location), + ConstantKind::Ty(_) => {} ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } } @@ -969,9 +909,6 @@ macro_rules! make_mir_visitor { fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) { } - fn super_const(&mut self, _const: $(& $mutability)? ty::Const<'tcx>) { - } - fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { } @@ -982,12 +919,7 @@ macro_rules! make_mir_visitor { body: &$($mutability)? Body<'tcx>, location: Location ) { - #[allow(unused_macro_rules)] - macro_rules! basic_blocks { - (mut) => (body.basic_blocks_mut()); - () => (body.basic_blocks()); - } - let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block]; + let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { self.visit_terminator(terminator, location) @@ -1002,6 +934,94 @@ macro_rules! make_mir_visitor { } } +macro_rules! basic_blocks { + ($body:ident, mut, true) => { + $body.basic_blocks.as_mut() + }; + ($body:ident, mut, false) => { + $body.basic_blocks.as_mut_preserves_cfg() + }; + ($body:ident,) => { + $body.basic_blocks + }; +} + +macro_rules! basic_blocks_iter { + ($body:ident, mut, $invalidate:tt) => { + basic_blocks!($body, mut, $invalidate).iter_enumerated_mut() + }; + ($body:ident,) => { + basic_blocks!($body,).iter_enumerated() + }; +} + +macro_rules! extra_body_methods { + (mut) => { + fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { + self.super_body_preserves_cfg(body); + } + + fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { + super_body!(self, body, mut, false); + } + }; + () => {}; +} + +macro_rules! super_body { + ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => { + let span = $body.span; + if let Some(gen) = &$($mutability)? $body.generator { + if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { + $self.visit_ty( + yield_ty, + TyContext::YieldTy(SourceInfo::outermost(span)) + ); + } + } + + for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) { + $self.visit_basic_block_data(bb, data); + } + + for scope in &$($mutability)? $body.source_scopes { + $self.visit_source_scope_data(scope); + } + + $self.visit_ty( + $(& $mutability)? $body.return_ty(), + TyContext::ReturnTy(SourceInfo::outermost($body.span)) + ); + + for local in $body.local_decls.indices() { + $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]); + } + + #[allow(unused_macro_rules)] + macro_rules! type_annotations { + (mut) => ($body.user_type_annotations.iter_enumerated_mut()); + () => ($body.user_type_annotations.iter_enumerated()); + } + + for (index, annotation) in type_annotations!($($mutability)?) { + $self.visit_user_type_annotation( + index, annotation + ); + } + + for var_debug_info in &$($mutability)? $body.var_debug_info { + $self.visit_var_debug_info(var_debug_info); + } + + $self.visit_span($(& $mutability)? $body.span); + + for const_ in &$($mutability)? $body.required_consts { + let location = START_BLOCK.start_location(); + $self.visit_constant(const_, location); + } + } +} + macro_rules! visit_place_fns { (mut) => { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d8483e7e4..4b336ea62 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -47,14 +47,14 @@ rustc_queries! { /// To avoid this fate, do not call `tcx.hir().krate()`; instead, /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: ()) -> Crate<'tcx> { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "get the crate HIR" } } /// All items in the crate. query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "get HIR crate items" } } @@ -64,7 +64,7 @@ rustc_queries! { /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. /// Avoid calling this query directly. query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } @@ -161,6 +161,14 @@ rustc_queries! { separate_provide_extern } + query collect_trait_impl_trait_tys(key: DefId) + -> Result<&'tcx FxHashMap>, ErrorGuaranteed> + { + desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } @@ -189,7 +197,7 @@ rustc_queries! { /// associated generics. query generics_of(key: DefId) -> ty::Generics { desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) + arena_cache cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -261,13 +269,13 @@ rustc_queries! { } query native_libraries(_: CrateNum) -> Vec { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "looking up the native libraries of a linked crate" } separate_provide_extern } query lint_levels(_: ()) -> LintLevelMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "computing the lint levels for items in this crate" } } @@ -300,7 +308,7 @@ rustc_queries! { /// Create a THIR tree for debugging. query thir_tree(key: ty::WithOptConstParam) -> String { no_hash - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } } @@ -308,7 +316,7 @@ rustc_queries! { /// them. This includes all the body owners, but also things like struct /// constructors. query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "getting a list of all mir_keys" } } @@ -415,7 +423,7 @@ rustc_queries! { query symbols_for_closure_captures( key: (LocalDefId, LocalDefId) ) -> Vec { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "symbols for captures of closure `{}` in `{}`", tcx.def_path_str(key.1.to_def_id()), @@ -435,7 +443,7 @@ rustc_queries! { /// MIR pass (assuming the -Cinstrument-coverage option is enabled). query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo { desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) } - storage(ArenaCacheSelector<'tcx>) + arena_cache } /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the @@ -445,7 +453,7 @@ rustc_queries! { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) + arena_cache cache_on_disk_if { key.is_local() } } @@ -483,7 +491,7 @@ rustc_queries! { } query wasm_import_module_map(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "wasm import module map" } } @@ -559,7 +567,7 @@ rustc_queries! { query trait_def(key: DefId) -> ty::TraitDef { desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) + arena_cache cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -637,7 +645,7 @@ rustc_queries! { /// Gets a map with the variance of every item; use `item_variance` instead. query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "computing the variances for items in this crate" } } @@ -650,7 +658,7 @@ rustc_queries! { /// Maps from thee `DefId` of a type to its (inferred) outlives. query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "computing the inferred outlives predicates for items in this crate" } } @@ -664,14 +672,14 @@ rustc_queries! { /// Maps from a trait item to the trait item "descriptor". query associated_item(key: DefId) -> ty::AssocItem { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } - storage(ArenaCacheSelector<'tcx>) + arena_cache cache_on_disk_if { key.is_local() } separate_provide_extern } /// Collects the associated items defined on a trait or impl. query associated_items(key: DefId) -> ty::AssocItems<'tcx> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } @@ -697,7 +705,7 @@ rustc_queries! { /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be ///`{ trait_f: impl_f, trait_g: impl_g }` query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) } } @@ -765,11 +773,20 @@ rustc_queries! { desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } } + /// Returns the types assumed to be well formed while "inside" of the given item. + /// + /// Note that we've liberated the late bound regions of function signatures, so + /// this can not be used to check whether these types are well formed. + query assumed_wf_types(key: DefId) -> &'tcx ty::List> { + desc { |tcx| "computing the implied bounds of {}", tcx.def_path_str(key) } + } + /// Computes the signature of the function. query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + cycle_delay_bug } /// Performs lint checking for the module. @@ -809,8 +826,8 @@ rustc_queries! { desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } } - query check_mod_liveness(key: LocalDefId) -> () { - desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } + query check_liveness(key: DefId) { + desc { |tcx| "checking liveness of variables in {}", tcx.def_path_str(key) } } /// Return the live symbols in the crate for dead code check. @@ -821,7 +838,7 @@ rustc_queries! { FxHashSet, FxHashMap> ) { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "find live symbols in crate" } } @@ -867,13 +884,6 @@ rustc_queries! { query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } - load_cached(tcx, id) { - let typeck_results: Option> = tcx - .on_disk_cache().as_ref() - .and_then(|c| c.try_load_query_result(*tcx, id)); - - typeck_results.map(|x| &*tcx.arena.alloc(x)) - } } query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet { @@ -905,7 +915,7 @@ rustc_queries! { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. query crate_inherent_impls(k: ()) -> CrateInherentImpls { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "all inherent impls defined in crate" } } @@ -1038,7 +1048,7 @@ rustc_queries! { } query reachable_set(_: ()) -> FxHashSet { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "reachability" } } @@ -1050,7 +1060,7 @@ rustc_queries! { /// Generates a MIR body for the shim. query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } @@ -1094,6 +1104,11 @@ rustc_queries! { separate_provide_extern } + query lookup_default_body_stability(def_id: DefId) -> Option { + desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query should_inherit_track_caller(def_id: DefId) -> bool { desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) } } @@ -1119,7 +1134,7 @@ rustc_queries! { query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } - storage(ArenaCacheSelector<'tcx>) + arena_cache cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1136,8 +1151,8 @@ rustc_queries! { /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. query rendered_const(def_id: DefId) -> String { - storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + arena_cache + desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1181,14 +1196,11 @@ rustc_queries! { } } - query codegen_fulfill_obligation( + query codegen_select_candidate( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> { cache_on_disk_if { true } - desc { |tcx| - "checking if `{}` fulfills its obligations", - tcx.def_path_str(key.1.def_id()) - } + desc { |tcx| "computing candidate for `{}`", key.1 } } /// Return all `impl` blocks in the current crate. @@ -1198,12 +1210,12 @@ rustc_queries! { /// Given a trait `trait_id`, return all known `impl` blocks. query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } } query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } @@ -1295,6 +1307,7 @@ rustc_queries! { query layout_of( key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Result, ty::layout::LayoutError<'tcx>> { + depth_limit desc { "computing layout of `{}`", key.value } remap_env_constness } @@ -1329,7 +1342,7 @@ rustc_queries! { } query dependency_formats(_: ()) -> Lrc { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "get the linkage format of all dependencies" } } @@ -1422,7 +1435,7 @@ rustc_queries! { // like the compiler-generated `main` function and so on. query reachable_non_generics(_: CrateNum) -> DefIdMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "looking up the exported symbols of a crate" } separate_provide_extern } @@ -1445,7 +1458,7 @@ rustc_queries! { /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even /// better, `Instance::upstream_monomorphization()`. query upstream_monomorphizations(_: ()) -> DefIdMap, CrateNum>> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "collecting available upstream monomorphizations" } } @@ -1459,7 +1472,7 @@ rustc_queries! { query upstream_monomorphizations_for(def_id: DefId) -> Option<&'tcx FxHashMap, CrateNum>> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "collecting available upstream monomorphizations for `{}`", tcx.def_path_str(def_id), @@ -1487,7 +1500,7 @@ rustc_queries! { } query foreign_modules(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "looking up the foreign modules of a linked crate" } separate_provide_extern } @@ -1513,13 +1526,13 @@ rustc_queries! { separate_provide_extern } query extra_filename(_: CrateNum) -> String { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "looking up the extra filename for a crate" } separate_provide_extern } query crate_extern_paths(_: CrateNum) -> Vec { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "looking up the paths for extern crates" } separate_provide_extern @@ -1551,6 +1564,9 @@ rustc_queries! { -> Option { desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) } } + query native_library(def_id: DefId) -> Option<&'tcx NativeLib> { + desc { |tcx| "native_library({})", tcx.def_path_str(def_id) } + } /// Does lifetime resolution, but does not descend into trait items. This /// should only be used for resolving lifetimes of on trait definitions, @@ -1558,14 +1574,14 @@ rustc_queries! { /// the same lifetimes and is responsible for diagnostics. /// See `rustc_resolve::late::lifetimes for details. query resolve_lifetimes_trait_definition(_: LocalDefId) -> ResolveLifetimes { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "resolving lifetimes for a trait definition" } } /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes for details. query resolve_lifetimes(_: LocalDefId) -> ResolveLifetimes { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "resolving lifetimes" } } query named_region_map(_: LocalDefId) -> @@ -1575,19 +1591,31 @@ rustc_queries! { query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet> { desc { "testing if a region is late bound" } } - /// For a given item (like a struct), gets the default lifetimes to be used + /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. - /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`. - /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`. - query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> { - desc { "looking up lifetime defaults for a region on an item" } + /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`. + /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`. + /// This query will panic if passed something that is not a type parameter. + query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault { + desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } + separate_provide_extern } query late_bound_vars_map(_: LocalDefId) -> Option<&'tcx FxHashMap>> { desc { "looking up late bound vars" } } - query visibility(def_id: DefId) -> ty::Visibility { + /// Computes the visibility of the provided `def_id`. + /// + /// If the item from the `def_id` doesn't have a visibility, it will panic. For example + /// a generic type parameter will panic if you call this method on it: + /// + /// ``` + /// pub trait Foo {} + /// ``` + /// + /// In here, if you call `visibility` on `T`, it'll panic. + query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } @@ -1623,7 +1651,7 @@ rustc_queries! { } query lib_features(_: ()) -> LibFeatures { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "calculating the lib features map" } } query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option)] { @@ -1631,7 +1659,7 @@ rustc_queries! { separate_provide_extern } query stability_implications(_: CrateNum) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } separate_provide_extern } @@ -1642,14 +1670,14 @@ rustc_queries! { } /// Returns the lang items defined in another crate by loading it from metadata. query get_lang_items(_: ()) -> LanguageItems { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "calculating the lang items map" } } /// Returns all diagnostic items defined in all crates. query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "calculating the diagnostic items map" } } @@ -1662,7 +1690,7 @@ rustc_queries! { /// Returns the diagnostic items defined in a crate. query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "calculating the diagnostic items map in a crate" } separate_provide_extern } @@ -1672,11 +1700,11 @@ rustc_queries! { separate_provide_extern } query visible_parent_map(_: ()) -> DefIdMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "calculating the visible parent map" } } query trimmed_def_paths(_: ()) -> FxHashMap { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "calculating trimmed def paths" } } query missing_extern_crate_item(_: CrateNum) -> bool { @@ -1685,14 +1713,14 @@ rustc_queries! { separate_provide_extern } query used_crate_source(_: CrateNum) -> Lrc { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "looking at the source for a crate" } separate_provide_extern } /// Returns the debugger visualizers defined for this crate. query debugger_visualizers(_: CrateNum) -> Vec { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { "looking up the debugger visualizers for this crate" } separate_provide_extern } @@ -1726,7 +1754,7 @@ rustc_queries! { } query stability_index(_: ()) -> stability::Index { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "calculating the stability index for the local crate" } } @@ -1951,6 +1979,14 @@ rustc_queries! { } } + query is_impossible_method(key: (DefId, DefId)) -> bool { + desc { |tcx| + "checking if {} is impossible to call within {}", + tcx.def_path_str(key.1), + tcx.def_path_str(key.0), + } + } + query method_autoderef_steps( goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { @@ -1959,7 +1995,7 @@ rustc_queries! { } query supported_target_features(_: CrateNum) -> FxHashMap> { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "looking up supported target features" } } @@ -2029,7 +2065,7 @@ rustc_queries! { /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option> { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always no_hash desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 } @@ -2039,13 +2075,13 @@ rustc_queries! { /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). query global_backend_features(_: ()) -> Vec { - storage(ArenaCacheSelector<'tcx>) + arena_cache eval_always desc { "computing the backend features for CLI flags" } } query generator_diagnostic_data(key: DefId) -> Option> { - storage(ArenaCacheSelector<'tcx>) + arena_cache desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b856af1d8..86b415050 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -15,50 +15,33 @@ use rustc_hir::def_id::DefId; use rustc_hir::RangeEnd; use rustc_index::newtype_index; use rustc_index::vec::IndexVec; -use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::CanonicalUserTypeAnnotation; -use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType}; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts}; +use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; - -use rustc_span::def_id::LocalDefId; use std::fmt; use std::ops::Index; pub mod visit; -newtype_index! { - /// An index to an [`Arm`] stored in [`Thir::arms`] - #[derive(HashStable)] - pub struct ArmId { - DEBUG_FORMAT = "a{}" - } -} - -newtype_index! { - /// An index to an [`Expr`] stored in [`Thir::exprs`] - #[derive(HashStable)] - pub struct ExprId { - DEBUG_FORMAT = "e{}" - } -} - -newtype_index! { - #[derive(HashStable)] - /// An index to a [`Stmt`] stored in [`Thir::stmts`] - pub struct StmtId { - DEBUG_FORMAT = "s{}" - } -} - macro_rules! thir_with_elements { - ($($name:ident: $id:ty => $value:ty,)*) => { + ($($name:ident: $id:ty => $value:ty => $format:literal,)*) => { + $( + newtype_index! { + #[derive(HashStable)] + pub struct $id { + DEBUG_FORMAT = $format + } + } + )* + /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). @@ -90,10 +73,29 @@ macro_rules! thir_with_elements { } } +pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0); + thir_with_elements! { - arms: ArmId => Arm<'tcx>, - exprs: ExprId => Expr<'tcx>, - stmts: StmtId => Stmt<'tcx>, + arms: ArmId => Arm<'tcx> => "a{}", + blocks: BlockId => Block => "b{}", + exprs: ExprId => Expr<'tcx> => "e{}", + stmts: StmtId => Stmt<'tcx> => "s{}", + params: ParamId => Param<'tcx> => "p{}", +} + +/// Description of a type-checked function parameter. +#[derive(Clone, Debug, HashStable)] +pub struct Param<'tcx> { + /// The pattern that appears in the parameter list, or None for implicit parameters. + pub pat: Option>>, + /// The possibly inferred type. + pub ty: Ty<'tcx>, + /// Span of the explicitly provided type, or None if inferred for closures. + pub ty_span: Option, + /// Whether this param is `self`, and how it is bound. + pub self_kind: Option, + /// HirId for lints. + pub hir_id: Option, } #[derive(Copy, Clone, Debug, HashStable)] @@ -121,8 +123,10 @@ pub struct Block { pub safety_mode: BlockSafety, } +type UserTy<'tcx> = Option>>; + #[derive(Clone, Debug, HashStable)] -pub struct Adt<'tcx> { +pub struct AdtExpr<'tcx> { /// The ADT we're constructing. pub adt_def: AdtDef<'tcx>, /// The variant of the ADT. @@ -131,13 +135,30 @@ pub struct Adt<'tcx> { /// Optional user-given substs: for something like `let x = /// Bar:: { ... }`. - pub user_ty: Option>>, + pub user_ty: UserTy<'tcx>, pub fields: Box<[FieldExpr]>, /// The base, e.g. `Foo {x: 1, .. base}`. pub base: Option>, } +#[derive(Clone, Debug, HashStable)] +pub struct ClosureExpr<'tcx> { + pub closure_id: LocalDefId, + pub substs: UpvarSubsts<'tcx>, + pub upvars: Box<[ExprId]>, + pub movability: Option, + pub fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>, +} + +#[derive(Clone, Debug, HashStable)] +pub struct InlineAsmExpr<'tcx> { + pub template: &'tcx [InlineAsmTemplatePiece], + pub operands: Box<[InlineAsmOperand<'tcx>]>, + pub options: InlineAsmOptions, + pub line_spans: &'tcx [Span], +} + #[derive(Copy, Clone, Debug, HashStable)] pub enum BlockSafety { Safe, @@ -177,13 +198,13 @@ pub enum StmtKind<'tcx> { /// `let = ...` /// /// If a type annotation is included, it is added as an ascription pattern. - pattern: Pat<'tcx>, + pattern: Box>, /// `let pat: ty = ` initializer: Option, /// `let pat: ty = else { } - else_block: Option, + else_block: Option, /// The lint level for this `let` statement. lint_level: LintLevel, @@ -298,7 +319,7 @@ pub enum ExprKind<'tcx> { }, Let { expr: ExprId, - pat: Pat<'tcx>, + pat: Box>, }, /// A `match` expression. Match { @@ -307,7 +328,7 @@ pub enum ExprKind<'tcx> { }, /// A block. Block { - body: Block, + block: BlockId, }, /// An assignment: `lhs = rhs`. Assign { @@ -387,27 +408,21 @@ pub enum ExprKind<'tcx> { fields: Box<[ExprId]>, }, /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`. - Adt(Box>), + Adt(Box>), /// A type ascription on a place. PlaceTypeAscription { source: ExprId, /// Type that the user gave to this expression - user_ty: Option>>, + user_ty: UserTy<'tcx>, }, /// A type ascription on a value, e.g. `42: i32`. ValueTypeAscription { source: ExprId, /// Type that the user gave to this expression - user_ty: Option>>, + user_ty: UserTy<'tcx>, }, /// A closure definition. - Closure { - closure_id: LocalDefId, - substs: UpvarSubsts<'tcx>, - upvars: Box<[ExprId]>, - movability: Option, - fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>, - }, + Closure(Box>), /// A literal. Literal { lit: &'tcx hir::Lit, @@ -416,17 +431,17 @@ pub enum ExprKind<'tcx> { /// For literals that don't correspond to anything in the HIR NonHirLiteral { lit: ty::ScalarInt, - user_ty: Option>>, + user_ty: UserTy<'tcx>, }, /// A literal of a ZST type. ZstLiteral { - user_ty: Option>>, + user_ty: UserTy<'tcx>, }, /// Associated constants and named constants NamedConst { def_id: DefId, substs: SubstsRef<'tcx>, - user_ty: Option>>, + user_ty: UserTy<'tcx>, }, ConstParam { param: ty::ParamConst, @@ -443,12 +458,7 @@ pub enum ExprKind<'tcx> { def_id: DefId, }, /// Inline assembly, i.e. `asm!()`. - InlineAsm { - template: &'tcx [InlineAsmTemplatePiece], - operands: Box<[InlineAsmOperand<'tcx>]>, - options: InlineAsmOptions, - line_spans: &'tcx [Span], - }, + InlineAsm(Box>), /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), /// A `yield` expression. @@ -475,7 +485,7 @@ pub struct FruInfo<'tcx> { /// A `match` arm. #[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { - pub pattern: Pat<'tcx>, + pub pattern: Box>, pub guard: Option>, pub body: ExprId, pub lint_level: LintLevel, @@ -487,7 +497,7 @@ pub struct Arm<'tcx> { #[derive(Clone, Debug, HashStable)] pub enum Guard<'tcx> { If(ExprId), - IfLet(Pat<'tcx>, ExprId), + IfLet(Box>, ExprId), } #[derive(Copy, Clone, Debug, HashStable)] @@ -542,19 +552,28 @@ pub enum BindingMode { #[derive(Clone, Debug, HashStable)] pub struct FieldPat<'tcx> { pub field: Field, - pub pattern: Pat<'tcx>, + pub pattern: Box>, } #[derive(Clone, Debug, HashStable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, - pub kind: Box>, + pub kind: PatKind<'tcx>, } impl<'tcx> Pat<'tcx> { pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self { - Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) } + Pat { ty, span: DUMMY_SP, kind: PatKind::Wild } + } + + pub fn simple_ident(&self) -> Option { + match self.kind { + PatKind::Binding { name, mode: BindingMode::ByValue, subpattern: None, .. } => { + Some(name) + } + _ => None, + } } } @@ -589,7 +608,7 @@ pub enum PatKind<'tcx> { AscribeUserType { ascription: Ascription<'tcx>, - subpattern: Pat<'tcx>, + subpattern: Box>, }, /// `x`, `ref x`, `x @ P`, etc. @@ -599,7 +618,7 @@ pub enum PatKind<'tcx> { mode: BindingMode, var: LocalVarId, ty: Ty<'tcx>, - subpattern: Option>, + subpattern: Option>>, /// Is this the leftmost occurrence of the binding, i.e., is `var` the /// `HirId` of this pattern? is_primary: bool, @@ -622,7 +641,7 @@ pub enum PatKind<'tcx> { /// `box P`, `&P`, `&mut P`, etc. Deref { - subpattern: Pat<'tcx>, + subpattern: Box>, }, /// One of the following: @@ -636,32 +655,32 @@ pub enum PatKind<'tcx> { value: mir::ConstantKind<'tcx>, }, - Range(PatRange<'tcx>), + Range(Box>), /// Matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// e.g., `&[ref xs @ ..]`. Slice { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Box<[Box>]>, + slice: Option>>, + suffix: Box<[Box>]>, }, /// Fixed match against an array; irrefutable. Array { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Box<[Box>]>, + slice: Option>>, + suffix: Box<[Box>]>, }, /// An or-pattern, e.g. `p | q`. /// Invariant: `pats.len() >= 2`. Or { - pats: Vec>, + pats: Box<[Box>]>, }, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { pub lo: mir::ConstantKind<'tcx>, pub hi: mir::ConstantKind<'tcx>, @@ -682,7 +701,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; let mut start_or_comma = || start_or_continue(", "); - match *self.kind { + match self.kind { PatKind::Wild => write!(f, "_"), PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern), PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { @@ -703,17 +722,32 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant = match *self.kind { - PatKind::Variant { adt_def, variant_index, .. } => { - Some(adt_def.variant(variant_index)) - } - _ => self.ty.ty_adt_def().and_then(|adt| { - if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None } + let variant_and_name = match self.kind { + PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { + let variant = adt_def.variant(variant_index); + let adt_did = adt_def.did(); + let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) + || tcx.get_diagnostic_item(sym::Result) == Some(adt_did) + { + variant.name.to_string() + } else { + format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) + }; + Some((variant, name)) + }), + _ => self.ty.ty_adt_def().and_then(|adt_def| { + if !adt_def.is_enum() { + ty::tls::with(|tcx| { + Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) + }) + } else { + None + } }), }; - if let Some(variant) = variant { - write!(f, "{}", variant.name)?; + if let Some((variant, name)) = &variant_and_name { + write!(f, "{}", name)?; // Only for Adt we can have `S {...}`, // which we handle separately here. @@ -722,7 +756,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { let mut printed = 0; for p in subpatterns { - if let PatKind::Wild = *p.pattern.kind { + if let PatKind::Wild = p.pattern.kind { continue; } let name = variant.fields[p.field.index()].name; @@ -738,8 +772,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } - let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); - if num_fields != 0 || variant.is_none() { + let num_fields = + variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len()); + if num_fields != 0 || variant_and_name.is_none() { write!(f, "(")?; for i in 0..num_fields { write!(f, "{}", start_or_comma())?; @@ -775,7 +810,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { write!(f, "{}", subpattern) } PatKind::Constant { value } => write!(f, "{}", value), - PatKind::Range(PatRange { lo, hi, end }) => { + PatKind::Range(box PatRange { lo, hi, end }) => { write!(f, "{}", lo)?; write!(f, "{}", end)?; write!(f, "{}", hi) @@ -783,24 +818,24 @@ impl<'tcx> fmt::Display for Pat<'tcx> { PatKind::Slice { ref prefix, ref slice, ref suffix } | PatKind::Array { ref prefix, ref slice, ref suffix } => { write!(f, "[")?; - for p in prefix { + for p in prefix.iter() { write!(f, "{}{}", start_or_comma(), p)?; } if let Some(ref slice) = *slice { write!(f, "{}", start_or_comma())?; - match *slice.kind { + match slice.kind { PatKind::Wild => {} _ => write!(f, "{}", slice)?, } write!(f, "..")?; } - for p in suffix { + for p in suffix.iter() { write!(f, "{}{}", start_or_comma(), p)?; } write!(f, "]") } PatKind::Or { ref pats } => { - for pat in pats { + for pat in pats.iter() { write!(f, "{}{}", start_or_continue(" | "), pat)?; } Ok(()) @@ -814,8 +849,15 @@ impl<'tcx> fmt::Display for Pat<'tcx> { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Block, 56); - rustc_data_structures::static_assert_size!(Expr<'_>, 104); - rustc_data_structures::static_assert_size!(Pat<'_>, 24); - rustc_data_structures::static_assert_size!(Stmt<'_>, 120); + static_assert_size!(Block, 56); + static_assert_size!(Expr<'_>, 64); + static_assert_size!(ExprKind<'_>, 40); + #[cfg(not(bootstrap))] + static_assert_size!(Pat<'_>, 72); + #[cfg(not(bootstrap))] + static_assert_size!(PatKind<'_>, 56); + #[cfg(not(bootstrap))] + static_assert_size!(Stmt<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(StmtKind<'_>, 40); } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 97249fdd1..79a0e75aa 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,5 +1,6 @@ use super::{ - Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, + AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, Guard, InlineAsmExpr, InlineAsmOperand, Pat, + PatKind, Stmt, StmtKind, Thir, }; pub trait Visitor<'a, 'tcx: 'a>: Sized { @@ -75,7 +76,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_arm(&visitor.thir()[arm]); } } - Block { ref body } => visitor.visit_block(body), + Block { block } => visitor.visit_block(&visitor.thir()[block]), Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { visitor.visit_expr(&visitor.thir()[lhs]); visitor.visit_expr(&visitor.thir()[rhs]); @@ -108,7 +109,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_expr(&visitor.thir()[field]); } } - Adt(box crate::thir::Adt { + Adt(box AdtExpr { ref fields, ref base, adt_def: _, @@ -126,14 +127,20 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { visitor.visit_expr(&visitor.thir()[source]) } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Closure(box ClosureExpr { + closure_id: _, + substs: _, + upvars: _, + movability: _, + fake_reads: _, + }) => {} Literal { lit: _, neg: _ } => {} NonHirLiteral { lit: _, user_ty: _ } => {} ZstLiteral { user_ty: _ } => {} NamedConst { def_id: _, substs: _, user_ty: _ } => {} ConstParam { param: _, def_id: _ } => {} StaticRef { alloc_id: _, ty: _, def_id: _ } => {} - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => { for op in &**operands { use InlineAsmOperand::*; match op { @@ -174,7 +181,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm } visitor.visit_pat(pattern); if let Some(block) = else_block { - visitor.visit_block(block) + visitor.visit_block(&visitor.thir()[*block]) } } } @@ -204,7 +211,7 @@ pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<' pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { use PatKind::*; - match pat.kind.as_ref() { + match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } | Binding { @@ -225,18 +232,18 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' Constant { value: _ } => {} Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { + for subpattern in prefix.iter() { visitor.visit_pat(&subpattern); } if let Some(pat) = slice { - visitor.visit_pat(pat); + visitor.visit_pat(&pat); } - for subpattern in suffix { + for subpattern in suffix.iter() { visitor.visit_pat(&subpattern); } } Or { pats } => { - for pat in pats { + for pat in pats.iter() { visitor.visit_pat(&pat); } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 72b848c3e..68a7af0b8 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -10,9 +10,10 @@ mod structural_impls; pub mod util; use crate::infer::canonical::Canonical; +use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -183,6 +184,16 @@ impl<'tcx> ObligationCause<'tcx> { variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into(); self } + + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { + match self.code() { + MatchImpl(cause, _) => cause.to_constraint_category(), + AscribeUserTypeProvePredicate(predicate_span) => { + ConstraintCategory::Predicate(*predicate_span) + } + _ => ConstraintCategory::BoringNoLocation, + } + } } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] @@ -234,13 +245,23 @@ pub enum ObligationCauseCode<'tcx> { /// This is the trait reference from the given projection. ProjectionWf(ty::ProjectionTy<'tcx>), - /// In an impl of trait `X` for type `Y`, type `Y` must - /// also implement all supertraits of `X`. + /// Must satisfy all of the where-clause predicates of the + /// given item. ItemObligation(DefId), - /// Like `ItemObligation`, but with extra detail on the source of the obligation. + /// Like `ItemObligation`, but carries the span of the + /// predicate when it can be identified. BindingObligation(DefId, Span), + /// Like `ItemObligation`, but carries the `HirId` of the + /// expression that caused the obligation, and the `usize` + /// indicates exactly which predicate it is in the list of + /// instantiated predicates. + ExprItemObligation(DefId, rustc_hir::HirId, usize), + + /// Combines `ExprItemObligation` and `BindingObligation`. + ExprBindingObligation(DefId, Span, rustc_hir::HirId, usize), + /// A type like `&'a T` is WF only if `T: 'a`. ReferenceOutlivesReferent(Ty<'tcx>), @@ -406,8 +427,10 @@ pub enum ObligationCauseCode<'tcx> { BinOp { rhs_span: Option, is_lit: bool, - output_pred: Option>, + output_ty: Option>, }, + + AscribeUserTypeProvePredicate(Span), } /// The 'location' at which we try to perform HIR-based wf checking. @@ -459,6 +482,13 @@ impl<'tcx> ObligationCauseCode<'tcx> { _ => None, } } + + pub fn peel_match_impls(&self) -> &Self { + match self { + MatchImpl(cause, _) => cause.code(), + _ => self, + } + } } // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -634,6 +664,10 @@ pub enum ImplSource<'tcx, N> { /// ImplSource for a `const Drop` implementation. ConstDestruct(ImplSourceConstDestructData), + + /// ImplSource for a `std::marker::Tuple` implementation. + /// This has no nested predicates ever, so no data. + Tuple, } impl<'tcx, N> ImplSource<'tcx, N> { @@ -648,7 +682,8 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(), + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::Tuple => Vec::new(), ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, ImplSource::ConstDestruct(i) => i.nested, @@ -666,7 +701,8 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => &d.nested, ImplSource::FnPointer(d) => &d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => &[], + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::Tuple => &[], ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, ImplSource::ConstDestruct(i) => &i.nested, @@ -733,6 +769,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { nested: i.nested.into_iter().map(f).collect(), }) } + ImplSource::Tuple => ImplSource::Tuple, } } } @@ -891,6 +928,12 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { format!("method `{}` references the `Self` type in its return type", name).into() } + ObjectSafetyViolation::Method( + name, + MethodViolationCode::ReferencesImplTraitInTrait, + _, + ) => format!("method `{}` references an `impl Trait` type in its return type", name) + .into(), ObjectSafetyViolation::Method( name, MethodViolationCode::WhereClauseReferencesSelf, @@ -997,6 +1040,9 @@ pub enum MethodViolationCode { /// e.g., `fn foo(&self) -> Self` ReferencesSelfOutput, + /// e.g., `fn foo(&self) -> impl Sized` + ReferencesImplTraitInTrait, + /// e.g., `fn foo(&self) where Self: Clone` WhereClauseReferencesSelf, @@ -1007,7 +1053,7 @@ pub enum MethodViolationCode { UndispatchableReceiver(Option), } -/// These are the error cases for `codegen_fulfill_obligation`. +/// These are the error cases for `codegen_select_candidate`. #[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)] pub enum CodegenObligationError { /// Ambiguity can happen when monomorphizing during trans diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 1f9b474ad..0e6cacb9f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -5,11 +5,11 @@ //! The providers for the queries defined here can be found in //! `rustc_traits`. +use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use rustc_errors::struct_span_err; use rustc_span::source_map::Span; use std::iter::FromIterator; @@ -117,15 +117,7 @@ pub struct DropckOutlivesResult<'tcx> { impl<'tcx> DropckOutlivesResult<'tcx> { pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { if let Some(overflow_ty) = self.overflows.get(0) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - ty, - ); - err.note(&format!("overflowed on {}", overflow_ty)); - err.emit(); + tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty }); } } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index e836ba47e..53af3e905 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`. ConstDestructCandidate(Option), + + /// Witnesses the fact that a type is a tuple. + TupleCandidate, } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 2465f8e25..0a2819fee 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -115,7 +115,7 @@ impl Node { matches!(self, Node::Trait(..)) } - /// Trys to find the associated item that implements `trait_item_def_id` + /// Tries to find the associated item that implements `trait_item_def_id` /// defined in this node. /// /// If this returns `None`, the item can potentially still be found in diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 7fbd57ac7..c526344e1 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -34,6 +34,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d), + + super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"), } } } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index bed809930..8f79b4705 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -42,7 +42,7 @@ impl<'tcx> AbstractConst<'tcx> { ct: ty::Const<'tcx>, ) -> Result>, ErrorGuaranteed> { match ct.kind() { - ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()), + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported), _ => Ok(None), } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index d36cf2fe3..b809f1767 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -77,7 +77,7 @@ pub enum PointerCast { /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` -> /// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, pub target: Ty<'tcx>, @@ -89,7 +89,7 @@ impl<'tcx> Adjustment<'tcx> { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, @@ -108,7 +108,7 @@ pub enum Adjust<'tcx> { /// The target type is `U` in both cases, with the region and mutability /// being those shared by both the receiver and the returned reference. #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable, Lift)] pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, @@ -167,7 +167,7 @@ impl From for hir::Mutability { } #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable, Lift)] pub enum AutoBorrow<'tcx> { /// Converts from T to &T. Ref(ty::Region<'tcx>, AutoBorrowMutability), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index c97156ac1..55ee5bd2f 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -42,7 +42,7 @@ impl AssocItem { } #[inline] - pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility { + pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility { tcx.visibility(self.def_id) } diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 3d65429f2..a5b05a4f9 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -1,6 +1,4 @@ -use rustc_hir::BindingAnnotation; -use rustc_hir::BindingAnnotation::*; -use rustc_hir::Mutability; +use rustc_hir::{BindingAnnotation, ByRef, Mutability}; #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)] pub enum BindingMode { @@ -11,12 +9,10 @@ pub enum BindingMode { TrivialTypeTraversalAndLiftImpls! { BindingMode, } impl BindingMode { - pub fn convert(ba: BindingAnnotation) -> BindingMode { - match ba { - Unannotated => BindingMode::BindByValue(Mutability::Not), - Mutable => BindingMode::BindByValue(Mutability::Mut), - Ref => BindingMode::BindByReference(Mutability::Not), - RefMut => BindingMode::BindByReference(Mutability::Mut), + pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { + match by_ref { + ByRef::No => BindingMode::BindByValue(mutbl), + ByRef::Yes => BindingMode::BindByReference(mutbl), } } } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c4b743dd4..981e2d3b6 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -33,6 +33,8 @@ pub enum CastTy<'tcx> { FnPtr, /// Raw pointers. Ptr(ty::TypeAndMut<'tcx>), + /// Casting into a `dyn*` value. + DynStar, } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) @@ -50,6 +52,7 @@ pub enum CastKind { ArrayPtrCast, FnPtrPtrCast, FnPtrAddrCast, + DynStarCast, } impl<'tcx> CastTy<'tcx> { @@ -67,6 +70,7 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::FnPtr(..) => Some(CastTy::FnPtr), + ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f8792edc0..339ff4d35 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -41,7 +41,7 @@ pub struct ConstS<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstS<'_>, 48); +static_assert_size!(ConstS<'_>, 40); impl<'tcx> Const<'tcx> { #[inline] @@ -65,8 +65,6 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> Self { - debug!("Const::from_anon_const(def={:?})", def); - let body_id = match tcx.hir().get_by_def_id(def.did) { hir::Node::AnonConst(ac) => ac.body, _ => span_bug!( @@ -86,7 +84,7 @@ impl<'tcx> Const<'tcx> { kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), - promoted: None, + promoted: (), }), ty, }), @@ -183,7 +181,7 @@ impl<'tcx> Const<'tcx> { kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def: ty::WithOptConstParam::unknown(def_id).to_global(), substs, - promoted: None, + promoted: (), }), ty, }) diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index cb0137d2e..455015280 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -11,6 +11,7 @@ use rustc_macros::HashStable; use rustc_target::abi::Size; use super::ScalarInt; + /// An unevaluated, potentially generic, constant. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable)] @@ -20,6 +21,12 @@ pub struct Unevaluated<'tcx, P = Option> { pub promoted: P, } +impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{:?}", self).into_diagnostic_arg() + } +} + impl<'tcx> Unevaluated<'tcx> { #[inline] pub fn shrink(self) -> Unevaluated<'tcx, ()> { @@ -44,7 +51,7 @@ impl<'tcx, P: Default> Unevaluated<'tcx, P> { /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable)] +#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum ConstKind<'tcx> { /// A const generic parameter. Param(ty::ParamConst), @@ -60,7 +67,7 @@ pub enum ConstKind<'tcx> { /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other /// variants when the code is monomorphic enough for that. - Unevaluated(Unevaluated<'tcx>), + Unevaluated(Unevaluated<'tcx, ()>), /// Used to hold computed value. Value(ty::ValTree<'tcx>), @@ -71,7 +78,7 @@ pub enum ConstKind<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstKind<'_>, 40); +static_assert_size!(ConstKind<'_>, 32); impl<'tcx> ConstKind<'tcx> { #[inline] @@ -174,9 +181,12 @@ impl<'tcx> ConstKind<'tcx> { param_env: ParamEnv<'tcx>, eval_mode: EvalMode, ) -> Option, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; + assert_eq!(unevaluated.promoted, ()); + // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` // also does later, but we want to do it before checking for // inference variables. @@ -197,7 +207,7 @@ impl<'tcx> ConstKind<'tcx> { tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { def: unevaluated.def, substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did), - promoted: unevaluated.promoted, + promoted: (), }) } else { param_env_and @@ -221,7 +231,7 @@ impl<'tcx> ConstKind<'tcx> { } } EvalMode::Mir => { - match tcx.const_eval_resolve(param_env, unevaluated, None) { + match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { // NOTE(eddyb) `val` contains no lifetimes/types/consts, // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 93707bb18..a803fca0d 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. pub enum ValTree<'tcx> { - /// ZSTs, integers, `bool`, `char` are represented as scalars. + /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), @@ -27,8 +27,11 @@ pub enum ValTree<'tcx> { // dont use SliceOrStr for now /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by /// listing their fields' values in order. + /// /// Enums are represented by storing their discriminant as a field, followed by all /// the fields of the variant. + /// + /// ZST types are represented as an empty slice. Branch(&'tcx [ValTree<'tcx>]), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0a0f45ce1..0b497fa4a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -22,6 +22,7 @@ use crate::ty::{ FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, + Visibility, }; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -62,7 +63,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags}; +use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; use std::borrow::Borrow; @@ -275,9 +276,6 @@ pub struct CommonTypes<'tcx> { } pub struct CommonLifetimes<'tcx> { - /// `ReEmpty` in the root universe. - pub re_root_empty: Region<'tcx>, - /// `ReStatic` pub re_static: Region<'tcx>, @@ -874,7 +872,7 @@ pub type CanonicalUserTypeAnnotations<'tcx> = #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalUserTypeAnnotation<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, + pub user_ty: Box>, pub span: Span, pub inferred_ty: Ty<'tcx>, } @@ -986,11 +984,7 @@ impl<'tcx> CommonLifetimes<'tcx> { )) }; - CommonLifetimes { - re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)), - re_static: mk(ty::ReStatic), - re_erased: mk(ty::ReErased), - } + CommonLifetimes { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased) } } } @@ -1089,7 +1083,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, - query_kinds: &'tcx [DepKindStruct], + query_kinds: &'tcx [DepKindStruct<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock>>, @@ -1246,12 +1240,12 @@ impl<'tcx> TyCtxt<'tcx> { dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, - query_kinds: &'tcx [DepKindStruct], + query_kinds: &'tcx [DepKindStruct<'tcx>], crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { - s.fatal(&err); + s.emit_fatal(err); }); let interners = CtxtInterners::new(arena); let common_types = CommonTypes::new( @@ -1296,7 +1290,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { + pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> { &self.query_kinds[k as usize] } @@ -1498,17 +1492,17 @@ impl<'tcx> TyCtxt<'tcx> { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.iter_local_def_id() } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_table() @@ -1517,10 +1511,10 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path_hash_to_def_index_map( self, ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_hash_to_def_index_map() @@ -1596,7 +1590,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. + /// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { @@ -1728,6 +1722,11 @@ impl<'tcx> TyCtxt<'tcx> { .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) } + + #[inline] + pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { + self.visibility(def_id.to_def_id()).expect_local() + } } /// A trait implemented for all `X<'a>` types that can be safely and @@ -1821,7 +1820,9 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } +CloneLiftImpls! { for<'tcx> { + Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint, +} } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; @@ -1829,9 +1830,9 @@ pub mod tls { use crate::dep_graph::TaskDepsRef; use crate::ty::query; use rustc_data_structures::sync::{self, Lock}; - use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use std::mem; + use thin_vec::ThinVec; #[cfg(not(parallel_compiler))] use std::cell::Cell; @@ -1857,8 +1858,8 @@ pub mod tls { /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. pub diagnostics: Option<&'a Lock>>, - /// Used to prevent layout from recursing too deeply. - pub layout_depth: usize, + /// Used to prevent queries from calling too deeply. + pub query_depth: usize, /// The current dep graph task. This is used to add dependencies to queries /// when executing them. @@ -1872,7 +1873,7 @@ pub mod tls { tcx, query: None, diagnostics: None, - layout_depth: 0, + query_depth: 0, task_deps: TaskDepsRef::Ignore, } } @@ -2546,8 +2547,9 @@ impl<'tcx> TyCtxt<'tcx> { self, obj: &'tcx List>>, reg: ty::Region<'tcx>, + repr: DynKind, ) -> Ty<'tcx> { - self.mk_ty(Dynamic(obj, reg)) + self.mk_ty(Dynamic(obj, reg, repr)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index dd2f43210..855917fb8 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -102,13 +102,25 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( generics: &hir::Generics<'_>, err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, + associated_ty: Option<(&'static str, Ty<'tcx>)>, ) -> bool { if !trait_pred.is_suggestable(tcx, false) { return false; } let param_name = trait_pred.skip_binder().self_ty().to_string(); - let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + + if let Some((name, term)) = associated_ty { + // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. + // That should be extracted into a helper function. + if constraint.ends_with('>') { + constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term); + } else { + constraint.push_str(&format!("<{} = {}>", name, term)); + } + } + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); // Skip, there is a param named Self @@ -396,7 +408,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { ) => { self.0.push(ty); } - hir::TyKind::OpaqueDef(item_id, _) => { + hir::TyKind::OpaqueDef(item_id, _, _) => { self.0.push(ty); let item = self.1.item(item_id); hir::intravisit::walk_item(self, item); @@ -455,7 +467,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } - Dynamic(dty, _) => { + Dynamic(dty, _, _) => { for pred in *dty { match pred.skip_binder() { ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 4b0bc3c11..01e1e97b2 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -2,6 +2,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; +use hir::def::DefKind; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -13,7 +14,7 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::fmt; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)] pub struct ExpectedFound { pub expected: T, pub found: T, @@ -30,7 +31,8 @@ impl ExpectedFound { } // Data structures used in type unification -#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] +#[rustc_pass_by_value] pub enum TypeError<'tcx> { Mismatch, ConstnessMismatch(ExpectedFound), @@ -73,6 +75,18 @@ pub enum TypeError<'tcx> { TargetFeatureCast(DefId), } +impl TypeError<'_> { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsOverlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } +} + /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related @@ -211,7 +225,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(&self) -> bool { + pub fn must_include_note(self) -> bool { use self::TypeError::*; match self { CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) @@ -263,10 +277,23 @@ impl<'tcx> Ty<'tcx> { } ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(), ty::Slice(_) => "slice".into(), - ty::RawPtr(_) => "*-ptr".into(), + ty::RawPtr(tymut) => { + let tymut_string = match tymut.mutbl { + hir::Mutability::Mut => tymut.to_string(), + hir::Mutability::Not => format!("const {}", tymut.ty), + }; + + if tymut_string != "_" && (tymut.ty.is_simple_text() || tymut_string.len() < "const raw pointer".len()) { + format!("`*{}`", tymut_string).into() + } else { + // Unknown type name, it's long or has type arguments + "raw pointer".into() + } + }, ty::Ref(_, ty, mutbl) => { let tymut = ty::TypeAndMut { ty, mutbl }; let tymut_string = tymut.to_string(); + if tymut_string != "_" && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len()) { @@ -347,7 +374,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn note_and_explain_type_err( self, diag: &mut Diagnostic, - err: &TypeError<'tcx>, + err: TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, body_owner_def_id: DefId, @@ -512,7 +539,7 @@ impl Trait for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Projection(proj_ty), _) => { + (ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => { self.expected_projection( diag, proj_ty, @@ -521,7 +548,7 @@ impl Trait for X { cause.code(), ); } - (_, ty::Projection(proj_ty)) => { + (_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => { let msg = format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, @@ -568,7 +595,7 @@ impl Trait for X { } TargetFeatureCast(def_id) => { let target_spans = - self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span); + self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); @@ -640,7 +667,7 @@ impl Trait for X { self, diag: &mut Diagnostic, proj_ty: &ty::ProjectionTy<'tcx>, - values: &ExpectedFound>, + values: ExpectedFound>, body_owner_def_id: DefId, cause_code: &ObligationCauseCode<'_>, ) { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ea6bb8a7a..98b8a7386 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -1,5 +1,5 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, InferConst, Term, Ty, TypeFlags}; +use crate::ty::{self, InferConst, Ty, TypeFlags}; use std::slice; #[derive(Debug)] @@ -171,7 +171,7 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Dynamic(obj, r) => { + &ty::Dynamic(obj, r, _) => { for predicate in obj.iter() { self.bound_computation(predicate, |computation, predicate| match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), @@ -243,9 +243,9 @@ impl FlagComputation { } ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { self.add_projection_ty(projection_ty); - match term { - Term::Ty(ty) => self.add_ty(ty), - Term::Const(c) => self.add_const(c), + match term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(c) => self.add_const(c), } } ty::PredicateKind::WellFormed(arg) => { @@ -320,9 +320,9 @@ impl FlagComputation { fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); - match projection.term { - ty::Term::Ty(ty) => self.add_ty(ty), - ty::Term::Const(ct) => self.add_const(ct), + match projection.term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e96e278b..cac95e14a 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -302,6 +302,17 @@ impl<'tcx> TyCtxt<'tcx> { { value.fold_with(&mut RegionFolder::new(self, &mut f)) } + + pub fn super_fold_regions( + self, + value: T, + mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> T + where + T: TypeSuperFoldable<'tcx>, + { + value.super_fold_with(&mut RegionFolder::new(self, &mut f)) + } } /// Folds over the substructure of a type, visiting its component @@ -353,7 +364,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { t } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { @@ -377,17 +388,13 @@ pub trait BoundVarReplacerDelegate<'tcx> { fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>; } -pub struct FnMutDelegate { - pub regions: R, - pub types: T, - pub consts: C, +pub struct FnMutDelegate<'a, 'tcx> { + pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), + pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a), } -impl<'tcx, R, T, C> BoundVarReplacerDelegate<'tcx> for FnMutDelegate -where - R: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - T: FnMut(ty::BoundTy) -> Ty<'tcx>, - C: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>, -{ + +impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> { (self.regions)(br) } @@ -511,7 +518,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_late_bound_regions_uncached( self, value: Binder<'tcx, T>, - replace_regions: F, + mut replace_regions: F, ) -> T where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -522,9 +529,9 @@ impl<'tcx> TyCtxt<'tcx> { value } else { let delegate = FnMutDelegate { - regions: replace_regions, - types: |b| bug!("unexpected bound ty in binder: {b:?}"), - consts: |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + regions: &mut replace_regions, + types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), + consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); value.fold_with(&mut replacer) @@ -584,19 +591,19 @@ impl<'tcx> TyCtxt<'tcx> { self.replace_escaping_bound_vars_uncached( value, FnMutDelegate { - regions: |r: ty::BoundRegion| { + regions: &mut |r: ty::BoundRegion| { self.mk_region(ty::ReLateBound( ty::INNERMOST, ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, )) }, - types: |t: ty::BoundTy| { + types: &mut |t: ty::BoundTy| { self.mk_ty(ty::Bound( ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, )) }, - consts: |c, ty: Ty<'tcx>| { + consts: &mut |c, ty: Ty<'tcx>| { self.mk_const(ty::ConstS { kind: ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index add2df258..0c8bdde9c 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,4 +1,3 @@ -use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::ty; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::EarlyBinder; @@ -13,7 +12,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { Lifetime, - Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool }, + Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } @@ -28,8 +27,9 @@ impl GenericParamDefKind { pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, - GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type, - GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const, + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + ast::ParamKindOrd::TypeOrConst + } } } @@ -122,6 +122,21 @@ pub struct Generics { } impl<'tcx> Generics { + /// Looks through the generics and all parents to find the index of the + /// given param def-id. This is in comparison to the `param_def_id_to_index` + /// struct member, which only stores information about this item's own + /// generics. + pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + if let Some(idx) = self.param_def_id_to_index.get(&def_id) { + Some(*idx) + } else if let Some(parent) = self.parent { + let parent = tcx.generics_of(parent); + parent.param_def_id_to_index(tcx, def_id) + } else { + None + } + } + #[inline] pub fn count(&self) -> usize { self.parent_count + self.params.len() @@ -252,7 +267,7 @@ impl<'tcx> Generics { // Filter the default arguments. // // This currently uses structural equality instead - // of semantic equivalance. While not ideal, that's + // of semantic equivalence. While not ideal, that's // good enough for now as this should only be used // for diagnostics anyways. own_params.end -= self @@ -314,6 +329,7 @@ impl<'tcx> GenericPredicates<'tcx> { } } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index cd00b26b8..d1c0d62ac 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -113,7 +113,7 @@ impl<'a> HashStable> for mir::interpret::AllocId { } // `Relocations` with default type parameters is a sorted map. -impl<'a, Prov> HashStable> for mir::interpret::Relocations +impl<'a, Prov> HashStable> for mir::interpret::ProvenanceMap where Prov: HashStable>, { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 3d22f5a04..aaa66deb2 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -169,14 +169,10 @@ impl<'tcx> FieldDef { param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest<'tcx> { let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); - // FIXME(canndrew): Currently enum fields are (incorrectly) stored with - // `Visibility::Invisible` so we need to override `self.vis` if we're - // dealing with an enum. if is_enum { data_uninhabitedness() } else { match self.vis { - Visibility::Invisible => DefIdForest::empty(), Visibility::Restricted(from) => { let forest = DefIdForest::from_id(from); let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 53218225d..9afd66207 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -20,14 +20,14 @@ use std::fmt; /// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval /// will do all required substitution as they run. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, Lift)] +#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct Instance<'tcx> { pub def: InstanceDef<'tcx>, pub substs: SubstsRef<'tcx>, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum InstanceDef<'tcx> { /// A user-defined callable item. /// diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ad78d24e9..042eeec3f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,10 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::subst::Subst; -use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable}; +use crate::ty::{ + self, layout_sanity_check::sanity_check_layout, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, + TyCtxt, TypeVisitable, +}; use rustc_ast as ast; use rustc_attr as attr; use rustc_hir as hir; @@ -19,7 +22,7 @@ use rustc_target::abi::call::{ use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; -use std::cmp; +use std::cmp::{self, Ordering}; use std::fmt; use std::iter; use std::num::NonZeroUsize; @@ -221,164 +224,46 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -/// Enforce some basic invariants on layouts. -fn sanity_check_layout<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - layout: &TyAndLayout<'tcx>, -) { - // Type-level uninhabitedness should always imply ABI uninhabitedness. - if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) { - assert!(layout.abi.is_uninhabited()); - } - - if layout.size.bytes() % layout.align.abi.bytes() != 0 { - bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); - } - - if cfg!(debug_assertions) { - fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) { - match layout.abi() { - Abi::Scalar(scalar) => { - // No padding in scalars. - assert_eq!( - layout.align().abi, - scalar.align(&tcx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.size(), - scalar.size(&tcx), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::Vector { count, element } => { - // No padding in vectors. Alignment can be strengthened, though. - assert!( - layout.align().abi >= element.align(&tcx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - let size = element.size(&tcx) * count; - assert_eq!( - layout.size(), - size.align_to(tcx.data_layout().vector_align(size).abi), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::ScalarPair(scalar1, scalar2) => { - // Sanity-check scalar pairs. These are a bit more flexible and support - // padding, but we can at least ensure both fields actually fit into the layout - // and the alignment requirement has not been weakened. - let align1 = scalar1.align(&tcx).abi; - let align2 = scalar2.align(&tcx).abi; - assert!( - layout.align().abi >= cmp::max(align1, align2), - "alignment mismatch between ABI and layout in {layout:#?}", - ); - let field2_offset = scalar1.size(&tcx).align_to(align2); - assert!( - layout.size() >= field2_offset + scalar2.size(&tcx), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. - } - } - - check_layout_abi(tcx, layout.layout); - - if let Variants::Multiple { variants, .. } = &layout.variants { - for variant in variants { - check_layout_abi(tcx, *variant); - // No nested "multiple". - assert!(matches!(variant.variants(), Variants::Single { .. })); - // Skip empty variants. - if variant.size() == Size::ZERO - || variant.fields().count() == 0 - || variant.abi().is_uninhabited() - { - // These are never actually accessed anyway, so we can skip them. (Note that - // sometimes, variants with fields have size 0, and sometimes, variants without - // fields have non-0 size.) - continue; - } - // Variants should have the same or a smaller size as the full thing. - if variant.size() > layout.size { - bug!( - "Type with size {} bytes has variant with size {} bytes: {layout:#?}", - layout.size.bytes(), - variant.size().bytes(), - ) - } - // The top-level ABI and the ABI of the variants should be coherent. - let abi_coherent = match (layout.abi, variant.abi()) { - (Abi::Scalar(..), Abi::Scalar(..)) => true, - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, - (Abi::Uninhabited, _) => true, - (Abi::Aggregate { .. }, _) => true, - _ => false, - }; - if !abi_coherent { - bug!( - "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}", - variant - ); - } - } - } - } -} - #[instrument(skip(tcx, query), level = "debug")] fn layout_of<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result, LayoutError<'tcx>> { - ty::tls::with_related_context(tcx, move |icx| { - let (param_env, ty) = query.into_parts(); - debug!(?ty); - - if !tcx.recursion_limit().value_within_limit(icx.layout_depth) { - tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); + let (param_env, ty) = query.into_parts(); + debug!(?ty); + + let param_env = param_env.with_reveal_all_normalized(tcx); + let unnormalized_ty = ty; + + // FIXME: We might want to have two different versions of `layout_of`: + // One that can be called after typecheck has completed and can use + // `normalize_erasing_regions` here and another one that can be called + // before typecheck has completed and uses `try_normalize_erasing_regions`. + let ty = match tcx.try_normalize_erasing_regions(param_env, ty) { + Ok(t) => t, + Err(normalization_error) => { + return Err(LayoutError::NormalizationFailure(ty, normalization_error)); } + }; - // Update the ImplicitCtxt to increase the layout_depth - let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| { - let param_env = param_env.with_reveal_all_normalized(tcx); - let unnormalized_ty = ty; - - // FIXME: We might want to have two different versions of `layout_of`: - // One that can be called after typecheck has completed and can use - // `normalize_erasing_regions` here and another one that can be called - // before typecheck has completed and uses `try_normalize_erasing_regions`. - let ty = match tcx.try_normalize_erasing_regions(param_env, ty) { - Ok(t) => t, - Err(normalization_error) => { - return Err(LayoutError::NormalizationFailure(ty, normalization_error)); - } - }; - - if ty != unnormalized_ty { - // Ensure this layout is also cached for the normalized type. - return tcx.layout_of(param_env.and(ty)); - } + if ty != unnormalized_ty { + // Ensure this layout is also cached for the normalized type. + return tcx.layout_of(param_env.and(ty)); + } - let cx = LayoutCx { tcx, param_env }; + let cx = LayoutCx { tcx, param_env }; - let layout = cx.layout_of_uncached(ty)?; - let layout = TyAndLayout { ty, layout }; + let layout = cx.layout_of_uncached(ty)?; + let layout = TyAndLayout { ty, layout }; - cx.record_layout_for_printing(layout); + cx.record_layout_for_printing(layout); - sanity_check_layout(tcx, param_env, &layout); + sanity_check_layout(&cx, &layout); - Ok(layout) - }) - }) + Ok(layout) } +#[derive(Clone, Copy)] pub struct LayoutCx<'tcx, C> { pub tcx: C, pub param_env: ty::ParamEnv<'tcx>, @@ -740,6 +625,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) } + ty::Dynamic(_, _, ty::DynStar) => { + let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false)); + data.valid_range_mut().start = 0; + let mut vtable = scalar_unit(Pointer); + vtable.valid_range_mut().start = 1; + tcx.intern_layout(self.scalar_pair(data, vtable)) + } + // Arrays and slices. ty::Array(element, mut count) => { if count.has_projections() { @@ -794,7 +687,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Odd unit types. ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(..) | ty::Foreign(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { let mut unit = self.univariant_uninterned( ty, &[], @@ -872,7 +765,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // * the element type and length of the single array field, if // the first field is of array type, or // - // * the homogenous field type and the number of fields. + // * the homogeneous field type and the number of fields. let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { // First ADT field is an array: @@ -1161,131 +1054,191 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // that allow representation optimization.) assert!(def.is_enum()); - // The current code for niche-filling relies on variant indices - // instead of actual discriminants, so dataful enums with - // explicit discriminants (RFC #2363) would misbehave. - let no_explicit_discriminants = def - .variants() - .iter_enumerated() - .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32())); - - let mut niche_filling_layout = None; - - // Niche-filling enum optimization. - if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants { - let mut dataful_variant = None; - let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); + // Until we've decided whether to use the tagged or + // niche filling LayoutS, we don't want to intern the + // variant layouts, so we can't store them in the + // overall LayoutS. Store the overall LayoutS + // and the variant LayoutSs here until then. + struct TmpLayout<'tcx> { + layout: LayoutS<'tcx>, + variants: IndexVec>, + } - // Find one non-ZST variant. - 'variants: for (v, fields) in variants.iter_enumerated() { - if absent(fields) { - continue 'variants; + let calculate_niche_filling_layout = + || -> Result>, LayoutError<'tcx>> { + // The current code for niche-filling relies on variant indices + // instead of actual discriminants, so enums with + // explicit discriminants (RFC #2363) would misbehave. + if def.repr().inhibit_enum_layout_opt() + || def + .variants() + .iter_enumerated() + .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())) + { + return Ok(None); } - for f in fields { - if !f.is_zst() { - if dataful_variant.is_none() { - dataful_variant = Some(v); - continue 'variants; - } else { - dataful_variant = None; - break 'variants; - } - } + + if variants.len() < 2 { + return Ok(None); } - niche_variants = *niche_variants.start().min(&v)..=v; - } - if niche_variants.start() > niche_variants.end() { - dataful_variant = None; - } + let mut align = dl.aggregate_align; + let mut variant_layouts = variants + .iter_enumerated() + .map(|(j, v)| { + let mut st = self.univariant_uninterned( + ty, + v, + &def.repr(), + StructKind::AlwaysSized, + )?; + st.variants = Variants::Single { index: j }; + + align = align.max(st.align); + + Ok(st) + }) + .collect::, _>>()?; + + let largest_variant_index = match variant_layouts + .iter_enumerated() + .max_by_key(|(_i, layout)| layout.size.bytes()) + .map(|(i, _layout)| i) + { + None => return Ok(None), + Some(i) => i, + }; + + let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1); + let needs_disc = |index: VariantIdx| { + index != largest_variant_index && !absent(&variants[index]) + }; + let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() + ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); - if let Some(i) = dataful_variant { - let count = (niche_variants.end().as_u32() - - niche_variants.start().as_u32() - + 1) as u128; + let count = niche_variants.size_hint().1.unwrap() as u128; // Find the field with the largest niche - let niche_candidate = variants[i] + let (field_index, niche, (niche_start, niche_scalar)) = match variants + [largest_variant_index] .iter() .enumerate() .filter_map(|(j, field)| Some((j, field.largest_niche?))) - .max_by_key(|(_, niche)| niche.available(dl)); - - if let Some((field_index, niche, (niche_start, niche_scalar))) = - niche_candidate.and_then(|(field_index, niche)| { - Some((field_index, niche, niche.reserve(self, count)?)) - }) + .max_by_key(|(_, niche)| niche.available(dl)) + .and_then(|(j, niche)| Some((j, niche, niche.reserve(self, count)?))) { - let mut align = dl.aggregate_align; - let st = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = self.univariant_uninterned( - ty, - v, - &def.repr(), - StructKind::AlwaysSized, - )?; - st.variants = Variants::Single { index: j }; + None => return Ok(None), + Some(x) => x, + }; + + let niche_offset = niche.offset + + variant_layouts[largest_variant_index].fields.offset(field_index); + let niche_size = niche.value.size(dl); + let size = variant_layouts[largest_variant_index].size.align_to(align.abi); - align = align.max(st.align); + let all_variants_fit = + variant_layouts.iter_enumerated_mut().all(|(i, layout)| { + if i == largest_variant_index { + return true; + } - Ok(tcx.intern_layout(st)) - }) - .collect::, _>>()?; + layout.largest_niche = None; - let offset = st[i].fields().offset(field_index) + niche.offset; + if layout.size <= niche_offset { + // This variant will fit before the niche. + return true; + } - // Align the total size to the largest alignment. - let size = st[i].size().align_to(align.abi); + // 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); - let abi = if st.iter().all(|v| v.abi().is_uninhabited()) { - Abi::Uninhabited - } else if align == st[i].align() && size == st[i].size() { - // When the total alignment and size match, we can use the - // same ABI as the scalar variant with the reserved niche. - match st[i].abi() { - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { - // Only the niche is guaranteed to be initialised, - // so use union layout for the other primitive. - if offset.bytes() == 0 { - Abi::ScalarPair(niche_scalar, second.to_union()) - } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + if this_offset + layout.size > size { + return false; + } + + // It'll fit, but we need to make some adjustments. + match layout.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for (j, offset) in offsets.iter_mut().enumerate() { + if !variants[i][j].is_zst() { + *offset += this_offset; + } } } - _ => Abi::Aggregate { sized: true }, + _ => { + panic!("Layout of fields should be Arbitrary for variants") + } } - } else { - Abi::Aggregate { sized: true } - }; - let largest_niche = Niche::from_scalar(dl, offset, niche_scalar); - - niche_filling_layout = Some(LayoutS { - variants: Variants::Multiple { - tag: niche_scalar, - tag_encoding: TagEncoding::Niche { - dataful_variant: i, - niche_variants, - niche_start, - }, - tag_field: 0, - variants: st, - }, - fields: FieldsShape::Arbitrary { - offsets: vec![offset], - memory_index: vec![0], - }, - abi, - largest_niche, - size, - align, + // It can't be a Scalar or ScalarPair because the offset isn't 0. + if !layout.abi.is_uninhabited() { + layout.abi = Abi::Aggregate { sized: true }; + } + layout.size += this_offset; + + true }); + + if !all_variants_fit { + return Ok(None); } - } - } + + let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); + + let others_zst = variant_layouts.iter_enumerated().all(|(i, layout)| { + i == largest_variant_index || layout.size == Size::ZERO + }); + let same_size = size == variant_layouts[largest_variant_index].size; + let same_align = align == variant_layouts[largest_variant_index].align; + + let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { + Abi::Uninhabited + } else if same_size && same_align && others_zst { + match variant_layouts[largest_variant_index].abi { + // When the total alignment and size match, we can use the + // same ABI as the scalar variant with the reserved niche. + Abi::Scalar(_) => Abi::Scalar(niche_scalar), + Abi::ScalarPair(first, second) => { + // Only the niche is guaranteed to be initialised, + // so use union layouts for the other primitive. + if niche_offset == Size::ZERO { + Abi::ScalarPair(niche_scalar, second.to_union()) + } else { + Abi::ScalarPair(first.to_union(), niche_scalar) + } + } + _ => Abi::Aggregate { sized: true }, + } + } else { + Abi::Aggregate { sized: true } + }; + + let layout = LayoutS { + variants: Variants::Multiple { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { + untagged_variant: largest_variant_index, + niche_variants, + niche_start, + }, + tag_field: 0, + variants: IndexVec::new(), + }, + fields: FieldsShape::Arbitrary { + offsets: vec![niche_offset], + memory_index: vec![0], + }, + abi, + largest_niche, + size, + align, + }; + + Ok(Some(TmpLayout { layout, variants: variant_layouts })) + }; + + let niche_filling_layout = calculate_niche_filling_layout()?; let (mut min, mut max) = (i128::MAX, i128::MIN); let discr_type = def.repr().discr_type(); @@ -1540,15 +1493,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let layout_variants = - layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect(); - let tagged_layout = LayoutS { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, tag_field: 0, - variants: layout_variants, + variants: IndexVec::new(), }, fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], @@ -1560,20 +1510,45 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { size, }; - let best_layout = match (tagged_layout, niche_filling_layout) { - (tagged_layout, Some(niche_filling_layout)) => { + 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. - cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| { - let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl)); - (layout.size, cmp::Reverse(niche_size)) - }) + use Ordering::*; + let niche_size = |tmp_l: &TmpLayout<'_>| { + tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + }; + match ( + tl.layout.size.cmp(&nl.layout.size), + niche_size(&tl).cmp(&niche_size(&nl)), + ) { + (Greater, _) => nl, + (Equal, Less) => nl, + _ => tl, + } } - (tagged_layout, None) => tagged_layout, + (tl, None) => tl, }; - tcx.intern_layout(best_layout) + // Now we can intern the variant layouts and store them in the enum layout. + best_layout.layout.variants = match best_layout.layout.variants { + Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple { + tag, + tag_encoding, + tag_field, + variants: best_layout + .variants + .into_iter() + .map(|layout| tcx.intern_layout(layout)) + .collect(), + }, + _ => bug!(), + }; + + tcx.intern_layout(best_layout.layout) } // Types with no meaningful known layout. @@ -2468,7 +2443,9 @@ where | ty::FnDef(..) | ty::GeneratorWitness(..) | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this), + | ty::Dynamic(_, _, ty::Dyn) => { + bug!("TyAndLayout::field({:?}): not applicable", this) + } // Potentially-fat pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { @@ -2497,7 +2474,7 @@ where match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), - ty::Dynamic(_, _) => { + ty::Dynamic(_, _, ty::Dyn) => { TyMaybeWithLayout::Ty(tcx.mk_imm_ref( tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3), @@ -2566,6 +2543,22 @@ where } } + ty::Dynamic(_, _, ty::DynStar) => { + if i == 0 { + TyMaybeWithLayout::Ty(tcx.types.usize) + } else if i == 1 { + // FIXME(dyn-star) same FIXME as above applies here too + TyMaybeWithLayout::Ty( + tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + ), + ) + } else { + bug!("no field {i} on dyn*") + } + } + ty::Projection(_) | ty::Bound(..) | ty::Placeholder(..) @@ -2674,11 +2667,11 @@ where // using more niches than just null (e.g., the first page of // the address space, or unaligned pointers). Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, tag_field, .. } if this.fields.offset(tag_field) == offset => { - Some(this.for_variant(cx, dataful_variant)) + Some(this.for_variant(cx, untagged_variant)) } _ => Some(this), }; @@ -2761,6 +2754,7 @@ impl<'tcx> ty::Instance<'tcx> { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. + #[tracing::instrument(level = "debug", skip(tcx, param_env))] fn fn_sig_for_fn_abi( &self, tcx: TyCtxt<'tcx>, @@ -2907,6 +2901,7 @@ impl<'tcx> ty::Instance<'tcx> { /// with `-Cpanic=abort` will look like they can't unwind when in fact they /// might (from a foreign exception or similar). #[inline] +#[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: SpecAbi) -> bool { if let Some(did) = fn_def_id { // Special attribute for functions which can't unwind. @@ -3123,6 +3118,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// NB: that includes virtual calls, which are represented by "direct calls" /// to an `InstanceDef::Virtual` instance (of `::fn`). #[inline] + #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( &self, instance: ty::Instance<'tcx>, @@ -3179,9 +3175,100 @@ fn fn_abi_of_instance<'tcx>( ) } +// Handle safe Rust thin and fat pointers. +pub fn adjust_for_rust_scalar<'tcx>( + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + attrs: &mut ArgAttributes, + scalar: Scalar, + layout: TyAndLayout<'tcx>, + offset: Size, + is_return: bool, +) { + // Booleans are always a noundef i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.ext(ArgExtension::Zext); + attrs.set(ArgAttribute::NoUndef); + return; + } + + // Scalars which have invalid values cannot be undef. + if !scalar.is_always_valid(&cx) { + attrs.set(ArgAttribute::NoUndef); + } + + // Only pointer types handled below. + let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; + + if !valid_range.contains(0) { + attrs.set(ArgAttribute::NonNull); + } + + if let Some(pointee) = layout.pointee_info_at(&cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_align = Some(pointee.align); + + // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable + // for the entire duration of the function as they can be deallocated + // at any time. Same for shared mutable references. If LLVM had a + // way to say "dereferenceable on entry" we could use it here. + attrs.pointee_size = match kind { + PointerKind::UniqueBorrowed + | PointerKind::UniqueBorrowedPinned + | PointerKind::Frozen => pointee.size, + PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, + }; + + // `Box`, `&T`, and `&mut T` cannot be undef. + // Note that this only applies to the value of the pointer itself; + // this attribute doesn't make it UB for the pointed-to data to be undef. + attrs.set(ArgAttribute::NoUndef); + + // The aliasing rules for `Box` are still not decided, but currently we emit + // `noalias` for it. This can be turned off using an unstable flag. + // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 + let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true); + + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + // + // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute + // for UniqueBorrowed arguments, so that the codegen backend can decide whether + // or not to actually emit the attribute. It can also be controlled with the + // `-Zmutable-noalias` debugging option. + let no_alias = match kind { + PointerKind::SharedMutable + | PointerKind::UniqueBorrowed + | PointerKind::UniqueBorrowedPinned => false, + PointerKind::UniqueOwned => noalias_for_box, + PointerKind::Frozen => !is_return, + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + + if kind == PointerKind::UniqueBorrowed && !is_return { + attrs.set(ArgAttribute::NoAliasMutRef); + } + } + } +} + impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) // arguments of this method, into a separate `struct`. + #[tracing::instrument( + level = "debug", + skip(self, caller_location, fn_def_id, force_thin_self_ptr) + )] fn fn_abi_new_uncached( &self, sig: ty::PolyFnSig<'tcx>, @@ -3191,8 +3278,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) replace this with something typed, like an `enum`. force_thin_self_ptr: bool, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args); - let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig); let conv = conv_from_spec_abi(self.tcx(), sig.abi); @@ -3234,92 +3319,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { use SpecAbi::*; let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: Scalar, - layout: TyAndLayout<'tcx>, - offset: Size, - is_return: bool| { - // Booleans are always a noundef i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.ext(ArgExtension::Zext); - attrs.set(ArgAttribute::NoUndef); - return; - } - - // Scalars which have invalid values cannot be undef. - if !scalar.is_always_valid(self) { - attrs.set(ArgAttribute::NoUndef); - } - - // Only pointer types handled below. - let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; - - if !valid_range.contains(0) { - attrs.set(ArgAttribute::NonNull); - } - - if let Some(pointee) = layout.pointee_info_at(self, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_align = Some(pointee.align); - - // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable - // for the entire duration of the function as they can be deallocated - // at any time. Same for shared mutable references. If LLVM had a - // way to say "dereferenceable on entry" we could use it here. - attrs.pointee_size = match kind { - PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned - | PointerKind::Frozen => pointee.size, - PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, - }; - - // `Box`, `&T`, and `&mut T` cannot be undef. - // Note that this only applies to the value of the pointer itself; - // this attribute doesn't make it UB for the pointed-to data to be undef. - attrs.set(ArgAttribute::NoUndef); - - // The aliasing rules for `Box` are still not decided, but currently we emit - // `noalias` for it. This can be turned off using an unstable flag. - // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 - let noalias_for_box = - self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true); - - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - // - // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute - // for UniqueBorrowed arguments, so that the codegen backend can decide whether - // or not to actually emit the attribute. It can also be controlled with the - // `-Zmutable-noalias` debugging option. - let no_alias = match kind { - PointerKind::SharedMutable - | PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned => false, - PointerKind::UniqueOwned => noalias_for_box, - PointerKind::Frozen => !is_return, - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - - if kind == PointerKind::UniqueBorrowed && !is_return { - attrs.set(ArgAttribute::NoAliasMutRef); - } - } - } - }; - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, FnAbiError<'tcx>> { + let span = tracing::debug_span!("arg_of"); + let _entered = span.enter(); let is_return = arg_idx.is_none(); let layout = self.layout_of(ty)?; @@ -3334,7 +3336,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| { let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return); + adjust_for_rust_scalar(*self, &mut attrs, scalar, *layout, offset, is_return); attrs }); @@ -3367,7 +3369,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .map(|(i, ty)| arg_of(ty, Some(i))) .collect::>()?, c_variadic: sig.c_variadic, - fixed_count: inputs.len(), + fixed_count: inputs.len() as u32, conv, can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi), }; @@ -3376,6 +3378,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Ok(self.tcx.arena.alloc(fn_abi)) } + #[tracing::instrument(level = "trace", skip(self))] fn fn_abi_adjust_for_abi( &self, fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, @@ -3439,7 +3442,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } }; fixup(&mut fn_abi.ret); - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { fixup(arg); } } else { @@ -3450,6 +3453,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } +#[tracing::instrument(level = "debug", skip(cx))] fn make_thin_self_ptr<'tcx>( cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), layout: TyAndLayout<'tcx>, @@ -3461,7 +3465,7 @@ fn make_thin_self_ptr<'tcx>( tcx.mk_mut_ptr(layout.ty) } else { match layout.abi { - Abi::ScalarPair(..) => (), + Abi::ScalarPair(..) | Abi::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_middle/src/ty/layout_sanity_check.rs b/compiler/rustc_middle/src/ty/layout_sanity_check.rs new file mode 100644 index 000000000..87c85dcff --- /dev/null +++ b/compiler/rustc_middle/src/ty/layout_sanity_check.rs @@ -0,0 +1,303 @@ +use crate::ty::{ + layout::{LayoutCx, TyAndLayout}, + TyCtxt, +}; +use rustc_target::abi::*; + +use std::cmp; + +/// Enforce some basic invariants on layouts. +pub(super) fn sanity_check_layout<'tcx>( + cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + layout: &TyAndLayout<'tcx>, +) { + // Type-level uninhabitedness should always imply ABI uninhabitedness. + if cx.tcx.conservative_is_privately_uninhabited(cx.param_env.and(layout.ty)) { + assert!(layout.abi.is_uninhabited()); + } + + if layout.size.bytes() % layout.align.abi.bytes() != 0 { + bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); + } + + if cfg!(debug_assertions) { + /// Yields non-ZST fields of the type + fn non_zst_fields<'tcx, 'a>( + cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>, + layout: &'a TyAndLayout<'tcx>, + ) -> impl Iterator)> + 'a { + (0..layout.layout.fields().count()).filter_map(|i| { + let field = layout.field(cx, i); + // Also checking `align == 1` here leads to test failures in + // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with + // alignment 4 that still gets ignored during layout computation (which is okay + // since other fields already force alignment 4). + let zst = field.is_zst(); + (!zst).then(|| (layout.fields.offset(i), field)) + }) + } + + fn skip_newtypes<'tcx>( + cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + layout: &TyAndLayout<'tcx>, + ) -> TyAndLayout<'tcx> { + if matches!(layout.layout.variants(), Variants::Multiple { .. }) { + // Definitely not a newtype of anything. + return *layout; + } + let mut fields = non_zst_fields(cx, layout); + let Some(first) = fields.next() else { + // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing + return *layout + }; + if fields.next().is_none() { + let (offset, first) = first; + if offset == Size::ZERO && first.layout.size() == layout.size { + // This is a newtype, so keep recursing. + // FIXME(RalfJung): I don't think it would be correct to do any checks for + // alignment here, so we don't. Is that correct? + return skip_newtypes(cx, &first); + } + } + // No more newtypes here. + *layout + } + + fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) { + match layout.layout.abi() { + Abi::Scalar(scalar) => { + // No padding in scalars. + let size = scalar.size(cx); + let align = scalar.align(cx).abi; + assert_eq!( + layout.layout.size(), + size, + "size mismatch between ABI and layout in {layout:#?}" + ); + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + // Check that this matches the underlying field. + let inner = skip_newtypes(cx, layout); + assert!( + matches!(inner.layout.abi(), Abi::Scalar(_)), + "`Scalar` type {} is newtype around non-`Scalar` type {}", + layout.ty, + inner.ty + ); + match inner.layout.fields() { + FieldsShape::Primitive => { + // Fine. + } + FieldsShape::Union(..) => { + // FIXME: I guess we could also check something here? Like, look at all fields? + return; + } + FieldsShape::Arbitrary { .. } => { + // Should be an enum, the only field is the discriminant. + assert!( + inner.ty.is_enum(), + "`Scalar` layout for non-primitive non-enum type {}", + inner.ty + ); + assert_eq!( + inner.layout.fields().count(), + 1, + "`Scalar` layout for multiple-field type in {inner:#?}", + ); + let offset = inner.layout.fields().offset(0); + let field = inner.field(cx, 0); + // The field should be at the right offset, and match the `scalar` layout. + assert_eq!( + offset, + Size::ZERO, + "`Scalar` field at non-0 offset in {inner:#?}", + ); + assert_eq!( + field.size, size, + "`Scalar` field with bad size in {inner:#?}", + ); + assert_eq!( + field.align.abi, align, + "`Scalar` field with bad align in {inner:#?}", + ); + assert!( + matches!(field.abi, Abi::Scalar(_)), + "`Scalar` field with bad ABI in {inner:#?}", + ); + } + _ => { + panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty); + } + } + } + Abi::ScalarPair(scalar1, scalar2) => { + // Sanity-check scalar pairs. These are a bit more flexible and support + // padding, but we can at least ensure both fields actually fit into the layout + // and the alignment requirement has not been weakened. + let size1 = scalar1.size(cx); + let align1 = scalar1.align(cx).abi; + let size2 = scalar2.size(cx); + let align2 = scalar2.align(cx).abi; + assert!( + layout.layout.align().abi >= cmp::max(align1, align2), + "alignment mismatch between ABI and layout in {layout:#?}", + ); + let field2_offset = size1.align_to(align2); + assert!( + layout.layout.size() >= field2_offset + size2, + "size mismatch between ABI and layout in {layout:#?}" + ); + // Check that the underlying pair of fields matches. + let inner = skip_newtypes(cx, layout); + assert!( + matches!(inner.layout.abi(), Abi::ScalarPair(..)), + "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", + layout.ty, + inner.ty + ); + if matches!(inner.layout.variants(), Variants::Multiple { .. }) { + // FIXME: ScalarPair for enums is enormously complicated and it is very hard + // to check anything about them. + return; + } + match inner.layout.fields() { + FieldsShape::Arbitrary { .. } => { + // Checked below. + } + FieldsShape::Union(..) => { + // FIXME: I guess we could also check something here? Like, look at all fields? + return; + } + _ => { + panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}"); + } + } + let mut fields = non_zst_fields(cx, &inner); + let (offset1, field1) = fields.next().unwrap_or_else(|| { + panic!("`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}") + }); + let (offset2, field2) = fields.next().unwrap_or_else(|| { + panic!("`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}") + }); + assert!( + fields.next().is_none(), + "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}" + ); + // The fields might be in opposite order. + let (offset1, field1, offset2, field2) = if offset1 <= offset2 { + (offset1, field1, offset2, field2) + } else { + (offset2, field2, offset1, field1) + }; + // The fields should be at the right offset, and match the `scalar` layout. + assert_eq!( + offset1, + Size::ZERO, + "`ScalarPair` first field at non-0 offset in {inner:#?}", + ); + assert_eq!( + field1.size, size1, + "`ScalarPair` first field with bad size in {inner:#?}", + ); + assert_eq!( + field1.align.abi, align1, + "`ScalarPair` first field with bad align in {inner:#?}", + ); + assert!( + matches!(field1.abi, Abi::Scalar(_)), + "`ScalarPair` first field with bad ABI in {inner:#?}", + ); + assert_eq!( + offset2, field2_offset, + "`ScalarPair` second field at bad offset in {inner:#?}", + ); + assert_eq!( + field2.size, size2, + "`ScalarPair` second field with bad size in {inner:#?}", + ); + assert_eq!( + field2.align.abi, align2, + "`ScalarPair` second field with bad align in {inner:#?}", + ); + assert!( + matches!(field2.abi, Abi::Scalar(_)), + "`ScalarPair` second field with bad ABI in {inner:#?}", + ); + } + Abi::Vector { count, element } => { + // No padding in vectors. Alignment can be strengthened, though. + assert!( + layout.layout.align().abi >= element.align(cx).abi, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + let size = element.size(cx) * count; + assert_eq!( + layout.layout.size(), + size.align_to(cx.data_layout().vector_align(size).abi), + "size mismatch between ABI and layout in {layout:#?}" + ); + } + Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + } + } + + check_layout_abi(cx, layout); + + if let Variants::Multiple { variants, .. } = &layout.variants { + for variant in variants.iter() { + // No nested "multiple". + assert!(matches!(variant.variants(), Variants::Single { .. })); + // Variants should have the same or a smaller size as the full thing, + // and same for alignment. + if variant.size() > layout.size { + bug!( + "Type with size {} bytes has variant with size {} bytes: {layout:#?}", + layout.size.bytes(), + variant.size().bytes(), + ) + } + if variant.align().abi > layout.align.abi { + bug!( + "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", + layout.align.abi.bytes(), + variant.align().abi.bytes(), + ) + } + // Skip empty variants. + if variant.size() == Size::ZERO + || variant.fields().count() == 0 + || variant.abi().is_uninhabited() + { + // These are never actually accessed anyway, so we can skip the coherence check + // for them. They also fail that check, since they have + // `Aggregate`/`Uninhbaited` ABI even when the main type is + // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size + // 0, and sometimes, variants without fields have non-0 size.) + continue; + } + // The top-level ABI and the ABI of the variants should be coherent. + let scalar_coherent = |s1: Scalar, s2: Scalar| { + s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx) + }; + let abi_coherent = match (layout.abi, variant.abi()) { + (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2), + (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + scalar_coherent(a1, a2) && scalar_coherent(b1, b2) + } + (Abi::Uninhabited, _) => true, + (Abi::Aggregate { .. }, _) => true, + _ => false, + }; + if !abi_coherent { + bug!( + "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}", + variant + ); + } + } + } + } +} diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index db3b5cfd1..79365ef28 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -65,6 +65,10 @@ impl List { pub fn len(&self) -> usize { self.len } + + pub fn as_slice(&self) -> &[T] { + self + } } impl List { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 02da02568..3f9871190 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -15,6 +15,7 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; +use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::AccessLevels; use crate::mir::{Body, GeneratorLayout}; @@ -40,6 +41,7 @@ use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; +use rustc_serialize::{Decodable, Encodable}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; @@ -49,10 +51,14 @@ pub use vtable::*; use std::fmt::Debug; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::mem; +use std::num::NonZeroUsize; use std::ops::ControlFlow; use std::{fmt, str}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; pub use rustc_type_ir::TyKind::*; @@ -124,6 +130,7 @@ mod erase_regions; mod generics; mod impls_ty; mod instance; +mod layout_sanity_check; mod list; mod parameterized; mod rvalue_scopes; @@ -177,11 +184,6 @@ pub struct ResolverAstLowering { pub label_res_map: NodeMap, /// Resolutions for lifetimes. pub lifetimes_res_map: NodeMap, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - pub generics_def_id_map: Vec>, /// Lifetime parameters that lowering will have to introduce. pub extra_lifetime_params_map: NodeMap>, @@ -262,13 +264,11 @@ impl fmt::Display for ImplPolarity { } #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] -pub enum Visibility { +pub enum Visibility { /// Visible everywhere (including in other crates). Public, /// Visible only in the given crate-local module. - Restricted(DefId), - /// Not visible anywhere in the local crate. This is the visibility of private external items. - Invisible, + Restricted(Id), } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] @@ -359,31 +359,45 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> { } } -impl Visibility { - /// Returns `true` if an item with this visibility is accessible from the given block. - pub fn is_accessible_from(self, module: DefId, tree: T) -> bool { - let restriction = match self { - // Public items are visible everywhere. - Visibility::Public => return true, - // Private items from other crates are visible nowhere. - Visibility::Invisible => return false, - // Restricted items are visible in an arbitrary local module. - Visibility::Restricted(other) if other.krate != module.krate => return false, - Visibility::Restricted(module) => module, - }; +impl Visibility { + pub fn is_public(self) -> bool { + matches!(self, Visibility::Public) + } + + pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Visibility { + match self { + Visibility::Public => Visibility::Public, + Visibility::Restricted(id) => Visibility::Restricted(f(id)), + } + } +} - tree.is_descendant_of(module, restriction) +impl> Visibility { + pub fn to_def_id(self) -> Visibility { + self.map_id(Into::into) + } + + /// Returns `true` if an item with this visibility is accessible from the given module. + pub fn is_accessible_from(self, module: impl Into, tree: impl DefIdTree) -> bool { + match self { + // Public items are visible everywhere. + Visibility::Public => true, + Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()), + } } /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least(self, vis: Visibility, tree: T) -> bool { - let vis_restriction = match vis { - Visibility::Public => return self == Visibility::Public, - Visibility::Invisible => return true, - Visibility::Restricted(module) => module, - }; + pub fn is_at_least(self, vis: Visibility>, tree: impl DefIdTree) -> bool { + match vis { + Visibility::Public => self.is_public(), + Visibility::Restricted(id) => self.is_accessible_from(id, tree), + } + } +} - self.is_accessible_from(vis_restriction, tree) +impl Visibility { + pub fn expect_local(self) -> Visibility { + self.map_id(|id| id.expect_local()) } // Returns `true` if this item is visible anywhere in the local crate. @@ -391,13 +405,8 @@ impl Visibility { match self { Visibility::Public => true, Visibility::Restricted(def_id) => def_id.is_local(), - Visibility::Invisible => false, } } - - pub fn is_public(self) -> bool { - matches!(self, Visibility::Public) - } } /// The crate variances map is computed during typeck and contains the @@ -468,15 +477,6 @@ pub(crate) struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyS<'_>, 40); - -// We are actually storing a stable hash cache next to the type, so let's -// also check the full size -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(WithStableHash>, 56); - /// Use this rather than `TyS`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] @@ -533,10 +533,6 @@ pub(crate) struct PredicateS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateS<'_>, 56); - /// Use this rather than `PredicateS`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] @@ -593,6 +589,29 @@ impl<'tcx> Predicate<'tcx> { } self } + + /// Whether this projection can be soundly normalized. + /// + /// Wf predicates must not be normalized, as normalization + /// can remove required bounds which would cause us to + /// unsoundly accept some programs. See #91068. + #[inline] + pub fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + PredicateKind::WellFormed(_) => false, + PredicateKind::Trait(_) + | PredicateKind::RegionOutlives(_) + | PredicateKind::TypeOutlives(_) + | PredicateKind::Projection(_) + | PredicateKind::ObjectSafe(_) + | PredicateKind::ClosureKind(_, _, _) + | PredicateKind::Subtype(_) + | PredicateKind::Coerce(_) + | PredicateKind::ConstEvaluatable(_) + | PredicateKind::ConstEquate(_, _) + | PredicateKind::TypeWellFormedFromEnv(_) => true, + } + } } impl<'a, 'tcx> HashStable> for Predicate<'tcx> { @@ -617,7 +636,7 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -789,7 +808,7 @@ impl<'tcx> Predicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, @@ -869,7 +888,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct OutlivesPredicate(pub A, pub B); // `A: B` pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; @@ -880,7 +899,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicat /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct SubtypePredicate<'tcx> { pub a_is_expected: bool, pub a: Ty<'tcx>, @@ -890,49 +909,142 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; /// Encodes that we have to coerce *from* the `a` type to the `b` type. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CoercePredicate<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, } pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub enum Term<'tcx> { - Ty(Ty<'tcx>), - Const(Const<'tcx>), +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Term<'tcx> { + ptr: NonZeroUsize, + marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, +} + +impl Debug for Term<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data = if let Some(ty) = self.ty() { + format!("Term::Ty({:?})", ty) + } else if let Some(ct) = self.ct() { + format!("Term::Ct({:?})", ct) + } else { + unreachable!() + }; + f.write_str(&data) + } } impl<'tcx> From> for Term<'tcx> { fn from(ty: Ty<'tcx>) -> Self { - Term::Ty(ty) + TermKind::Ty(ty).pack() } } impl<'tcx> From> for Term<'tcx> { fn from(c: Const<'tcx>) -> Self { - Term::Const(c) + TermKind::Const(c).pack() + } +} + +impl<'a, 'tcx> HashStable> for Term<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> { + fn try_fold_with>(self, folder: &mut F) -> Result { + Ok(self.unpack().try_fold_with(folder)?.pack()) + } +} + +impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.unpack().visit_with(visitor) + } +} + +impl<'tcx, E: TyEncoder>> Encodable for Term<'tcx> { + fn encode(&self, e: &mut E) { + self.unpack().encode(e) + } +} + +impl<'tcx, D: TyDecoder>> Decodable for Term<'tcx> { + fn decode(d: &mut D) -> Self { + let res: TermKind<'tcx> = Decodable::decode(d); + res.pack() } } impl<'tcx> Term<'tcx> { + #[inline] + pub fn unpack(self) -> TermKind<'tcx> { + let ptr = self.ptr.get(); + // SAFETY: use of `Interned::new_unchecked` here is ok because these + // pointers were originally created from `Interned` types in `pack()`, + // and this is just going in the other direction. + unsafe { + match ptr & TAG_MASK { + TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const WithStableHash>), + ))), + CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), + ))), + _ => core::intrinsics::unreachable(), + } + } + } + pub fn ty(&self) -> Option> { - if let Term::Ty(ty) = self { Some(*ty) } else { None } + if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None } } pub fn ct(&self) -> Option> { - if let Term::Const(c) = self { Some(*c) } else { None } + if let TermKind::Const(c) = self.unpack() { Some(c) } else { None } } pub fn into_arg(self) -> GenericArg<'tcx> { - match self { - Term::Ty(ty) => ty.into(), - Term::Const(c) => c.into(), + match self.unpack() { + TermKind::Ty(ty) => ty.into(), + TermKind::Const(c) => c.into(), } } } +const TAG_MASK: usize = 0b11; +const TYPE_TAG: usize = 0b00; +const CONST_TAG: usize = 0b01; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] +pub enum TermKind<'tcx> { + Ty(Ty<'tcx>), + Const(Const<'tcx>), +} + +impl<'tcx> TermKind<'tcx> { + #[inline] + fn pack(self) -> Term<'tcx> { + let (tag, ptr) = match self { + TermKind::Ty(ty) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + (TYPE_TAG, ty.0.0 as *const WithStableHash> as usize) + } + TermKind::Const(ct) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) + } + }; + + Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -946,7 +1058,7 @@ impl<'tcx> Term<'tcx> { /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub term: Term<'tcx>, @@ -1002,6 +1114,12 @@ pub trait ToPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } +impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1166,20 +1284,17 @@ pub struct OpaqueHiddenType<'tcx> { impl<'tcx> OpaqueHiddenType<'tcx> { pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { // Found different concrete types for the opaque type. - let mut err = tcx.sess.struct_span_err( - other.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); - if self.span == other.span { - err.span_label( - self.span, - "this expression supplies two conflicting concrete types for the same opaque type", - ); + let sub_diag = if self.span == other.span { + TypeMismatchReason::ConflictType { span: self.span } } else { - err.span_note(self.span, "previous use here"); - } - err.emit(); + TypeMismatchReason::PreviousUse { span: self.span } + }; + tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + self_ty: self.ty, + other_ty: other.ty, + other_span: other.span, + sub: sub_diag, + }); } } @@ -1411,7 +1526,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { Ok(ParamEnv::new( self.caller_bounds().try_fold_with(folder)?, self.reveal().try_fold_with(folder)?, - self.constness().try_fold_with(folder)?, + self.constness(), )) } } @@ -1419,8 +1534,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> { fn visit_with>(&self, visitor: &mut V) -> ControlFlow { self.caller_bounds().visit_with(visitor)?; - self.reveal().visit_with(visitor)?; - self.constness().visit_with(visitor) + self.reveal().visit_with(visitor) } } @@ -1577,7 +1691,7 @@ impl<'tcx> PolyTraitRef<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] -#[derive(HashStable)] +#[derive(HashStable, Lift)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, pub value: T, @@ -1779,7 +1893,7 @@ pub enum VariantDiscr { pub struct FieldDef { pub did: DefId, pub name: Symbol, - pub vis: Visibility, + pub vis: Visibility, } impl PartialEq for FieldDef { @@ -2256,7 +2370,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { - self.get_attrs(did, attr).next() + if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); + } else { + self.get_attrs(did, attr).next() + } } /// Determines whether an item is annotated with an attribute. @@ -2358,6 +2476,25 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } + /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion + /// site. Only applies when `Span` is the result of macro expansion. + /// + /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default + /// and only when a macro definition is annotated with `#[collapse_debuginfo]`. + /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. + /// + /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. + pub fn should_collapse_debuginfo(self, span: Span) -> bool { + !self.sess.opts.unstable_opts.debug_macros + && if self.features().collapse_debuginfo { + span.in_macro_expansion_with_collapse_debuginfo() + } else { + // Inlined spans should not be collapsed as that leads to all of the + // inlined code being attributed to the inline callsite. + span.from_expansion() && !span.is_inlined() + } + } + pub fn is_object_safe(self, key: DefId) -> bool { self.object_safety_violations(key).is_empty() } @@ -2372,6 +2509,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn is_const_default_method(self, def_id: DefId) -> bool { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } + + pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId { + while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { + debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); + def_id = self.parent(def_id); + } + def_id + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. @@ -2516,3 +2661,14 @@ pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [ty::Const<'tcx>], } + +// 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; + // These are in alphabetical order, which is easy to maintain. + static_assert_size!(PredicateS<'_>, 48); + static_assert_size!(TyS<'_>, 40); + static_assert_size!(WithStableHash>, 56); +} diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9d8a81165..9db5a2894 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -36,6 +36,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_regions(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, @@ -100,6 +101,7 @@ impl<'tcx> TyCtxt<'tcx> { /// N.B., currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in /// codegen, we need to normalize the contents. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, @@ -188,13 +190,11 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { - #[instrument(skip(self), level = "debug")] fn normalize_generic_arg_after_erasing_regions( &self, arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.param_env.and(arg); - debug!(?arg); self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e189ee2fc..9c8dc30e2 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -1,4 +1,4 @@ -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIndex}; use rustc_index::vec::{Idx, IndexVec}; use crate::middle::exported_symbols::ExportedSymbol; @@ -53,17 +53,20 @@ trivially_parameterized_over_tcx! { crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, crate::middle::exported_symbols::SymbolExportInfo, + crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, + ty::AssocItemContainer, ty::Generics, ty::ImplPolarity, ty::ReprOptions, ty::TraitDef, - ty::Visibility, + ty::Visibility, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedTypeGen, rustc_ast::Attribute, rustc_ast::MacArgs, rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, rustc_attr::Stability, rustc_hir::Constness, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7f2e81a71..97bddb93e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,7 +1,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{ - self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable, + self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, }; use rustc_apfloat::ieee::{Double, Single}; @@ -619,12 +619,16 @@ pub trait PrettyPrinter<'tcx>: ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, repr) => { let print_r = self.should_print_region(r); if print_r { p!("("); } - p!("dyn ", print(data)); + match repr { + ty::Dyn => p!("dyn "), + ty::DynStar => p!("dyn* "), + } + p!(print(data)); if print_r { p!(" + ", print(r), ")"); } @@ -632,7 +636,13 @@ pub trait PrettyPrinter<'tcx>: ty::Foreign(def_id) => { p!(print_def_path(def_id, &[])); } - ty::Projection(ref data) => p!(print(data)), + ty::Projection(ref data) => { + if self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder { + return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs); + } else { + p!(print(data)) + } + } ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), ty::Opaque(def_id, substs) => { // FIXME(eddyb) print this with `print_def_path`. @@ -855,7 +865,7 @@ pub trait PrettyPrinter<'tcx>: } p!(")"); - if let Term::Ty(ty) = return_ty.skip_binder() { + if let Some(ty) = return_ty.skip_binder().ty() { if !ty.is_unit() { p!(" -> ", print(return_ty)); } @@ -916,12 +926,14 @@ pub trait PrettyPrinter<'tcx>: // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, // unless we can find out what generator return type it comes from. let term = if let Some(ty) = term.skip_binder().ty() - && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() - && Some(*item_def_id) == tcx.lang_items().generator_return() + && let ty::Projection(proj) = ty.kind() + && let assoc = tcx.associated_item(proj.item_def_id) + && assoc.trait_container(tcx) == tcx.lang_items().gen_trait() + && assoc.name == rustc_span::sym::Return { if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { let return_ty = substs.as_generator().return_ty(); - if !return_ty.is_ty_infer() { + if !return_ty.is_ty_var() { return_ty.into() } else { continue; @@ -942,13 +954,9 @@ pub trait PrettyPrinter<'tcx>: p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); - match term { - Term::Ty(ty) => { - p!(print(ty)) - } - Term::Const(c) => { - p!(print(c)); - } + match term.unpack() { + TermKind::Ty(ty) => p!(print(ty)), + TermKind::Const(c) => p!(print(c)), }; } @@ -1193,15 +1201,9 @@ pub trait PrettyPrinter<'tcx>: } match ct.kind() { - ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs, - promoted: Some(promoted), - }) => { - p!(print_value_path(def.did, substs)); - p!(write("::{:?}", promoted)); - } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { + assert_eq!(promoted, ()); + match self.tcx().def_kind(def.did) { DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => { p!(print_value_path(def.did, substs)) @@ -1275,7 +1277,7 @@ pub trait PrettyPrinter<'tcx>: let range = AllocRange { start: offset, size: Size::from_bytes(len) }; if let Ok(byte_str) = - alloc.inner().get_bytes(&self.tcx(), range) + alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) { p!(pretty_print_byte_str(byte_str)) } else { @@ -1401,14 +1403,7 @@ pub trait PrettyPrinter<'tcx>: } fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result { - define_scoped_cx!(self); - p!("b\""); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; - } - } - p!("\""); + write!(self, "b\"{}\"", byte_str.escape_ascii())?; Ok(self) } @@ -1513,6 +1508,10 @@ pub trait PrettyPrinter<'tcx>: } return Ok(self); } + (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { + p!(write("&")); + return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + } (ty::ValTree::Leaf(leaf), _) => { return self.pretty_print_const_scalar_int(leaf, ty, print_ty); } @@ -1532,6 +1531,34 @@ pub trait PrettyPrinter<'tcx>: } Ok(self) } + + fn pretty_closure_as_impl( + mut self, + closure: ty::ClosureSubsts<'tcx>, + ) -> Result { + let sig = closure.sig(); + let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); + + write!(self, "impl ")?; + self.wrap_binder(&sig, |sig, mut cx| { + define_scoped_cx!(cx); + + p!(print(kind), "("); + for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() { + if i > 0 { + p!(", "); + } + p!(print(arg)); + } + p!(")"); + + if !sig.output().is_unit() { + p!(" -> ", print(sig.output())); + } + + Ok(cx) + }) + } } // HACK(eddyb) boxed to avoid moving around a large struct by-value. @@ -1950,7 +1977,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { ty::ReVar(_) | ty::ReErased => false, - ty::ReStatic | ty::ReEmpty(_) => true, + ty::ReStatic => true, } } @@ -2034,14 +2061,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { p!("'static"); return Ok(self); } - ty::ReEmpty(ty::UniverseIndex::ROOT) => { - p!("'"); - return Ok(self); - } - ty::ReEmpty(ui) => { - p!(write("'", ui)); - return Ok(self); - } } p!("'_"); @@ -2446,6 +2465,11 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { } } +#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct PrintClosureAsImpl<'tcx> { + pub closure: ty::ClosureSubsts<'tcx>, +} + forward_display_to_print! { ty::Region<'tcx>, Ty<'tcx>, @@ -2538,6 +2562,10 @@ define_print_and_forward_display! { p!(print(self.0.trait_ref.print_only_trait_path())); } + PrintClosureAsImpl<'tcx> { + p!(pretty_closure_as_impl(self.closure)) + } + ty::ParamTy { p!(write("{}", self.name)) } @@ -2567,9 +2595,9 @@ define_print_and_forward_display! { } ty::Term<'tcx> { - match self { - ty::Term::Ty(ty) => p!(print(ty)), - ty::Term::Const(c) => p!(print(c)), + match self.unpack() { + ty::TermKind::Ty(ty) => p!(print(ty)), + ty::TermKind::Const(c) => p!(print(c)), } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2452bcf6a..a300a8df2 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -121,8 +121,8 @@ macro_rules! query_storage { ([][$K:ty, $V:ty]) => { >::Cache }; - ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { - <$ty as CacheSelector<$K, $V>>::Cache + ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => { + as CacheSelector<$K, $V>>::Cache }; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { query_storage!([$($modifiers)*][$($args)*]) @@ -173,7 +173,7 @@ macro_rules! opt_remap_env_constness { } macro_rules! define_callbacks { - (<$tcx:tt> + ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { @@ -187,33 +187,33 @@ macro_rules! define_callbacks { pub mod query_keys { use super::*; - $(pub type $name<$tcx> = $($K)*;)* + $(pub type $name<'tcx> = $($K)*;)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { use super::*; - $(pub type $name<$tcx> = $V;)* + $(pub type $name<'tcx> = $V;)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_storage { use super::*; - $(pub type $name<$tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)* + $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_stored { use super::*; - $(pub type $name<$tcx> = as QueryStorage>::Stored;)* + $(pub type $name<'tcx> = as QueryStorage>::Stored;)* } #[derive(Default)] - pub struct QueryCaches<$tcx> { - $($(#[$attr])* pub $name: query_storage::$name<$tcx>,)* + pub struct QueryCaches<'tcx> { + $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* } - impl<$tcx> TyCtxtEnsure<$tcx> { + impl<'tcx> TyCtxtEnsure<'tcx> { $($(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { @@ -231,20 +231,20 @@ macro_rules! define_callbacks { })* } - impl<$tcx> TyCtxt<$tcx> { + impl<'tcx> TyCtxt<'tcx> { $($(#[$attr])* #[inline(always)] #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> { self.at(DUMMY_SP).$name(key) })* } - impl<$tcx> TyCtxtAt<$tcx> { + impl<'tcx> TyCtxtAt<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); @@ -311,11 +311,11 @@ macro_rules! define_callbacks { $($(#[$attr])* fn $name( &'tcx self, - tcx: TyCtxt<$tcx>, + tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<$tcx>, + key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option>;)* + ) -> Option>;)* } }; } @@ -332,7 +332,7 @@ macro_rules! define_callbacks { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { [define_callbacks!][<'tcx>] } +rustc_query_append! { define_callbacks! } mod sealed { use super::{DefId, LocalDefId}; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 818affa71..61c34730d 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -6,7 +6,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; use rustc_span::DUMMY_SP; @@ -441,7 +441,9 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { + (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate_with_variance( ty::Contravariant, @@ -450,7 +452,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_region, ) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) + Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) @@ -572,8 +574,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( /// it. pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, + mut a: ty::Const<'tcx>, + mut b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); @@ -594,9 +596,16 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( ); } - let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env()); - let a = eagerly_eval(a); - let b = eagerly_eval(b); + // HACK(const_generics): We still need to eagerly evaluate consts when + // relating them because during `normalize_param_env_or_error`, + // we may relate an evaluated constant in a obligation against + // an unnormalized (i.e. unevaluated) const in the param-env. + // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants + // these `eval` calls can be removed. + if !relation.tcx().features().generic_const_exprs { + a = a.eval(tcx, relation.param_env()); + b = b.eval(tcx, relation.param_env()); + } // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -617,7 +626,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().generic_const_exprs => { - tcx.try_unify_abstract_consts(relation.param_env().and((au.shrink(), bu.shrink()))) + tcx.try_unify_abstract_consts(relation.param_env().and((au, bu))) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` @@ -626,6 +635,8 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def && au.promoted == bu.promoted => { + assert_eq!(au.promoted, ()); + let substs = relation.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -636,7 +647,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def: au.def, substs, - promoted: au.promoted, + promoted: (), }), ty: a.ty(), })); @@ -803,15 +814,15 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Term<'tcx> { +impl<'tcx> Relate<'tcx> for Term<'tcx> { fn relate>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { - Ok(match (a, b) { - (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(), - (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(), + Ok(match (a.unpack(), b.unpack()) { + (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7660a2f3a..84d6a8b97 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -3,13 +3,12 @@ //! hand, though we've recently added some macros and proc-macros to help with the tedium. use crate::mir::interpret; -use crate::mir::ProjectionKind; +use crate::mir::{Field, ProjectionKind}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; -use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; @@ -238,12 +237,24 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::Variance, ::rustc_span::Span, ::rustc_errors::ErrorGuaranteed, + Field, + interpret::Scalar, + rustc_target::abi::Size, + ty::DelaySpanBugEmitted, + rustc_type_ir::DebruijnIndex, + ty::BoundVar, + ty::Placeholder, +} + +TrivialTypeTraversalAndLiftImpls! { + for<'tcx> { + ty::ValTree<'tcx>, + } } /////////////////////////////////////////////////////////////////////////// // Lift implementations -// FIXME(eddyb) replace all the uses of `Option::map` with `?`. impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { type Lifted = (A::Lifted, B::Lifted); fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -261,10 +272,10 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { type Lifted = Option; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - Some(x) => tcx.lift(x).map(Some), - None => Some(None), - } + Some(match self { + Some(x) => Some(tcx.lift(x)?), + None => None, + }) } } @@ -281,21 +292,21 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box { type Lifted = Box; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(*self).map(Box::new) + Some(Box::new(tcx.lift(*self)?)) } } impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc { type Lifted = Rc; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.as_ref().clone()).map(Rc::new) + Some(Rc::new(tcx.lift(self.as_ref().clone())?)) } } impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc { type Lifted = Arc; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.as_ref().clone()).map(Arc::new) + Some(Arc::new(tcx.lift(self.as_ref().clone())?)) } } impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec { @@ -312,159 +323,18 @@ impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec { } } -impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { - type Lifted = ty::TraitRef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { - type Lifted = ty::ExistentialTraitRef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> { - type Lifted = ty::ExistentialPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - ty::ExistentialPredicate::Trait(x) => tcx.lift(x).map(ty::ExistentialPredicate::Trait), - ty::ExistentialPredicate::Projection(x) => { - tcx.lift(x).map(ty::ExistentialPredicate::Projection) - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - Some(ty::ExistentialPredicate::AutoTrait(def_id)) - } - } - } -} - impl<'a, 'tcx> Lift<'tcx> for Term<'a> { type Lifted = ty::Term<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some(match self { - Term::Ty(ty) => Term::Ty(tcx.lift(ty)?), - Term::Const(c) => Term::Const(tcx.lift(c)?), - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { - type Lifted = ty::TraitPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref, - constness: self.constness, - polarity: self.polarity, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { - type Lifted = ty::SubtypePredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - tcx.lift((self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a, - b, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> { - type Lifted = ty::CoercePredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b }) - } -} - -impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { - type Lifted = ty::OutlivesPredicate; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift((self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b)) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> { - type Lifted = ty::ProjectionTy<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - tcx.lift(self.substs) - .map(|substs| ty::ProjectionTy { item_def_id: self.item_def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { - type Lifted = ty::ProjectionPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - tcx.lift((self.projection_ty, self.term)) - .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { - type Lifted = ty::ExistentialProjection<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.substs).map(|substs| ty::ExistentialProjection { - substs, - term: tcx.lift(self.term).expect("type must lift when substs do"), - item_def_id: self.item_def_id, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { - type Lifted = ty::PredicateKind<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait), - ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype), - ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce), - ty::PredicateKind::RegionOutlives(data) => { - tcx.lift(data).map(ty::PredicateKind::RegionOutlives) - } - ty::PredicateKind::TypeOutlives(data) => { - tcx.lift(data).map(ty::PredicateKind::TypeOutlives) - } - ty::PredicateKind::Projection(data) => { - tcx.lift(data).map(ty::PredicateKind::Projection) - } - ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed), - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { - tcx.lift(closure_substs).map(|closure_substs| { - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) - }) - } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - Some(ty::PredicateKind::ObjectSafe(trait_def_id)) - } - ty::PredicateKind::ConstEvaluatable(uv) => { - tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv)) - } - ty::PredicateKind::ConstEquate(c1, c2) => { - tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) - } - ty::PredicateKind::TypeWellFormedFromEnv(ty) => { - tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv) + Some( + match self.unpack() { + TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?), + TermKind::Const(c) => TermKind::Const(tcx.lift(c)?), } - } + .pack(), + ) } } - -impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T> -where - >::Lifted: TypeVisitable<'tcx>, -{ - type Lifted = ty::Binder<'tcx, T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - let bound_vars = tcx.lift(self.bound_vars()); - tcx.lift(self.skip_binder()) - .zip(bound_vars) - .map(|(value, vars)| ty::Binder::bind_with_vars(value, vars)) - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -473,178 +343,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { } } -impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> { - type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.param_env).and_then(|param_env| { - tcx.lift(self.value).map(|value| ty::ParamEnvAnd { param_env, value }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { - type Lifted = ty::ClosureSubsts<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.substs).map(|substs| ty::ClosureSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> { - type Lifted = ty::GeneratorSubsts<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.substs).map(|substs| ty::GeneratorSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { - type Lifted = ty::adjustment::Adjustment<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - let ty::adjustment::Adjustment { kind, target } = self; - tcx.lift(kind).and_then(|kind| { - tcx.lift(target).map(|target| ty::adjustment::Adjustment { kind, target }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { - type Lifted = ty::adjustment::Adjust<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - ty::adjustment::Adjust::NeverToAny => Some(ty::adjustment::Adjust::NeverToAny), - ty::adjustment::Adjust::Pointer(ptr) => Some(ty::adjustment::Adjust::Pointer(ptr)), - ty::adjustment::Adjust::Deref(overloaded) => { - tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref) - } - ty::adjustment::Adjust::Borrow(autoref) => { - tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow) - } - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { - type Lifted = ty::adjustment::OverloadedDeref<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.region).map(|region| ty::adjustment::OverloadedDeref { - region, - mutbl: self.mutbl, - span: self.span, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { - type Lifted = ty::adjustment::AutoBorrow<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - ty::adjustment::AutoBorrow::Ref(r, m) => { - tcx.lift(r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m)) - } - ty::adjustment::AutoBorrow::RawPtr(m) => Some(ty::adjustment::AutoBorrow::RawPtr(m)), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { - type Lifted = ty::GenSig<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift((self.resume_ty, self.yield_ty, self.return_ty)) - .map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { - type Lifted = ty::FnSig<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.inputs_and_output).map(|x| ty::FnSig { - inputs_and_output: x, - c_variadic: self.c_variadic, - unsafety: self.unsafety, - abi: self.abi, - }) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound { - type Lifted = ty::error::ExpectedFound; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - let ty::error::ExpectedFound { expected, found } = self; - tcx.lift(expected).and_then(|expected| { - tcx.lift(found).map(|found| ty::error::ExpectedFound { expected, found }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { - type Lifted = ty::error::TypeError<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - use crate::ty::error::TypeError::*; - - Some(match self { - Mismatch => Mismatch, - ConstnessMismatch(x) => ConstnessMismatch(x), - PolarityMismatch(x) => PolarityMismatch(x), - UnsafetyMismatch(x) => UnsafetyMismatch(x), - AbiMismatch(x) => AbiMismatch(x), - Mutability => Mutability, - ArgumentMutability(i) => ArgumentMutability(i), - TupleSize(x) => TupleSize(x), - FixedArraySize(x) => FixedArraySize(x), - ArgCount => ArgCount, - FieldMisMatch(x, y) => FieldMisMatch(x, y), - RegionsDoesNotOutlive(a, b) => { - return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)); - } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(b).map(|b| RegionsInsufficientlyPolymorphic(a, b)); - } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(b).map(|b| RegionsOverlyPolymorphic(a, b)); - } - RegionsPlaceholderMismatch => RegionsPlaceholderMismatch, - IntMismatch(x) => IntMismatch(x), - FloatMismatch(x) => FloatMismatch(x), - Traits(x) => Traits(x), - VariadicMismatch(x) => VariadicMismatch(x), - CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)), - CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)), - ProjectionMismatched(x) => ProjectionMismatched(x), - ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)), - Sorts(x) => return tcx.lift(x).map(Sorts), - ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch), - ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch), - IntrinsicCast => IntrinsicCast, - TargetFeatureCast(x) => TargetFeatureCast(x), - ObjectUnsafeCoercion(x) => return tcx.lift(x).map(ObjectUnsafeCoercion), - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { - type Lifted = ty::InstanceDef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)), - ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), - ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), - ty::InstanceDef::FnPtrShim(def_id, ty) => { - Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller }) - } - ty::InstanceDef::DropGlue(def_id, ty) => { - Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::CloneShim(def_id, ty) => { - Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)) - } - } - } -} - /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. @@ -844,6 +542,12 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec { } } +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &[T] { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.iter().try_for_each(|t| t.visit_with(visitor)) + } +} + impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { fn try_fold_with>(self, folder: &mut F) -> Result { self.try_map_id(|t| t.try_fold_with(folder)) @@ -901,88 +605,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List TypeVisitable<'tcx> - for &'tcx ty::List>> -{ - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.iter().try_for_each(|p| p.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { fn try_fold_with>(self, folder: &mut F) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - use crate::ty::InstanceDef::*; - Ok(Self { - substs: self.substs.try_fold_with(folder)?, - def: match self.def { - Item(def) => Item(def.try_fold_with(folder)?), - VTableShim(did) => VTableShim(did.try_fold_with(folder)?), - ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?), - Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?), - FnPtrShim(did, ty) => { - FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i), - ClosureOnceShim { call_once, track_caller } => { - ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller } - } - DropGlue(did, ty) => { - DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - CloneShim(did, ty) => { - CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - }, - }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - use crate::ty::InstanceDef::*; - self.substs.visit_with(visitor)?; - match self.def { - Item(def) => def.visit_with(visitor), - VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { - did.visit_with(visitor) - } - FnPtrShim(did, ty) | CloneShim(did, ty) => { - did.visit_with(visitor)?; - ty.visit_with(visitor) - } - DropGlue(did, ty) => { - did.visit_with(visitor)?; - ty.visit_with(visitor) - } - ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.instance.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn try_fold_with>(self, folder: &mut F) -> Result { folder.try_fold_ty(self) @@ -1005,9 +633,11 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?), ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), - ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) - } + ty::Dynamic(trait_ty, region, representation) => ty::Dynamic( + trait_ty.try_fold_with(folder)?, + region.try_fold_with(folder)?, + representation, + ), ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), @@ -1051,7 +681,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg) => { + ty::Dynamic(ref trait_ty, ref reg, _) => { trait_ty.visit_with(visitor)?; reg.visit_with(visitor) } @@ -1156,12 +786,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.iter().try_for_each(|p| p.visit_with(visitor)) - } -} - impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.try_map_id(|x| x.try_fold_with(folder)) @@ -1208,34 +832,6 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?), - ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?), - ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ty::ConstKind::Value(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) - | ty::ConstKind::Error(_) => self, - }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - match *self { - ty::ConstKind::Infer(ic) => ic.visit_with(visitor), - ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ty::ConstKind::Value(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Error(_) => ControlFlow::CONTINUE, - } - } -} - impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { fn try_fold_with>(self, _folder: &mut F) -> Result { Ok(self) @@ -1290,15 +886,3 @@ impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> { self.expand().visit_with(visitor) } } - -impl<'tcx> TypeFoldable<'tcx> for hir::Constness { - fn try_fold_with>(self, _: &mut F) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeVisitable<'tcx> for hir::Constness { - fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE - } -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52c3a3886..36e560850 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -11,6 +11,7 @@ use crate::ty::{ TypeVisitor, }; use crate::ty::{List, ParamEnv}; +use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; @@ -201,7 +202,7 @@ static_assert_size!(TyKind<'_>, 32); /// * `GR`: The "return type", which is the type of value returned upon /// completion of the generator. /// * `GW`: The "generator witness". -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with a tuple containing the types of the upvars. @@ -325,10 +326,14 @@ impl<'tcx> ClosureSubsts<'tcx> { _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()), } } + + pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> { + ty::print::PrintClosureAsImpl { closure: self } + } } /// Similar to `ClosureSubsts`; see the above documentation for more. -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } @@ -655,7 +660,7 @@ impl<'tcx> InlineConstSubsts<'tcx> { } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum ExistentialPredicate<'tcx> { /// E.g., `Iterator`. Trait(ExistentialTraitRef<'tcx>), @@ -687,6 +692,9 @@ impl<'tcx> ExistentialPredicate<'tcx> { } impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> { + /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { @@ -781,7 +789,7 @@ impl<'tcx> List>> { /// Trait references also appear in object types like `Foo`, but in /// that case the `Self` parameter is absent from the substitutions. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -845,6 +853,12 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) @@ -853,7 +867,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -1009,7 +1023,7 @@ impl BoundVariableKind { /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(HashStable)] +#[derive(HashStable, Lift)] pub struct Binder<'tcx, T>(T, &'tcx List); impl<'tcx, T> Binder<'tcx, T> @@ -1171,7 +1185,7 @@ impl<'tcx, T> Binder<'tcx, Option> { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: SubstsRef<'tcx>, @@ -1186,7 +1200,9 @@ pub struct ProjectionTy<'tcx> { impl<'tcx> ProjectionTy<'tcx> { pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { - tcx.parent(self.item_def_id) + let parent = tcx.parent(self.item_def_id); + assert_eq!(tcx.def_kind(parent), DefKind::Trait); + parent } /// Extracts the underlying trait reference and own substs from this projection. @@ -1221,7 +1237,7 @@ impl<'tcx> ProjectionTy<'tcx> { } } -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, @@ -1237,7 +1253,7 @@ pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>; /// - `output`: is the return type. /// - `c_variadic`: indicates whether this is a C-variadic function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List>, pub c_variadic: bool, @@ -1419,7 +1435,7 @@ impl From for BoundTy { /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialProjection<'tcx> { pub item_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -1501,7 +1517,6 @@ impl<'tcx> Region<'tcx> { ty::ReStatic => true, ty::ReVar(..) => false, ty::RePlaceholder(placeholder) => placeholder.name.is_named(), - ty::ReEmpty(_) => false, ty::ReErased => false, } } @@ -1526,11 +1541,6 @@ impl<'tcx> Region<'tcx> { matches!(*self, ty::RePlaceholder(..)) } - #[inline] - pub fn is_empty(self) -> bool { - matches!(*self, ty::ReEmpty(..)) - } - #[inline] pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match *self { @@ -1562,7 +1572,7 @@ impl<'tcx> Region<'tcx> { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; } - ty::ReEmpty(_) | ty::ReStatic => { + ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } ty::ReLateBound(..) => { @@ -1617,6 +1627,10 @@ impl<'tcx> Region<'tcx> { _ => self.is_free(), } } + + pub fn is_var(self) -> bool { + matches!(self.kind(), ty::ReVar(_)) + } } /// Type utilities @@ -1838,7 +1852,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_trait(self) -> bool { - matches!(self.kind(), Dynamic(..)) + matches!(self.kind(), Dynamic(_, _, ty::Dyn)) + } + + #[inline] + pub fn is_dyn_star(self) -> bool { + matches!(self.kind(), Dynamic(_, _, ty::DynStar)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 6262aa180..8e69bf067 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -459,12 +459,6 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } -impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> { - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn try_fold_with>(self, folder: &mut F) -> Result { // This code is fairly hot, though not as hot as `SubstsRef`. @@ -497,7 +491,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List> { +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List { fn visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 541dace5c..ac79949fc 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -256,7 +256,6 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } // Query provider for `incoherent_impls`. -#[instrument(level = "debug", skip(tcx))] pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let mut impls = Vec::new(); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 591bb7831..23ad4d27d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -627,7 +627,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Expands the given impl trait type, stopping if the type is recursive. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -644,7 +644,6 @@ impl<'tcx> TyCtxt<'tcx> { }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); - trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } @@ -652,6 +651,13 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.type_of(def_id)) } + pub fn bound_trait_impl_trait_tys( + self, + def_id: DefId, + ) -> ty::EarlyBinder>, ErrorGuaranteed>> { + ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id)) + } + pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder> { ty::EarlyBinder(self.fn_sig(def_id)) } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 536506720..5f8cb5782 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -84,7 +84,7 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { self.has_vars_bound_at_or_above(ty::INNERMOST) } - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } @@ -560,7 +560,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let flags = t.flags(); trace!(t.flags=?t.flags()); @@ -572,7 +572,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); trace!(r.flags=?flags); @@ -584,7 +584,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); trace!(r.flags=?flags); @@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { let flags = FlagComputation::for_unevaluated_const(uv); trace!(r.flags=?flags); @@ -608,7 +608,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", @@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { - if let ty::Projection(..) = t.kind() { + if let ty::Projection(..) | ty::Opaque(..) = t.kind() { return ControlFlow::CONTINUE; } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 04a9fd1f7..5ca51c25a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::fmt; -use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit}; +use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; @@ -87,7 +87,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = ty::Instance::resolve_drop_in_place(tcx, ty); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(), VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(), @@ -97,14 +97,14 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = instance.polymorphize(tcx); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::TraitVPtr(trait_ref) => { let super_trait_ref = trait_ref .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref))); let vptr = Pointer::from(supertrait_alloc_id); - ScalarMaybeUninit::from_pointer(vptr, &tcx) + Scalar::from_pointer(vptr, &tcx) } }; vtable diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 02fe1f3a7..a3e11bbf0 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -152,7 +152,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Projection(data) => { stack.extend(data.substs.iter().rev()); } - ty::Dynamic(obj, lt) => { + ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); stack.extend(obj.iter().rev().flat_map(|predicate| { let (substs, opt_ty) = match predicate.skip_binder() { @@ -165,9 +165,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }; - substs.iter().rev().chain(opt_ty.map(|term| match term { - ty::Term::Ty(ty) => ty.into(), - ty::Term::Const(ct) => ct.into(), + substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(ct) => ct.into(), })) })); } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs new file mode 100644 index 000000000..7fbe9ae2a --- /dev/null +++ b/compiler/rustc_middle/src/values.rs @@ -0,0 +1,54 @@ +use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt}; +use rustc_query_system::Value; + +impl<'tcx> Value> for Ty<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { + // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { std::mem::transmute::, Ty<'_>>(tcx.ty_error()) } + } +} + +impl<'tcx> Value> for ty::SymbolName<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { + // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { + std::mem::transmute::, ty::SymbolName<'_>>(ty::SymbolName::new( + tcx, "", + )) + } + } +} + +impl<'tcx> Value> for AdtSizedConstraint<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { + // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { + std::mem::transmute::, AdtSizedConstraint<'_>>( + AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])), + ) + } + } +} + +impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { + let err = tcx.ty_error(); + // FIXME(compiler-errors): It would be nice if we could get the + // query key, so we could at least generate a fn signature that + // has the right arity. + let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [].into_iter(), + err, + false, + rustc_hir::Unsafety::Normal, + rustc_target::spec::abi::Abi::Rust, + )); + + // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { std::mem::transmute::, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) } + } +} diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 687560012..784583d94 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,6 +1,7 @@ use crate::build::matches::ArmHasGuard; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; +use rustc_middle::middle::region::Scope; use rustc_middle::thir::*; use rustc_middle::{mir::*, ty}; use rustc_span::Span; @@ -10,7 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, block: BasicBlock, - ast_block: &Block, + ast_block: BlockId, source_info: SourceInfo, ) -> BlockAnd<()> { let Block { @@ -21,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr, targeted_by_break, safety_mode, - } = *ast_block; + } = self.thir[ast_block]; let expr = expr.map(|expr| &self.thir[expr]); self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { @@ -34,10 +35,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &stmts, expr, safety_mode, + region_scope, )) }) } else { - this.ast_block_stmts(destination, block, span, &stmts, expr, safety_mode) + this.ast_block_stmts( + destination, + block, + span, + &stmts, + expr, + safety_mode, + region_scope, + ) } }) }) @@ -51,6 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { stmts: &[StmtId], expr: Option<&Expr<'tcx>>, safety_mode: BlockSafety, + region_scope: Scope, ) -> BlockAnd<()> { let this = self; @@ -73,6 +84,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut let_scope_stack = Vec::with_capacity(8); let outer_source_scope = this.source_scope; let outer_in_scope_unsafe = this.in_scope_unsafe; + // This scope information is kept for breaking out of the parent remainder scope in case + // one let-else pattern matching fails. + // By doing so, we can be sure that even temporaries that receive extended lifetime + // assignments are dropped, too. + let mut last_remainder_scope = region_scope; this.update_source_scope_for_safety_mode(span, safety_mode); let source_info = this.source_info(span); @@ -93,15 +109,172 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) ); } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer: Some(initializer), + lint_level, + else_block: Some(else_block), + } => { + // When lowering the statement `let = else { };`, + // the `` block is nested in the parent scope enclosing this statment. + // That scope is usually either the enclosing block scope, + // or the remainder scope of the last statement. + // This is to make sure that temporaries instantiated in `` are dropped + // as well. + // In addition, even though bindings in `` only come into scope if + // the pattern matching passes, in the MIR building the storages for them + // are declared as live any way. + // This is similar to `let x;` statements without an initializer expression, + // where the value of `x` in this example may or may be assigned, + // because the storage for their values may not be live after all due to + // failure in pattern matching. + // For this reason, we declare those storages as live but we do not schedule + // any drop yet- they are scheduled later after the pattern matching. + // The generated MIR will have `StorageDead` whenever the control flow breaks out + // of the parent scope, regardless of the result of the pattern matching. + // However, the drops are inserted in MIR only when the control flow breaks out of + // the scope of the remainder scope associated with this `let .. else` statement. + // Pictorial explanation of the scope structure: + // ┌─────────────────────────────────┠+ // │ Scope of the enclosing block, │ + // │ or the last remainder scope │ + // │ ┌───────────────────────────┠│ + // │ │ Scope for block │ │ + // │ └───────────────────────────┘ │ + // │ ┌───────────────────────────┠│ + // │ │ Remainder scope of │ │ + // │ │ this let-else statement │ │ + // │ │ ┌─────────────────────┠│ │ + // │ │ │ scope │ │ │ + // │ │ └─────────────────────┘ │ │ + // │ │ extended temporaries in │ │ + // │ │ lives in this │ │ + // │ │ scope │ │ + // │ │ ┌─────────────────────┠│ │ + // │ │ │ Scopes for the rest │ │ │ + // │ │ └─────────────────────┘ │ │ + // │ └───────────────────────────┘ │ + // └─────────────────────────────────┘ + // Generated control flow: + // │ let Some(x) = y() else { return; } + // │ + // ┌────────▼───────┠+ // │ evaluate y() │ + // └────────┬───────┘ + // │ ┌────────────────┠+ // ┌────────▼───────┠│Drop temporaries│ + // │Test the pattern├──────►in y() │ + // └────────┬───────┘ │because breaking│ + // │ │out of │ + // ┌────────▼───────┠│scope │ + // │Move value into │ └───────┬────────┘ + // │binding x │ │ + // └────────┬───────┘ ┌───────▼────────┠+ // │ │Drop extended │ + // ┌────────▼───────┠│temporaries in │ + // │Drop temporaries│ │ because │ + // │in y() │ │breaking out of │ + // │because breaking│ │remainder scope │ + // │out of │ └───────┬────────┘ + // │scope │ │ + // └────────┬───────┘ ┌───────▼────────┠+ // │ │Enter ├────────► + // ┌────────▼───────┠│block │ return; + // │Continue... │ └────────────────┘ + // └────────────────┘ + + let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); + this.block_context.push(BlockFrame::Statement { ignores_expr_result }); + + // Lower the `else` block first because its parent scope is actually + // enclosing the rest of the `let .. else ..` parts. + let else_block_span = this.thir[*else_block].span; + // This place is not really used because this destination place + // should never be used to take values at the end of the failure + // block. + let dummy_place = this.temp(this.tcx.types.never, else_block_span); + let failure_entry = this.cfg.start_new_block(); + let failure_block; + unpack!( + failure_block = this.ast_block( + dummy_place, + failure_entry, + *else_block, + this.source_info(else_block_span), + ) + ); + this.cfg.terminate( + failure_block, + this.source_info(else_block_span), + TerminatorKind::Unreachable, + ); + + // Declare the bindings, which may create a source scope. + let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree); + this.push_scope((*remainder_scope, source_info)); + let_scope_stack.push(remainder_scope); + + let visibility_scope = + Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); + + let init = &this.thir[*initializer]; + let initializer_span = init.span; + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + this.visit_primary_bindings( + pattern, + UserTypeProjections::none(), + &mut |this, _, _, _, node, span, _, _| { + this.storage_live_binding(block, node, span, OutsideGuard, true); + }, + ); + let failure = unpack!( + block = this.in_opt_scope( + opt_destruction_scope.map(|de| (de, source_info)), + |this| { + let scope = (*init_scope, source_info); + this.in_scope(scope, *lint_level, |this| { + this.ast_let_else( + block, + init, + initializer_span, + *else_block, + &last_remainder_scope, + pattern, + ) + }) + } + ) + ); + this.cfg.goto(failure, source_info, failure_entry); + + if let Some(source_scope) = visibility_scope { + this.source_scope = source_scope; + } + last_remainder_scope = *remainder_scope; + } + StmtKind::Let { init_scope, initializer: None, else_block: Some(_), .. } => { + span_bug!( + init_scope.span(this.tcx, this.region_scope_tree), + "initializer is missing, but else block is present in this let binding", + ) + } StmtKind::Let { remainder_scope, init_scope, ref pattern, initializer, lint_level, - else_block, + else_block: None, } => { - let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); + let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); // Enter the remainder scope, i.e., the bindings' destruction scope. @@ -125,27 +298,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |this| { let scope = (*init_scope, source_info); this.in_scope(scope, *lint_level, |this| { - if let Some(else_block) = else_block { - this.ast_let_else( - block, - init, - initializer_span, - else_block, - visibility_scope, - *remainder_scope, - remainder_span, - pattern, - ) - } else { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); - this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern - } + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + this.expr_into_pattern(block, &pattern, init) // irrefutable pattern }) }, ) @@ -178,6 +338,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(source_scope) = visibility_scope { this.source_scope = source_scope; } + last_remainder_scope = *remainder_scope; } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 648d10b9e..c9bec130c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -2,26 +2,18 @@ use crate::build::{parse_float_into_constval, Builder}; use rustc_ast as ast; -use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; use rustc_middle::mir::*; use rustc_middle::thir::*; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt}; use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { - let create_uneval_from_def_id = - |tcx: TyCtxt<'tcx>, def_id: DefId, ty: Ty<'tcx>, substs: SubstsRef<'tcx>| { - let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); - tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(uneval), ty }) - }; - let this = self; let tcx = this.tcx; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; @@ -41,11 +33,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: None, literal } } - ExprKind::NonHirLiteral { lit, user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::NonHirLiteral { lit, ref user_ty } => { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); @@ -53,11 +45,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } - ExprKind::ZstLiteral { user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::ZstLiteral { ref user_ty } => { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); @@ -65,15 +57,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } - ExprKind::NamedConst { def_id, substs, user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::NamedConst { def_id, substs, ref user_ty } => { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); - let literal = ConstantKind::Ty(create_uneval_from_def_id(tcx, def_id, ty, substs)); + + let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); + let literal = ConstantKind::Unevaluated(uneval, ty); Constant { user_ty, span, literal } } @@ -85,7 +79,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { user_ty: None, span, literal } } ExprKind::ConstBlock { did: def_id, substs } => { - let literal = ConstantKind::Ty(create_uneval_from_def_id(tcx, def_id, ty, substs)); + let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); + let literal = ConstantKind::Unevaluated(uneval, ty); Constant { user_ty: None, span, literal } } @@ -144,7 +139,7 @@ pub(crate) fn lit_to_mir_constant<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + (ast::LitKind::Err, _) => return Err(LitToConstError::Reported), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 0c06aad4e..ebb56e5a2 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -2,7 +2,7 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; -use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap}; use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; @@ -59,8 +59,6 @@ pub(crate) enum PlaceBase { var_hir_id: LocalVarId, /// DefId of the closure closure_def_id: LocalDefId, - /// The trait closure implements, `Fn`, `FnMut`, `FnOnce` - closure_kind: ty::ClosureKind, }, } @@ -145,27 +143,6 @@ fn is_ancestor_or_same_capture( iter::zip(proj_possible_ancestor, proj_capture).all(|(a, b)| a == b) } -/// Computes the index of a capture within the desugared closure provided the closure's -/// `closure_min_captures` and the capture's index of the capture in the -/// `ty::MinCaptureList` of the root variable `var_hir_id`. -fn compute_capture_idx<'tcx>( - closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>, - var_hir_id: LocalVarId, - root_var_idx: usize, -) -> usize { - let mut res = 0; - for (var_id, capture_list) in closure_min_captures { - if *var_id == var_hir_id.0 { - res += root_var_idx; - break; - } else { - res += capture_list.len(); - } - } - - res -} - /// Given a closure, returns the index of a capture within the desugared closure struct and the /// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id` /// and `projection`. @@ -174,27 +151,17 @@ fn compute_capture_idx<'tcx>( /// /// Returns None, when the ancestor is not found. fn find_capture_matching_projections<'a, 'tcx>( - typeck_results: &'a ty::TypeckResults<'tcx>, + upvars: &'a CaptureMap<'tcx>, var_hir_id: LocalVarId, - closure_def_id: LocalDefId, projections: &[PlaceElem<'tcx>], -) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> { - let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?; - let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?; - +) -> Option<(usize, &'a Capture<'tcx>)> { let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); - // If an ancestor is found, `idx` is the index within the list of captured places - // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself. - let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| { + upvars.get_by_key_enumerated(var_hir_id.0).find(|(_, capture)| { let possible_ancestor_proj_kinds: Vec<_> = - capture.place.projections.iter().map(|proj| proj.kind).collect(); + capture.captured_place.place.projections.iter().map(|proj| proj.kind).collect(); is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections) - })?; - - // Convert index to be from the perspective of the entire closure_min_captures map - // instead of just the root variable capture list - Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture)) + }) } /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the @@ -204,24 +171,15 @@ fn find_capture_matching_projections<'a, 'tcx>( fn to_upvars_resolved_place_builder<'a, 'tcx>( from_builder: PlaceBuilder<'tcx>, tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + upvars: &'a CaptureMap<'tcx>, ) -> Result, PlaceBuilder<'tcx>> { match from_builder.base { PlaceBase::Local(_) => Ok(from_builder), - PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { - let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL); - match closure_kind { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - upvar_resolved_place_builder = upvar_resolved_place_builder.deref(); - } - ty::ClosureKind::FnOnce => {} - } - + PlaceBase::Upvar { var_hir_id, closure_def_id } => { let Some((capture_index, capture)) = find_capture_matching_projections( - typeck_results, + upvars, var_hir_id, - closure_def_id, &from_builder.projection, ) else { let closure_span = tcx.def_span(closure_def_id); @@ -241,39 +199,17 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( return Err(from_builder); }; - // We won't be building MIR if the closure wasn't local - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id); - let closure_ty = typeck_results.node_type(closure_hir_id); - - let substs = match closure_ty.kind() { - ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), - ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), - _ => bug!("Lowering capture for non-closure type {:?}", closure_ty), - }; - // Access the capture by accessing the field within the Closure struct. - // - // We must have inferred the capture types since we are building MIR, therefore - // it's safe to call `tuple_element_ty` and we can unwrap here because - // we know that the capture exists and is the `capture_index`-th capture. - let var_ty = substs.tupled_upvars_ty().tuple_fields()[capture_index]; - - upvar_resolved_place_builder = - upvar_resolved_place_builder.field(Field::new(capture_index), var_ty); - - // If the variable is captured via ByRef(Immutable/Mutable) Borrow, - // we need to deref it - upvar_resolved_place_builder = match capture.info.capture_kind { - ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), - ty::UpvarCapture::ByValue => upvar_resolved_place_builder, - }; + let capture_info = &upvars[capture_index]; + + let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place); // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. let remaining_projections = strip_prefix( - capture.place.base_ty, + capture.captured_place.place.base_ty, from_builder.projection, - &capture.place.projections, + &capture.captured_place.place.projections, ); upvar_resolved_place_builder.projection.extend(remaining_projections); @@ -315,24 +251,24 @@ fn strip_prefix<'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - pub(crate) fn into_place<'a>( + pub(in crate::build) fn into_place<'a>( self, tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + upvars: &'a CaptureMap<'tcx>, ) -> Place<'tcx> { if let PlaceBase::Local(local) = self.base { Place { local, projection: tcx.intern_place_elems(&self.projection) } } else { - self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + self.expect_upvars_resolved(tcx, upvars).into_place(tcx, upvars) } } fn expect_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + upvars: &'a CaptureMap<'tcx>, ) -> PlaceBuilder<'tcx> { - to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() + to_upvars_resolved_place_builder(self, tcx, upvars).unwrap() } /// Attempts to resolve the `PlaceBuilder`. @@ -346,12 +282,12 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - pub(crate) fn try_upvars_resolved<'a>( + pub(in crate::build) fn try_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + upvars: &'a CaptureMap<'tcx>, ) -> Result, PlaceBuilder<'tcx>> { - to_upvars_resolved_place_builder(self, tcx, typeck_results) + to_upvars_resolved_place_builder(self, tcx, upvars) } pub(crate) fn base(&self) -> PlaceBase { @@ -392,6 +328,12 @@ impl<'tcx> From for PlaceBuilder<'tcx> { } } +impl<'tcx> From> for PlaceBuilder<'tcx> { + fn from(p: Place<'tcx>) -> Self { + Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() } + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a place that we can move from etc. /// @@ -411,7 +353,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self.tcx, &self.upvars)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -435,7 +377,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self.tcx, &self.upvars)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -513,7 +455,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder) } - ExprKind::PlaceTypeAscription { source, user_ty } => { + ExprKind::PlaceTypeAscription { source, ref user_ty } => { let place_builder = unpack!( block = this.expr_as_place( block, @@ -526,11 +468,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty, + user_ty: user_ty.clone(), inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.tcx, this.typeck_results); + let place = place_builder.clone().into_place(this.tcx, &this.upvars); this.cfg.push( block, Statement { @@ -547,7 +489,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } block.and(place_builder) } - ExprKind::ValueTypeAscription { source, user_ty } => { + ExprKind::ValueTypeAscription { source, ref user_ty } => { let source = &this.thir[source]; let temp = unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); @@ -555,7 +497,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty, + user_ty: user_ty.clone(), inferred_ty: expr.ty, }); this.cfg.push( @@ -629,17 +571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { closure_def_id: LocalDefId, var_hir_id: LocalVarId, ) -> BlockAnd> { - let closure_ty = - self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_def_id)); - - let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { - self.infcx.closure_kind(closure_substs).unwrap() - } else { - // Generators are considered FnOnce. - ty::ClosureKind::FnOnce - }; - - block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind })) + block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id })) } /// Lower an index expression @@ -678,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results); + base_place = base_place.expect_upvars_resolved(self.tcx, &self.upvars); self.add_fake_borrows_of_base( &base_place, block, @@ -710,7 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, len, - Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), + Rvalue::Len(slice.into_place(self.tcx, &self.upvars)), ); // lt = idx < len self.cfg.push_assign( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 15f2d17c4..f88ab63f0 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -197,13 +197,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // create all the steps directly in MIR with operations all backends need to support anyway. let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() { let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); - let place = unpack!(block = this.as_place(block, source)); + let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not)); let discr = this.temp(discr_ty, source.span); this.cfg.push_assign( block, source_info, discr, - Rvalue::Discriminant(place), + Rvalue::Discriminant(temp.into()), ); (Operand::Move(discr), discr_ty) @@ -216,6 +216,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); + debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress @@ -223,6 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => { CastKind::PointerFromExposedAddress } + (_, Some(CastTy::DynStar)) => CastKind::DynStar, (_, _) => CastKind::Misc, }; block.and(Rvalue::Cast(cast_kind, source, expr.ty)) @@ -302,7 +304,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields)) } - ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => { + ExprKind::Closure(box ClosureExpr { + closure_id, + substs, + ref upvars, + movability, + ref fake_reads, + }) => { // Convert the closure fake reads, if any, from `ExprRef` to mir `Place` // and push the fake reads. // This must come before creating the operands. This is required in case @@ -322,10 +330,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + place_builder.try_upvars_resolved(this.tcx, &this.upvars) { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); + let mir_place = place_builder_resolved.into_place(this.tcx, &this.upvars); this.cfg.push_fake_read( block, this.source_info(this.tcx.hir().span(*hir_id)), @@ -617,7 +624,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { let enclosing_upvars_resolved = - arg_place_builder.clone().into_place(this.tcx, this.typeck_results); + arg_place_builder.clone().into_place(this.tcx, &this.upvars); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -637,12 +644,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); // Not in a closure debug_assert!( - this.upvar_mutbls.len() > upvar_index.index(), - "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}", - this.upvar_mutbls, + this.upvars.len() > upvar_index.index(), + "Unexpected capture place, upvars={:#?}, upvar_index={:?}", + this.upvars, upvar_index ); - this.upvar_mutbls[upvar_index.index()] + this.upvars[upvar_index.index()].mutability } _ => bug!("Unexpected capture place"), } @@ -654,7 +661,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results); + let arg_place = arg_place_builder.into_place(this.tcx, &this.upvars); this.cfg.push_assign( block, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 724b72f87..e5dafb820 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -83,8 +83,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Don't bother with StorageLive and Dead for these temporaries, // they are never assigned. ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (), - ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } } - if expr_ty.is_never() => {} + ExprKind::Block { block } + if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block] + && expr_ty.is_never() => {} _ => { this.cfg .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 017d43d10..224a1b80f 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) }) } - ExprKind::Block { body: ref ast_block } => { + ExprKind::Block { block: ast_block } => { this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { scrutinee, ref arms } => { @@ -75,7 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.source_info(then_expr.span) }; let (then_block, else_block) = - this.in_if_then_scope(condition_scope, |this| { + this.in_if_then_scope(condition_scope, then_expr.span, |this| { let then_blk = unpack!(this.then_else_break( block, &this.thir[cond], @@ -108,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Let { expr, ref pat } => { let scope = this.local_scope(); - let (true_block, false_block) = this.in_if_then_scope(scope, |this| { + let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| { this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span) }); @@ -314,11 +314,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, destination, address_of); block.unit() } - ExprKind::Adt(box Adt { + ExprKind::Adt(box AdtExpr { adt_def, variant_index, substs, - user_ty, + ref user_ty, ref fields, ref base, }) => { @@ -366,9 +366,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None => { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( - place_builder - .field(n, *ty) - .into_place(this.tcx, this.typeck_results), + place_builder.field(n, *ty).into_place(this.tcx, &this.upvars), ) } }) @@ -378,10 +376,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let inferred_ty = expr.ty; - let user_ty = user_ty.map(|ty| { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty: ty, + user_ty: user_ty.clone(), inferred_ty, }) }); @@ -400,7 +398,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.unit() } - ExprKind::InlineAsm { template, ref operands, options, line_spans } => { + ExprKind::InlineAsm(box InlineAsmExpr { + template, + ref operands, + options, + line_spans, + }) => { use rustc_middle::{mir, thir}; let operands = operands .into_iter() diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index a7e1331aa..00dbcaeb0 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -116,14 +116,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. let adjusted_span = (|| { - if let ExprKind::Block { body } = &expr.kind && let Some(tail_ex) = body.expr { + if let ExprKind::Block { block } = expr.kind + && let Some(tail_ex) = this.thir[block].expr + { let mut expr = &this.thir[tail_ex]; - while let ExprKind::Block { - body: Block { expr: Some(nested_expr), .. }, - } - | ExprKind::Scope { value: nested_expr, .. } = expr.kind - { - expr = &this.thir[nested_expr]; + loop { + match expr.kind { + ExprKind::Block { block } + if let Some(nested_expr) = this.thir[block].expr => + { + expr = &this.thir[nested_expr]; + } + ExprKind::Scope { value: nested_expr, .. } => { + expr = &this.thir[nested_expr]; + } + _ => break, + } } this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored: true, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 58b1564cc..93f382cc6 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// * From each pre-binding block to the next pre-binding block. /// * From each otherwise block to the next pre-binding block. - #[tracing::instrument(level = "debug", skip(self, arms))] + #[instrument(level = "debug", skip(self, arms))] pub(crate) fn match_expr( &mut self, destination: Place<'tcx>, @@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms); - let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some()); + let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard); let mut candidates = arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::>(); @@ -221,9 +221,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(scrutinee_span); if let Ok(scrutinee_builder) = - scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) + scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, &self.upvars) { - let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results); + let scrutinee_place = scrutinee_builder.into_place(self.tcx, &self.upvars); self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -348,12 +348,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; let scrutinee_place: Place<'tcx>; - if let Ok(scrutinee_builder) = scrutinee_place_builder - .clone() - .try_upvars_resolved(this.tcx, this.typeck_results) + if let Ok(scrutinee_builder) = + scrutinee_place_builder.clone().try_upvars_resolved(this.tcx, &this.upvars) { - scrutinee_place = - scrutinee_builder.into_place(this.tcx, this.typeck_results); + scrutinee_place = scrutinee_builder.into_place(this.tcx, &this.upvars); opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); } let scope = this.declare_bindings( @@ -373,6 +371,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(arm.span), Some(arm.scope), Some(match_scope), + false, ); if let Some(source_scope) = scope { @@ -418,6 +417,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span: Option, arm_scope: Option, match_scope: Option, + storages_alive: bool, ) -> BasicBlock { if candidate.subcandidates.is_empty() { // Avoid generating another `BasicBlock` when we only have one @@ -431,6 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span, match_scope, true, + storages_alive, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -468,6 +469,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span, match_scope, schedule_drops, + storages_alive, ); if arm_scope.is_none() { schedule_drops = false; @@ -490,10 +492,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(super) fn expr_into_pattern( &mut self, mut block: BasicBlock, - irrefutable_pat: Pat<'tcx>, + irrefutable_pat: &Pat<'tcx>, initializer: &Expr<'tcx>, ) -> BlockAnd<()> { - match *irrefutable_pat.kind { + match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = @@ -518,17 +520,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // broken. PatKind::AscribeUserType { subpattern: - Pat { + box Pat { kind: - box PatKind::Binding { - mode: BindingMode::ByValue, - var, - subpattern: None, - .. + PatKind::Binding { + mode: BindingMode::ByValue, var, subpattern: None, .. }, .. }, - ascription: thir::Ascription { annotation, variance: _ }, + ascription: thir::Ascription { ref annotation, variance: _ }, } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); @@ -541,7 +540,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty_source_info = self.source_info(annotation.span); - let base = self.canonical_user_type_annotations.push(annotation); + let base = self.canonical_user_type_annotations.push(annotation.clone()); self.cfg.push( block, Statement { @@ -573,7 +572,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => { let place_builder = unpack!(block = self.as_place_builder(block, initializer)); - self.place_into_pattern(block, irrefutable_pat, place_builder, true) + self.place_into_pattern(block, &irrefutable_pat, place_builder, true) } } } @@ -581,7 +580,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn place_into_pattern( &mut self, block: BasicBlock, - irrefutable_pat: Pat<'tcx>, + irrefutable_pat: &Pat<'tcx>, initializer: PlaceBuilder<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { @@ -623,9 +622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` if let Ok(match_pair_resolved) = - initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) + initializer.clone().try_upvars_resolved(self.tcx, &self.upvars) { - let place = match_pair_resolved.into_place(self.tcx, self.typeck_results); + let place = match_pair_resolved.into_place(self.tcx, &self.upvars); *match_place = Some(place); } } @@ -646,6 +645,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + false, ) .unit() } @@ -702,9 +702,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); - // Altough there is almost always scope for given variable in corner cases + // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. - if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{ + if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop { self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } Place::from(local_id) @@ -744,7 +744,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty ); - match *pattern.kind { + match pattern.kind { PatKind::Binding { mutability, name, @@ -767,7 +767,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Slice { ref prefix, ref slice, ref suffix } => { let from = u64::try_from(prefix.len()).unwrap(); let to = u64::try_from(suffix.len()).unwrap(); - for subpattern in prefix { + for subpattern in prefix.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } for subpattern in slice { @@ -777,7 +777,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { f, ); } - for subpattern in suffix { + for subpattern in suffix.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } } @@ -830,7 +830,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // may not all be in the leftmost subpattern. For example in // `let (x | y) = ...`, the primary binding of `y` occurs in // the right subpattern - for subpattern in pats { + for subpattern in pats.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f); } } @@ -982,7 +982,7 @@ enum TestKind<'tcx> { }, /// Test whether the value falls within an inclusive or exclusive range - Range(PatRange<'tcx>), + Range(Box>), /// Test that the length of the slice is equal to `len`. Len { len: u64, op: BinOp }, @@ -1330,7 +1330,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // All of the or-patterns have been sorted to the end, so if the first // pattern is an or-pattern we only have or-patterns. - match *first_candidate.match_pairs[0].pattern.kind { + match first_candidate.match_pairs[0].pattern.kind { PatKind::Or { .. } => (), _ => { self.test_candidates( @@ -1350,7 +1350,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut otherwise = None; for match_pair in match_pairs { - let PatKind::Or { ref pats } = &*match_pair.pattern.kind else { + let PatKind::Or { ref pats } = &match_pair.pattern.kind else { bug!("Or-patterns should have been sorted to the end"); }; let or_span = match_pair.pattern.span; @@ -1384,7 +1384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &mut Candidate<'pat, 'tcx>, otherwise: &mut Option, - pats: &'pat [Pat<'tcx>], + pats: &'pat [Box>], or_span: Span, place: PlaceBuilder<'tcx>, fake_borrows: &mut Option>>, @@ -1605,9 +1605,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of any places that is switched on. if let Some(fb) = fake_borrows && let Ok(match_place_resolved) = - match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + match_place.clone().try_upvars_resolved(self.tcx, &self.upvars) { - let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results); + let resolved_place = match_place_resolved.into_place(self.tcx, &self.upvars); fb.insert(resolved_place); } @@ -1794,10 +1794,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None; let expr_place: Place<'tcx>; - if let Ok(expr_builder) = - expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - expr_place = expr_builder.into_place(self.tcx, self.typeck_results); + if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self.tcx, &self.upvars) { + expr_place = expr_builder.into_place(self.tcx, &self.upvars); opt_expr_place = Some((Some(&expr_place), expr_span)); } let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); @@ -1820,6 +1818,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + false, ); post_guard_block.unit() @@ -1843,6 +1842,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span: Option, match_scope: Option, schedule_drops: bool, + storages_alive: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1978,7 +1978,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut guard_span = rustc_span::DUMMY_SP; let (post_guard_block, otherwise_post_guard_block) = - self.in_if_then_scope(match_scope, |this| match *guard { + self.in_if_then_scope(match_scope, guard_span, |this| match *guard { Guard::If(e) => { let e = &this.thir[e]; guard_span = e.span; @@ -2058,7 +2058,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } assert!(schedule_drops, "patterns with guards must schedule drops"); - self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings); + self.bind_matched_candidate_for_arm_body( + post_guard_block, + true, + by_value_bindings, + storages_alive, + ); post_guard_block } else { @@ -2072,6 +2077,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .flat_map(|(bindings, _)| bindings) .chain(&candidate.bindings), + storages_alive, ); block } @@ -2161,6 +2167,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, schedule_drops: bool, bindings: impl IntoIterator>, + storages_alive: bool, ) where 'tcx: 'b, { @@ -2170,13 +2177,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = self.storage_live_binding( - block, - binding.var_id, - binding.span, - OutsideGuard, - schedule_drops, - ); + let local = if storages_alive { + // Here storages are already alive, probably because this is a binding + // from let-else. + // We just need to schedule drop for the value. + self.var_local_id(binding.var_id, OutsideGuard).into() + } else { + self.storage_live_binding( + block, + binding.var_id, + binding.span, + OutsideGuard, + schedule_drops, + ) + }; if schedule_drops { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } @@ -2280,23 +2294,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, init: &Expr<'tcx>, initializer_span: Span, - else_block: &Block, - visibility_scope: Option, - remainder_scope: region::Scope, - remainder_span: Span, + else_block: BlockId, + let_else_scope: ®ion::Scope, pattern: &Pat<'tcx>, - ) -> BlockAnd<()> { - let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| { + ) -> BlockAnd { + let else_block_span = self.thir[else_block].span; + let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); - let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; + let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); let mut candidate = Candidate::new(scrutinee.clone(), pattern, false); let fake_borrow_temps = this.lower_match_tree( block, @@ -2315,10 +2321,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + true, ); // This block is for the failure case let failure = this.bind_pattern( - this.source_info(else_block.span), + this.source_info(else_block_span), wildcard, None, &fake_borrow_temps, @@ -2326,29 +2333,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + true, ); - this.break_for_else(failure, remainder_scope, this.source_info(initializer_span)); + this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span)); matching.unit() }); - - // This place is not really used because this destination place - // should never be used to take values at the end of the failure - // block. - let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() }; - let failure_block; - unpack!( - failure_block = self.ast_block( - dummy_place, - failure, - else_block, - self.source_info(else_block.span), - ) - ); - self.cfg.terminate( - failure_block, - self.source_info(else_block.span), - TerminatorKind::Unreachable, - ); - matching.unit() + matching.and(failure) } } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index c62989041..df221d356 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { loop { let match_pairs = mem::take(&mut candidate.match_pairs); - if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] = + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = &*match_pairs { existing_bindings.extend_from_slice(&new_bindings); @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // late as possible. candidate .match_pairs - .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. })); + .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); debug!(simplified = ?candidate, "simplify_candidate"); return false; // if we were not able to simplify any, done. } @@ -127,10 +127,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &Candidate<'pat, 'tcx>, place: PlaceBuilder<'tcx>, - pats: &'pat [Pat<'tcx>], + pats: &'pat [Box>], ) -> Vec> { pats.iter() - .map(|pat| { + .map(|box pat| { let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard); self.simplify_candidate(&mut candidate); candidate @@ -149,18 +149,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) -> Result<(), MatchPair<'pat, 'tcx>> { let tcx = self.tcx; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self.tcx, &self.upvars), variance, }); } @@ -185,11 +185,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { is_primary: _, } => { if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars) { candidate.bindings.push(Binding { span: match_pair.pattern.span, - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self.tcx, &self.upvars), var_id: var, binding_mode: mode, }); @@ -208,7 +208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::Range(PatRange { lo, hi, end }) => { + PatKind::Range(box PatRange { lo, hi, end }) => { let (range, bias) = match *lo.ty().kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) @@ -254,7 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut candidate.match_pairs, &match_pair.place, prefix, - slice.as_ref(), + slice, suffix, ); Ok(()) @@ -294,7 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut candidate.match_pairs, &match_pair.place, prefix, - slice.as_ref(), + slice, suffix, ); Ok(()) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 598da80c5..47d05a6e3 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -29,7 +29,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// It is a bug to call this with a not-fully-simplified pattern. pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test { span: match_pair.pattern.span, kind: TestKind::Switch { @@ -58,10 +58,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { kind: TestKind::Eq { value, ty: match_pair.pattern.ty }, }, - PatKind::Range(range) => { + PatKind::Range(ref range) => { assert_eq!(range.lo.ty(), match_pair.pattern.ty); assert_eq!(range.hi.ty(), match_pair.pattern.ty); - Test { span: match_pair.pattern.span, kind: TestKind::Range(range) } + Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) } } PatKind::Slice { ref prefix, ref slice, ref suffix } => { @@ -92,7 +92,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Constant { value } => { options .entry(value) @@ -102,9 +102,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Variant { .. } => { panic!("you should have called add_variants_to_switch instead!"); } - PatKind::Range(range) => { + PatKind::Range(ref range) => { // Check that none of the switch values are in the range. - self.values_not_contained_in_range(range, options).unwrap_or(false) + self.values_not_contained_in_range(&*range, options).unwrap_or(false) } PatKind::Slice { .. } | PatKind::Array { .. } @@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Variant { adt_def: _, variant_index, .. } => { // We have a pattern testing for variant `variant_index` // set the corresponding index to true @@ -154,10 +154,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { make_target_blocks: impl FnOnce(&mut Self) -> Vec, ) { let place: Place<'tcx>; - if let Ok(test_place_builder) = - place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - place = test_place_builder.into_place(self.tcx, self.typeck_results); + if let Ok(test_place_builder) = place_builder.try_upvars_resolved(self.tcx, &self.upvars) { + place = test_place_builder.into_place(self.tcx, &self.upvars); } else { return; } @@ -272,7 +270,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatRange { lo, hi, ref end }) => { + TestKind::Range(box PatRange { lo, hi, ref end }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); @@ -506,7 +504,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (match_pair_index, match_pair) = candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; - match (&test.kind, &*match_pair.pattern.kind) { + match (&test.kind, &match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. ( @@ -540,9 +538,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(index) } - (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => { + (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => { let not_contained = - self.values_not_contained_in_range(range, options).unwrap_or(false); + self.values_not_contained_in_range(&*range, options).unwrap_or(false); if not_contained { // No switch values are contained in the pattern range, @@ -569,7 +567,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair_index, candidate, prefix, - slice.as_ref(), + slice, suffix, ); Some(0) @@ -607,7 +605,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair_index, candidate, prefix, - slice.as_ref(), + slice, suffix, ); Some(0) @@ -631,7 +629,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (&TestKind::Range(test), &PatKind::Range(pat)) => { + (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => { use std::cmp::Ordering::*; if test == pat { @@ -658,8 +656,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { no_overlap } - (&TestKind::Range(range), &PatKind::Constant { value }) => { - if let Some(false) = self.const_range_contains(range, value) { + (&TestKind::Range(ref range), &PatKind::Constant { value }) => { + if let Some(false) = self.const_range_contains(&*range, value) { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. Some(1) @@ -678,7 +676,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // However, at this point we can still encounter or-patterns that were extracted // from previous calls to `sort_candidate`, so we need to manually address that // case to avoid panicking in `self.test()`. - if let PatKind::Or { .. } = &*match_pair.pattern.kind { + if let PatKind::Or { .. } = &match_pair.pattern.kind { return None; } @@ -708,9 +706,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, match_pair_index: usize, candidate: &mut Candidate<'pat, 'tcx>, - prefix: &'pat [Pat<'tcx>], - opt_slice: Option<&'pat Pat<'tcx>>, - suffix: &'pat [Pat<'tcx>], + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], ) { let removed_place = candidate.match_pairs.remove(match_pair_index).place; self.prefix_slice_suffix( @@ -754,7 +752,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn const_range_contains( &self, - range: PatRange<'tcx>, + range: &PatRange<'tcx>, value: ConstantKind<'tcx>, ) -> Option { use std::cmp::Ordering::*; @@ -772,7 +770,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, - range: PatRange<'tcx>, + range: &PatRange<'tcx>, options: &FxIndexMap, u128>, ) -> Option { for &val in options.keys() { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 9a1e98d3b..b61c4fe50 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -26,19 +26,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, place: &PlaceBuilder<'tcx>, - prefix: &'pat [Pat<'tcx>], - opt_slice: Option<&'pat Pat<'tcx>>, - suffix: &'pat [Pat<'tcx>], + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], ) { let tcx = self.tcx; let (min_length, exact_size) = if let Ok(place_resolved) = - place.clone().try_upvars_resolved(tcx, self.typeck_results) + place.clone().try_upvars_resolved(tcx, &self.upvars) { - match place_resolved - .into_place(tcx, self.typeck_results) - .ty(&self.local_decls, tcx) - .ty - .kind() + match place_resolved.into_place(tcx, &self.upvars).ty(&self.local_decls, tcx).ty.kind() { ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 12b8ceede..25c4e51cb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,15 +1,14 @@ -use crate::build; pub(crate) use crate::build::expr::as_constant::lit_to_mir_constant; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; -use crate::thir::pattern::pat_from_hir; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -18,8 +17,9 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; -use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir}; -use rustc_middle::ty::subst::Subst; +use rustc_middle::thir::{ + self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, +}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -47,9 +47,7 @@ pub(crate) fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - let id = tcx.hir().local_def_id_to_hir_id(def.did); let body_owner_kind = tcx.hir().body_owner_kind(def.did); - let typeck_results = tcx.typeck_opt_const_arg(def); // Ensure unsafeck and abstract const building is ran before we steal the THIR. // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query @@ -66,235 +64,42 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ } } - // Figure out what primary body this item has. - let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { - Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { fn_decl, body, .. }), - .. - }) => (*body, fn_decl.output.span(), None), - Node::Item(hir::Item { - kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id), - span, - .. - }) - | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, body_id), - span, - .. - }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)), - span, - .. - }) => { - // Use the `Span` of the `Item/ImplItem/TraitItem` as the body span, - // since the def span of a function does not include the body - (*body_id, decl.output.span(), Some(*span)) - } - Node::Item(hir::Item { - kind: hir::ItemKind::Static(ty, _, body_id) | hir::ItemKind::Const(ty, body_id), - .. - }) - | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const(ty, Some(body_id)), - .. - }) => (*body_id, ty.span, None), - Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { - (*body, tcx.hir().span(*hir_id), None) - } - - _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), - }; - - // If we don't have a specialized span for the body, just use the - // normal def span. - let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id)); - - tcx.infer_ctxt().enter(|infcx| { - let body = if let Some(error_reported) = typeck_results.tainted_by_errors { - build::construct_error(&infcx, def, id, body_id, body_owner_kind, error_reported) - } else if body_owner_kind.is_fn_or_closure() { - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - let fn_sig = typeck_results.liberated_fn_sigs()[id]; - let fn_def_id = tcx.hir().local_def_id(id); - - let safety = match fn_sig.unsafety { - hir::Unsafety::Normal => Safety::Safe, - hir::Unsafety::Unsafe => Safety::FnUnsafe, - }; - - let body = tcx.hir().body(body_id); - let (thir, expr) = tcx - .thir_body(def) - .unwrap_or_else(|_| (tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0))); + let body = match tcx.thir_body(def) { + Err(error_reported) => construct_error(tcx, def.did, body_owner_kind, error_reported), + Ok((thir, expr)) => { // We ran all queries that depended on THIR at the beginning // of `mir_build`, so now we can steal it let thir = thir.steal(); - let ty = tcx.type_of(fn_def_id); - let mut abi = fn_sig.abi; - let implicit_argument = match ty.kind() { - ty::Closure(..) => { - // HACK(eddyb) Avoid having RustCall on closures, - // as it adds unnecessary (and wrong) auto-tupling. - abi = Abi::Rust; - vec![ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None)] - } - ty::Generator(..) => { - let gen_ty = tcx.typeck_body(body_id).node_type(id); - - // The resume argument may be missing, in that case we need to provide it here. - // It will always be `()` in this case. - if body.params.is_empty() { - vec![ - ArgInfo(gen_ty, None, None, None), - ArgInfo(tcx.mk_unit(), None, None, None), - ] - } else { - vec![ArgInfo(gen_ty, None, None, None)] - } - } - _ => vec![], - }; - - let explicit_arguments = body.params.iter().enumerate().map(|(index, arg)| { - let owner_id = tcx.hir().body_owner(body_id); - let opt_ty_info; - let self_arg; - if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) { - opt_ty_info = fn_decl - .inputs - .get(index) - // Make sure that inferred closure args have no type span - .and_then(|ty| if arg.pat.span != ty.span { Some(ty.span) } else { None }); - self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() { - match fn_decl.implicit_self { - hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm), - hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut), - hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef), - hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef), - _ => None, - } - } else { - None - }; - } else { - opt_ty_info = None; - self_arg = None; - } - - // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` - // (as it's created inside the body itself, not passed in from outside). - let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() { - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(arg.span)); - - tcx.bound_type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()]) - } else { - fn_sig.inputs()[index] - }; - - ArgInfo(ty, opt_ty_info, Some(&arg), self_arg) - }); - let arguments = implicit_argument.into_iter().chain(explicit_arguments); - - let (yield_ty, return_ty) = if body.generator_kind.is_some() { - let gen_ty = tcx.typeck_body(body_id).node_type(id); - let gen_sig = match gen_ty.kind() { - ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(), - _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty), - }; - (Some(gen_sig.yield_ty), gen_sig.return_ty) + if body_owner_kind.is_fn_or_closure() { + construct_fn(tcx, def, &thir, expr) } else { - (None, fn_sig.output()) - }; - - let mut mir = build::construct_fn( - &thir, - &infcx, - def, - id, - arguments, - safety, - abi, - return_ty, - return_ty_span, - body, - expr, - span_with_body, - ); - if yield_ty.is_some() { - mir.generator.as_mut().unwrap().yield_ty = yield_ty; + construct_const(tcx, def, &thir, expr) } - mir - } else { - // Get the revealed type of this const. This is *not* the adjusted - // type of its body, which may be a subtype of this type. For - // example: - // - // fn foo(_: &()) {} - // static X: fn(&'static ()) = foo; - // - // The adjusted type of the body of X is `for<'a> fn(&'a ())` which - // is not the same as the type of X. We need the type of the return - // place to be the type of the constant because NLL typeck will - // equate them. - - let return_ty = typeck_results.node_type(id); - - let (thir, expr) = tcx - .thir_body(def) - .unwrap_or_else(|_| (tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0))); - // We ran all queries that depended on THIR at the beginning - // of `mir_build`, so now we can steal it - let thir = thir.steal(); - - build::construct_const(&thir, &infcx, expr, def, id, return_ty, return_ty_span) - }; + } + }; - lints::check(tcx, &body); - - // The borrow checker will replace all the regions here with its own - // inference variables. There's no point having non-erased regions here. - // The exception is `body.user_type_annotations`, which is used unmodified - // by borrow checking. - debug_assert!( - !(body.local_decls.has_free_regions() - || body.basic_blocks().has_free_regions() - || body.var_debug_info.has_free_regions() - || body.yield_ty().has_free_regions()), - "Unexpected free regions in MIR: {:?}", - body, - ); + lints::check(tcx, &body); + + // The borrow checker will replace all the regions here with its own + // inference variables. There's no point having non-erased regions here. + // The exception is `body.user_type_annotations`, which is used unmodified + // by borrow checking. + debug_assert!( + !(body.local_decls.has_free_regions() + || body.basic_blocks.has_free_regions() + || body.var_debug_info.has_free_regions() + || body.yield_ty().has_free_regions()), + "Unexpected free regions in MIR: {:?}", + body, + ); - body - }) + body } /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -fn liberated_closure_env_ty( - tcx: TyCtxt<'_>, - closure_expr_id: hir::HirId, - body_id: hir::BodyId, -) -> Ty<'_> { - let closure_ty = tcx.typeck_body(body_id).node_type(closure_expr_id); - - let ty::Closure(closure_def_id, closure_substs) = *closure_ty.kind() else { - bug!("closure expr does not have closure type: {:?}", closure_ty); - }; - - let bound_vars = - tcx.mk_bound_variable_kinds(std::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::ReLateBound(ty::INNERMOST, br); - let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); - tcx.erase_late_bound_regions(ty::Binder::bind_with_vars(closure_env_ty, bound_vars)) -} - #[derive(Debug, PartialEq, Eq)] enum BlockFrame { /// Evaluation is currently within a statement. @@ -352,7 +157,7 @@ struct BlockContext(Vec); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'a, 'tcx>, typeck_results: &'tcx TypeckResults<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, @@ -404,12 +209,21 @@ struct Builder<'a, 'tcx> { var_indices: FxHashMap, local_decls: IndexVec>, canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, - upvar_mutbls: Vec, + upvars: CaptureMap<'tcx>, unit_temp: Option>, var_debug_info: Vec>, } +type CaptureMap<'tcx> = SortedIndexMultiMap>; + +#[derive(Debug)] +struct Capture<'tcx> { + captured_place: &'tcx ty::CapturedPlace<'tcx>, + use_place: Place<'tcx>, + mutability: Mutability, +} + impl<'a, 'tcx> Builder<'a, 'tcx> { fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool { self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) @@ -615,149 +429,212 @@ macro_rules! unpack { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'tcx>( - Ty<'tcx>, - Option, - Option<&'tcx hir::Param<'tcx>>, - Option, -); - -fn construct_fn<'tcx, A>( - thir: &Thir<'tcx>, - infcx: &InferCtxt<'_, 'tcx>, +fn construct_fn<'tcx>( + tcx: TyCtxt<'tcx>, fn_def: ty::WithOptConstParam, - fn_id: hir::HirId, - arguments: A, - safety: Safety, - abi: Abi, - return_ty: Ty<'tcx>, - return_ty_span: Span, - body: &'tcx hir::Body<'tcx>, + thir: &Thir<'tcx>, expr: ExprId, - span_with_body: Span, -) -> Body<'tcx> -where - A: Iterator>, -{ - let arguments: Vec<_> = arguments.collect(); - - let tcx = infcx.tcx; - let span = tcx.hir().span(fn_id); - - let mut builder = Builder::new( - thir, - infcx, - fn_def, - fn_id, - span_with_body, - arguments.len(), - safety, - return_ty, - return_ty_span, - body.generator_kind, - ); +) -> Body<'tcx> { + let span = tcx.def_span(fn_def.did); + let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); + let generator_kind = tcx.generator_kind(fn_def.did); - let call_site_scope = - region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite }; - let arg_scope = - region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments }; - let source_info = builder.source_info(span); - let call_site_s = (call_site_scope, source_info); - unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { - let arg_scope_s = (arg_scope, source_info); - // Attribute epilogue to function's closing brace - let fn_end = span_with_body.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { - Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { - builder.args_and_body( - START_BLOCK, - fn_def.did, - &arguments, - arg_scope, - &thir[expr], - ) - })) - })); - let source_info = builder.source_info(fn_end); - builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); - builder.build_drop_trees(); - return_block.unit() - })); + // Figure out what primary body this item has. + let body_id = tcx.hir().body_owned_by(fn_def.did); + let span_with_body = tcx.hir().span_with_body(fn_id); + let return_ty_span = tcx + .hir() + .fn_decl_by_hir_id(fn_id) + .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def.did)) + .output + .span(); + + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + let typeck_results = tcx.typeck_opt_const_arg(fn_def); + let fn_sig = typeck_results.liberated_fn_sigs()[fn_id]; + + let safety = match fn_sig.unsafety { + hir::Unsafety::Normal => Safety::Safe, + hir::Unsafety::Unsafe => Safety::FnUnsafe, + }; + + let mut abi = fn_sig.abi; + if let DefKind::Closure = tcx.def_kind(fn_def.did) { + // HACK(eddyb) Avoid having RustCall on closures, + // as it adds unnecessary (and wrong) auto-tupling. + abi = Abi::Rust; + } + + let arguments = &thir.params; + + let (yield_ty, return_ty) = if generator_kind.is_some() { + let gen_ty = arguments[thir::UPVAR_ENV_PARAM].ty; + let gen_sig = match gen_ty.kind() { + ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(), + _ => { + span_bug!(span, "generator w/o generator type: {:?}", gen_ty) + } + }; + (Some(gen_sig.yield_ty), gen_sig.return_ty) + } else { + (None, fn_sig.output()) + }; + + let mut body = tcx.infer_ctxt().enter(|infcx| { + let mut builder = Builder::new( + thir, + infcx, + fn_def, + fn_id, + span_with_body, + arguments.len(), + safety, + return_ty, + return_ty_span, + generator_kind, + ); + + let call_site_scope = + region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite }; + let arg_scope = + region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments }; + let source_info = builder.source_info(span); + let call_site_s = (call_site_scope, source_info); + unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { + let arg_scope_s = (arg_scope, source_info); + // Attribute epilogue to function's closing brace + let fn_end = span_with_body.shrink_to_hi(); + let return_block = unpack!(builder.in_breakable_scope( + None, + Place::return_place(), + fn_end, + |builder| { + Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { + builder.args_and_body( + START_BLOCK, + fn_def.did, + arguments, + arg_scope, + &thir[expr], + ) + })) + } + )); + let source_info = builder.source_info(fn_end); + builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); + builder.build_drop_trees(); + return_block.unit() + })); + + builder.finish() + }); - let spread_arg = if abi == Abi::RustCall { + body.spread_arg = if abi == Abi::RustCall { // RustCall pseudo-ABI untuples the last argument. Some(Local::new(arguments.len())) } else { None }; - - let mut body = builder.finish(); - body.spread_arg = spread_arg; + if yield_ty.is_some() { + body.generator.as_mut().unwrap().yield_ty = yield_ty; + } body } fn construct_const<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, thir: &'a Thir<'tcx>, - infcx: &'a InferCtxt<'a, 'tcx>, expr: ExprId, - def: ty::WithOptConstParam, - hir_id: hir::HirId, - const_ty: Ty<'tcx>, - const_ty_span: Span, ) -> Body<'tcx> { - let tcx = infcx.tcx; - let span = tcx.hir().span(hir_id); - let mut builder = Builder::new( - thir, - infcx, - def, - hir_id, - span, - 0, - Safety::Safe, - const_ty, - const_ty_span, - None, - ); + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + + // Figure out what primary body this item has. + let (span, const_ty_span) = match tcx.hir().get(hir_id) { + Node::Item(hir::Item { + kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _), + span, + .. + }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(ty, Some(_)), + span, + .. + }) => (*span, ty.span), + Node::AnonConst(_) => { + let span = tcx.def_span(def.did); + (span, span) + } + _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did), + }; + + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + let typeck_results = tcx.typeck_opt_const_arg(def); + let const_ty = typeck_results.node_type(hir_id); + + tcx.infer_ctxt().enter(|infcx| { + let mut builder = Builder::new( + thir, + infcx, + def, + hir_id, + span, + 0, + Safety::Safe, + const_ty, + const_ty_span, + None, + ); - let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); + let mut block = START_BLOCK; + unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); - let source_info = builder.source_info(span); - builder.cfg.terminate(block, source_info, TerminatorKind::Return); + let source_info = builder.source_info(span); + builder.cfg.terminate(block, source_info, TerminatorKind::Return); - builder.build_drop_trees(); + builder.build_drop_trees(); - builder.finish() + builder.finish() + }) } /// Construct MIR for an item that has had errors in type checking. /// /// This is required because we may still want to run MIR passes on an item /// with type errors, but normal MIR construction can't handle that in general. -fn construct_error<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - def: ty::WithOptConstParam, - hir_id: hir::HirId, - body_id: hir::BodyId, +fn construct_error<'tcx>( + tcx: TyCtxt<'tcx>, + def: LocalDefId, body_owner_kind: hir::BodyOwnerKind, err: ErrorGuaranteed, ) -> Body<'tcx> { - let tcx = infcx.tcx; - let span = tcx.hir().span(hir_id); + let span = tcx.def_span(def); + let hir_id = tcx.hir().local_def_id_to_hir_id(def); + let generator_kind = tcx.generator_kind(def); + let ty = tcx.ty_error(); - let generator_kind = tcx.hir().body(body_id).generator_kind; let num_params = match body_owner_kind { - hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len(), + hir::BodyOwnerKind::Fn => tcx.fn_sig(def).inputs().skip_binder().len(), hir::BodyOwnerKind::Closure => { - if generator_kind.is_some() { - // Generators have an implicit `self` parameter *and* a possibly - // implicit resume parameter. - 2 - } else { - // The implicit self parameter adds another local in MIR. - 1 + tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len() + let ty = tcx.type_of(def); + match ty.kind() { + ty::Closure(_, substs) => { + 1 + substs.as_closure().sig().inputs().skip_binder().len() + } + ty::Generator(..) => 2, + _ => bug!("expected closure or generator, found {ty:?}"), } } hir::BodyOwnerKind::Const => 0, @@ -788,7 +665,7 @@ fn construct_error<'a, 'tcx>( cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); let mut body = Body::new( - MirSource::item(def.did.to_def_id()), + MirSource::item(def.to_def_id()), cfg.basic_blocks, source_scopes, local_decls, @@ -806,7 +683,7 @@ fn construct_error<'a, 'tcx>( impl<'a, 'tcx> Builder<'a, 'tcx> { fn new( thir: &'a Thir<'tcx>, - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'a, 'tcx>, def: ty::WithOptConstParam, hir_id: hir::HirId, span: Span, @@ -855,7 +732,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { in_scope_unsafe: safety, local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), canonical_user_type_annotations: IndexVec::new(), - upvar_mutbls: vec![], + upvars: CaptureMap::new(), var_indices: Default::default(), unit_temp: None, var_debug_info: vec![], @@ -896,20 +773,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, fn_def_id: LocalDefId, - arguments: &[ArgInfo<'tcx>], + arguments: &IndexVec>, argument_scope: region::Scope, expr: &Expr<'tcx>, ) -> BlockAnd<()> { // Allocate locals for the function arguments - for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { + for param in arguments.iter() { let source_info = - SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span)); - let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info)); + SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span)); + let arg_local = + self.local_decls.push(LocalDecl::with_source_info(param.ty, source_info)); // If this is a simple binding pattern, give debuginfo a nice name. - if let Some(arg) = arg_opt && let Some(ident) = arg.pat.simple_ident() { + if let Some(ref pat) = param.pat && let Some(name) = pat.simple_ident() { self.var_debug_info.push(VarDebugInfo { - name: ident.name, + name, source_info, value: VarDebugInfoContents::Place(arg_local.into()), }); @@ -924,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // indexed closure and we stored in a map called closure_min_captures in TypeckResults // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar - // debuginfo and to fill `self.upvar_mutbls`. + // debuginfo and to fill `self.upvars`. if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; @@ -944,7 +822,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .closure_min_captures_flattened(fn_def_id) .zip(capture_tys.zip(capture_syms)); - self.upvar_mutbls = captures_with_tys + self.upvars = captures_with_tys .enumerate() .map(|(i, (captured_place, (ty, sym)))| { let capture = captured_place.info.capture_kind; @@ -964,48 +842,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }; + let use_place = Place { + local: ty::CAPTURE_STRUCT_LOCAL, + projection: tcx.intern_place_elems(&projs), + }; self.var_debug_info.push(VarDebugInfo { name: *sym, source_info: SourceInfo::outermost(tcx_hir.span(var_id)), - value: VarDebugInfoContents::Place(Place { - local: ty::CAPTURE_STRUCT_LOCAL, - projection: tcx.intern_place_elems(&projs), - }), + value: VarDebugInfoContents::Place(use_place), }); - mutability + let capture = Capture { captured_place, use_place, mutability }; + (var_id, capture) }) .collect(); } let mut scope = None; // Bind the argument patterns - for (index, arg_info) in arguments.iter().enumerate() { + for (index, param) in arguments.iter().enumerate() { // Function arguments always get the first Local indices after the return place let local = Local::new(index + 1); let place = Place::from(local); - let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info; // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( - arg_opt.as_ref().map_or(expr.span, |arg| arg.pat.span), + param.pat.as_ref().map_or(expr.span, |pat| pat.span), argument_scope, local, DropKind::Value, ); - let Some(arg) = arg_opt else { + let Some(ref pat) = param.pat else { continue; }; - let pat = match tcx.hir().get(arg.pat.hir_id) { - Node::Pat(pat) => pat, - node => bug!("pattern became {:?}", node), - }; - let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat); let original_source_scope = self.source_scope; - let span = pattern.span; - self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); - match *pattern.kind { + let span = pat.span; + if let Some(arg_hir_id) = param.hir_id { + self.set_correct_source_scope_for_arg(arg_hir_id, original_source_scope, span); + } + match pat.kind { // Don't introduce extra copies for simple bindings PatKind::Binding { mutability, @@ -1016,17 +892,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; - self.local_decls[local].local_info = if let Some(kind) = self_binding { + self.local_decls[local].local_info = if let Some(kind) = param.self_kind { Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( - BindingForm::ImplicitSelf(*kind), + BindingForm::ImplicitSelf(kind), )))) } else { let binding_mode = ty::BindingMode::BindByValue(mutability); Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { binding_mode, - opt_ty_info, - opt_match_place: Some((Some(place), span)), + opt_ty_info: param.ty_span, + opt_match_place: Some((None, span)), pat_span: span, }, ))))) @@ -1037,12 +913,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scope = self.declare_bindings( scope, expr.span, - &pattern, + &pat, matches::ArmHasGuard(false), Some((Some(&place), span)), ); let place_builder = PlaceBuilder::from(local); - unpack!(block = self.place_into_pattern(block, pattern, place_builder, false)); + unpack!(block = self.place_into_pattern(block, &pat, place_builder, false)); } } self.source_scope = original_source_scope; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b2fd9f25b..ff66ca595 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -466,9 +466,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); - let break_block = self.build_exit_tree(breakable_scope.break_drops, None); + let break_block = + self.build_exit_tree(breakable_scope.break_drops, region_scope, span, None); if let Some(drops) = breakable_scope.continue_drops { - self.build_exit_tree(drops, loop_block); + self.build_exit_tree(drops, region_scope, span, loop_block); } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, @@ -510,6 +511,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn in_if_then_scope( &mut self, region_scope: region::Scope, + span: Span, f: F, ) -> (BasicBlock, BasicBlock) where @@ -524,7 +526,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(if_then_scope.region_scope == region_scope); let else_block = self - .build_exit_tree(if_then_scope.else_drops, None) + .build_exit_tree(if_then_scope.else_drops, region_scope, span, None) .map_or_else(|| self.cfg.start_new_block(), |else_block_and| unpack!(else_block_and)); (then_block, else_block) @@ -997,10 +999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns the [DropIdx] for the innermost drop if the function unwound at /// this point. The `DropIdx` will be created if it doesn't already exist. fn diverge_cleanup(&mut self) -> DropIdx { - let is_generator = self.generator_kind.is_some(); - let (uncached_scope, mut cached_drop) = self - .scopes - .scopes + // It is okay to use dummy span because the getting scope index on the topmost scope + // must always succeed. + self.diverge_cleanup_target(self.scopes.topmost(), DUMMY_SP) + } + + /// This is similar to [diverge_cleanup](Self::diverge_cleanup) except its target is set to + /// some ancestor scope instead of the current scope. + /// It is possible to unwind to some ancestor scope if some drop panics as + /// the program breaks out of a if-then scope. + fn diverge_cleanup_target(&mut self, target_scope: region::Scope, span: Span) -> DropIdx { + let target = self.scopes.scope_index(target_scope, span); + let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] .iter() .enumerate() .rev() @@ -1009,7 +1019,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .unwrap_or((0, ROOT_NODE)); - for scope in &mut self.scopes.scopes[uncached_scope..] { + if uncached_scope > target { + return cached_drop; + } + + let is_generator = self.generator_kind.is_some(); + for scope in &mut self.scopes.scopes[uncached_scope..=target] { for drop in &scope.drops { if is_generator || drop.kind == DropKind::Value { cached_drop = self.scopes.unwind_drops.add_drop(*drop, cached_drop); @@ -1222,21 +1237,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { fn build_exit_tree( &mut self, mut drops: DropTree, + else_scope: region::Scope, + span: Span, continue_block: Option, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); blocks[ROOT_NODE] = continue_block; drops.build_mir::(&mut self.cfg, &mut blocks); + let is_generator = self.generator_kind.is_some(); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = self.diverge_cleanup(); + let unwind_target = self.diverge_cleanup_target(else_scope, span); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { DropKind::Storage => { - if self.generator_kind.is_some() { + if is_generator { let unwind_drop = self .scopes .unwind_drops diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 864caf0ba..495738ebe 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -75,10 +75,11 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { match self.safety_context { SafetyContext::BuiltinUnsafeBlock => {} SafetyContext::UnsafeBlock { ref mut used, .. } => { - if !self.body_unsafety.is_unsafe() || !unsafe_op_in_unsafe_fn_allowed { - // Mark this block as useful - *used = true; - } + // Mark this block as useful (even inside `unsafe fn`, where it is technically + // redundant -- but we want to eventually enable `unsafe_op_in_unsafe_fn` by + // default which will require those blocks: + // https://github.com/rust-lang/rust/issues/71668#issuecomment-1203075594). + *used = true; } SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { @@ -213,7 +214,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &Pat<'tcx>) { if self.in_union_destructure { - match *pat.kind { + match pat.kind { // binding to a variable allows getting stuff out of variable PatKind::Binding { .. } // match is conditional on having this value @@ -235,7 +236,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } }; - match &*pat.kind { + match &pat.kind { PatKind::Leaf { .. } => { if let ty::Adt(adt_def, ..) = pat.ty.kind() { if adt_def.is_union() { @@ -390,7 +391,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ExprKind::InlineAsm { .. } => { self.requires_unsafe(expr.span, UseOfInlineAssembly); } - ExprKind::Adt(box Adt { + ExprKind::Adt(box AdtExpr { adt_def, variant_index: _, substs: _, @@ -401,13 +402,13 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { (Bound::Unbounded, Bound::Unbounded) => {} _ => self.requires_unsafe(expr.span, InitializingTypeWith), }, - ExprKind::Closure { + ExprKind::Closure(box ClosureExpr { closure_id, substs: _, upvars: _, movability: _, fake_reads: _, - } => { + }) => { let closure_def = if let Some((did, const_param_id)) = ty::WithOptConstParam::try_lookup(closure_id, self.tcx) { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 11cd2a9aa..0c0a2fe9c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -6,7 +6,7 @@ #![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a7e4403a2..f626571b5 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -44,7 +44,7 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + (ast::LitKind::Err, _) => return Err(LitToConstError::Reported), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index dccaa61ed..321353ca2 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -9,13 +9,13 @@ use rustc_index::vec::Idx; use rustc_middle::ty::CanonicalUserTypeAnnotation; impl<'tcx> Cx<'tcx> { - pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { + pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId { // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts); let opt_destruction_scope = self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id); - Block { + let block = Block { targeted_by_break: block.targeted_by_break, region_scope: region::Scope { id: block.hir_id.local_id, @@ -34,7 +34,9 @@ impl<'tcx> Cx<'tcx> { BlockSafety::ExplicitUnsafe(block.hir_id) } }, - } + }; + + self.thir.blocks.push(block) } fn mirror_stmts( @@ -85,21 +87,21 @@ impl<'tcx> Cx<'tcx> { { debug!("mirror_stmts: user_ty={:?}", user_ty); let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span: ty.span, inferred_ty: self.typeck_results.node_type(ty.hir_id), }; - pattern = Pat { + pattern = Box::new(Pat { ty: pattern.ty, span: pattern.span, - kind: Box::new(PatKind::AscribeUserType { + kind: PatKind::AscribeUserType { ascription: Ascription { annotation, variance: ty::Variance::Covariant, }, subpattern: pattern, - }), - }; + }, + }); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 985601712..d059877f8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -108,8 +108,8 @@ impl<'tcx> Cx<'tcx> { // // ^ error message points at this expression. // } let mut adjust_span = |expr: &mut Expr<'tcx>| { - if let ExprKind::Block { body } = &expr.kind { - if let Some(last_expr) = body.expr { + if let ExprKind::Block { block } = expr.kind { + if let Some(last_expr) = self.thir[block].expr { span = self.thir[last_expr].span; expr.span = span; } @@ -261,15 +261,19 @@ impl<'tcx> Cx<'tcx> { let kind = match expr.kind { // Here comes the interesting stuff: - hir::ExprKind::MethodCall(segment, ref args, fn_span) => { + hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = self.method_callee(expr, segment.ident.span, None); // When we apply adjustments to the receiver, use the span of // the overall method call for better diagnostics. args[0] // is guaranteed to exist, since a method call always has a receiver. - let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); - tracing::info!("Using method span: {:?}", expr.span); - let args = self.mirror_exprs(args); + let old_adjustment_span = + self.adjustment_span.replace((receiver.hir_id, expr_span)); + info!("Using method span: {:?}", expr.span); + let args = std::iter::once(receiver) + .chain(args.iter()) + .map(|expr| self.mirror_expr(expr)) + .collect(); self.adjustment_span = old_adjustment_span; ExprKind::Call { ty: expr.ty, @@ -329,7 +333,7 @@ impl<'tcx> Cx<'tcx> { if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { *did = adt_def.did(); } - u_ty + Box::new(u_ty) }); debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); @@ -341,7 +345,7 @@ impl<'tcx> Cx<'tcx> { expr: self.mirror_expr(e), }) .collect(); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def, substs, variant_index: index, @@ -369,7 +373,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) } } - hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) }, + hir::ExprKind::Block(ref blk, _) => ExprKind::Block { block: self.mirror_block(blk) }, hir::ExprKind::Assign(ref lhs, ref rhs, _) => { ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) } @@ -464,9 +468,9 @@ impl<'tcx> Cx<'tcx> { ty::Adt(adt, substs) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { let user_provided_types = self.typeck_results().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).copied(); + let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt, variant_index: VariantIdx::new(0), substs, @@ -490,9 +494,10 @@ impl<'tcx> Cx<'tcx> { let index = adt.variant_index_with_id(variant_id); let user_provided_types = self.typeck_results().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).copied(); + let user_ty = + user_provided_types.get(expr.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt, variant_index: index, substs, @@ -547,7 +552,13 @@ impl<'tcx> Cx<'tcx> { None => Vec::new(), }; - ExprKind::Closure { closure_id: def_id, substs, upvars, movability, fake_reads } + ExprKind::Closure(Box::new(ClosureExpr { + closure_id: def_id, + substs, + upvars, + movability, + fake_reads, + })) } hir::ExprKind::Path(ref qpath) => { @@ -555,7 +566,7 @@ impl<'tcx> Cx<'tcx> { self.convert_path_expr(expr, res) } - hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm { + hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr { template: asm.template, operands: asm .operands @@ -614,7 +625,7 @@ impl<'tcx> Cx<'tcx> { .collect(), options: asm.options, line_spans: asm.line_spans, - }, + })), hir::ExprKind::ConstBlock(ref anon_const) => { let ty = self.typeck_results().node_type(anon_const.hir_id); @@ -679,8 +690,8 @@ impl<'tcx> Cx<'tcx> { let body = self.thir.exprs.push(Expr { ty: block_ty, temp_lifetime, - span: block.span, - kind: ExprKind::Block { body: block }, + span: self.thir[block].span, + kind: ExprKind::Block { block }, }); ExprKind::Loop { body } } @@ -712,14 +723,17 @@ impl<'tcx> Cx<'tcx> { }); debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty); - ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) } + ExprKind::ValueTypeAscription { + source: cast_expr, + user_ty: Some(Box::new(*user_ty)), + } } else { cast } } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_types = self.typeck_results.user_provided_types(); - let user_ty = user_provided_types.get(ty.hir_id).copied(); + let user_ty = user_provided_types.get(ty.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); let mirrored = self.mirror_expr(source); if source.is_syntactic_place_expr() { @@ -748,7 +762,7 @@ impl<'tcx> Cx<'tcx> { &mut self, hir_id: hir::HirId, res: Res, - ) -> Option> { + ) -> Option>> { debug!("user_substs_applied_to_res: res={:?}", res); let user_provided_type = match res { // A reference to something callable -- e.g., a fn, method, or @@ -759,7 +773,7 @@ impl<'tcx> Cx<'tcx> { | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { - self.typeck_results().user_provided_types().get(hir_id).copied() + self.typeck_results().user_provided_types().get(hir_id).copied().map(Box::new) } // A unit struct/variant which is used as a value (e.g., @@ -767,11 +781,11 @@ impl<'tcx> Cx<'tcx> { // this variant -- but with the substitutions given by the // user. Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => { - self.user_substs_applied_to_ty_of_hir_id(hir_id) + self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new) } // `Self` is used in expression as a tuple struct constructor or a unit struct constructor - Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id), + Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new), _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id), }; @@ -846,22 +860,22 @@ impl<'tcx> Cx<'tcx> { Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); - ExprKind::NamedConst { def_id, substs, user_ty: user_ty } + ExprKind::NamedConst { def_id, substs, user_ty } } Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { let user_provided_types = self.typeck_results.user_provided_types(); - let user_provided_type = user_provided_types.get(expr.hir_id).copied(); - debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); + let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new); + debug!("convert_path_expr: user_ty={:?}", user_ty); let ty = self.typeck_results().node_type(expr.hir_id); match ty.kind() { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. - ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt { + ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt_def, variant_index: adt_def.variant_index_with_ctor_id(def_id), substs, - user_ty: user_provided_type, + user_ty, fields: Box::new([]), base: None, })), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index f7351a4ca..3ef1b263f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -8,12 +8,14 @@ use crate::thir::util::UserAnnotatedTyHelpers; use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::lang_items::LangItem; use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::thir::*; -use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, Subst, TyCtxt}; use rustc_span::Span; pub(crate) fn thir_body<'tcx>( @@ -27,6 +29,26 @@ pub(crate) fn thir_body<'tcx>( return Err(reported); } let expr = cx.mirror_expr(&body.value); + + let owner_id = hir.local_def_id_to_hir_id(owner_def.did); + if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) { + let closure_env_param = cx.closure_env_param(owner_def.did, owner_id); + let explicit_params = cx.explicit_params(owner_id, fn_decl, body); + cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect(); + + // The resume argument may be missing, in that case we need to provide it here. + // It will always be `()` in this case. + if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() { + cx.thir.params.push(Param { + ty: tcx.mk_unit(), + pat: None, + ty_span: None, + self_kind: None, + hir_id: None, + }); + } + } + Ok((tcx.alloc_steal_thir(cx.thir), expr)) } @@ -44,11 +66,11 @@ struct Cx<'tcx> { tcx: TyCtxt<'tcx>, thir: Thir<'tcx>, - pub(crate) param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, - pub(crate) region_scope_tree: &'tcx region::ScopeTree, - pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>, - pub(crate) rvalue_scopes: &'tcx RvalueScopes, + region_scope_tree: &'tcx region::ScopeTree, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + rvalue_scopes: &'tcx RvalueScopes, /// When applying adjustments to the expression /// with the given `HirId`, use the given `Span`, @@ -77,14 +99,94 @@ impl<'tcx> Cx<'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { + #[instrument(level = "debug", skip(self))] + fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box> { let p = match self.tcx.hir().get(p.hir_id) { Node::Pat(p) => p, node => bug!("pattern became {:?}", node), }; pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) } + + fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option> { + match self.tcx.def_kind(owner_def) { + DefKind::Closure => { + let closure_ty = self.typeck_results.node_type(owner_id); + + let ty::Closure(closure_def_id, closure_substs) = *closure_ty.kind() else { + bug!("closure expr does not have closure type: {:?}", closure_ty); + }; + + let bound_vars = self.tcx.mk_bound_variable_kinds(std::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::ReLateBound(ty::INNERMOST, br); + let closure_env_ty = + self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); + let liberated_closure_env_ty = self.tcx.erase_late_bound_regions( + ty::Binder::bind_with_vars(closure_env_ty, bound_vars), + ); + let env_param = Param { + ty: liberated_closure_env_ty, + pat: None, + ty_span: None, + self_kind: None, + hir_id: None, + }; + + Some(env_param) + } + DefKind::Generator => { + let gen_ty = self.typeck_results.node_type(owner_id); + let gen_param = + Param { ty: gen_ty, pat: None, ty_span: None, self_kind: None, hir_id: None }; + Some(gen_param) + } + _ => None, + } + } + + fn explicit_params<'a>( + &'a mut self, + owner_id: HirId, + fn_decl: &'tcx hir::FnDecl<'tcx>, + body: &'tcx hir::Body<'tcx>, + ) -> impl Iterator> + 'a { + let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; + + body.params.iter().enumerate().map(move |(index, param)| { + let ty_span = fn_decl + .inputs + .get(index) + // Make sure that inferred closure args have no type span + .and_then(|ty| if param.pat.span != ty.span { Some(ty.span) } else { None }); + + let self_kind = if index == 0 && fn_decl.implicit_self.has_implicit_self() { + Some(fn_decl.implicit_self) + } else { + None + }; + + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { + let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); + + self.tcx + .bound_type_of(va_list_did) + .subst(self.tcx, &[self.tcx.lifetimes.re_erased.into()]) + } else { + fn_sig.inputs()[index] + }; + + let pat = self.pattern_from_hir(param.pat); + Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) } + }) + } } impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 063c07647..d45b88690 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -491,8 +491,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { err.span_suggestion_verbose( semi_span.shrink_to_lo(), &format!( - "alternatively, on nightly, you might want to use \ - `#![feature(let_else)]` to handle the variant{} that {} matched", + "alternatively, you might want to use \ + let else to handle the variant{} that {} matched", pluralize!(witnesses.len()), match witnesses.len() { 1 => "isn't", @@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>( )); } [.., prev, last] if prev.span.eq_ctxt(last.span) => { - if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) { - let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) - && last.span.eq_ctxt(last.body.span) - { - "" - } else { - "," - }; + let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) + && last.span.eq_ctxt(last.body.span) + { + "" + } else { + "," + }; + let spacing = if sm.is_multiline(prev.span.between(last.span)) { + sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) + } else { + Some(" ".to_string()) + }; + if let Some(spacing) = spacing { suggestion = Some(( last.span.shrink_to_hi(), - format!( - "{}{}{} => todo!()", - comma, - snippet.strip_prefix(',').unwrap_or(&snippet), - pattern - ), + format!("{}{}{} => todo!()", comma, spacing, pattern), )); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d6dd0f017..b58685e89 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -19,21 +19,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(super) fn const_to_pat( &self, cv: mir::ConstantKind<'tcx>, id: hir::HirId, span: Span, mir_structural_match_violation: bool, - ) -> Pat<'tcx> { - let pat = self.tcx.infer_ctxt().enter(|infcx| { + ) -> Box> { + self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) - }); - - debug!(?pat); - pat + }) } } @@ -159,7 +156,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { &mut self, cv: mir::ConstantKind<'tcx>, mir_structural_match_violation: bool, - ) -> Pat<'tcx> { + ) -> Box> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -168,7 +165,14 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); + let inlined_const_as_pat = + self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| { + Box::new(Pat { + span: self.span, + ty: cv.ty(), + kind: PatKind::Constant { value: cv }, + }) + }); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, @@ -269,7 +273,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { &self, cv: mir::ConstantKind<'tcx>, mir_structural_match_violation: bool, - ) -> Result, FallbackToConstRef> { + ) -> Result>, FallbackToConstRef> { let id = self.id; let span = self.span; let tcx = self.tcx(); @@ -396,7 +400,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: Vec::new(), + suffix: Box::new([]), }, ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // These are not allowed and will error elsewhere anyway. @@ -423,8 +427,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let old = self.behind_reference.replace(true); let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { - subpattern: Pat { - kind: Box::new(PatKind::Array { + subpattern: Box::new(Pat { + kind: PatKind::Array { prefix: tcx .destructure_mir_constant(param_env, array) .fields @@ -432,11 +436,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: vec![], - }), + suffix: Box::new([]), + }, span, ty: *pointee_ty, - }, + }), }; self.behind_reference.set(old); val @@ -449,8 +453,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let old = self.behind_reference.replace(true); let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { - subpattern: Pat { - kind: Box::new(PatKind::Slice { + subpattern: Box::new(Pat { + kind: PatKind::Slice { prefix: tcx .destructure_mir_constant(param_env, array) .fields @@ -458,11 +462,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: vec![], - }), + suffix: Box::new([]), + }, span, ty: tcx.mk_slice(elem_ty), - }, + }), }; self.behind_reference.set(old); val @@ -596,6 +600,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); } - Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) }) + Ok(Box::new(Pat { span, ty: cv.ty(), kind })) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 8d6f8efb6..5105f059f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -71,9 +71,9 @@ use std::ops::RangeInclusive; /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { - for pat in pats { - expand(pat, vec); + if let PatKind::Or { pats } = &pat.kind { + for pat in pats.iter() { + expand(&pat, vec); } } else { vec.push(pat) @@ -252,10 +252,14 @@ impl IntRange { let kind = if lo == hi { PatKind::Constant { value: lo_const } } else { - PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) + PatKind::Range(Box::new(PatRange { + lo: lo_const, + hi: hi_const, + end: RangeEnd::Included, + })) }; - Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } + Pat { ty, span: DUMMY_SP, kind } } /// Lint on likely incorrect range patterns (#63987) @@ -1297,7 +1301,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); let ctor; let fields; - match pat.kind.as_ref() { + match &pat.kind { PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { @@ -1342,9 +1346,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { fields = Fields::singleton(cx, pat); } ty::Adt(adt, _) => { - ctor = match pat.kind.as_ref() { + ctor = match pat.kind { PatKind::Leaf { .. } => Single, - PatKind::Variant { variant_index, .. } => Variant(*variant_index), + PatKind::Variant { variant_index, .. } => Variant(variant_index), _ => bug!(), }; let variant = &adt.variant(ctor.variant_index_for_adt(*adt)); @@ -1402,7 +1406,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } } - &PatKind::Range(PatRange { lo, hi, end }) => { + &PatKind::Range(box PatRange { lo, hi, end }) => { let ty = lo.ty(); ctor = if let Some(int_range) = IntRange::from_range( cx.tcx, @@ -1429,7 +1433,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { FixedLen(prefix.len() + suffix.len()) }; ctor = Slice(Slice::new(array_len, kind)); - fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat)); + fields = + Fields::from_iter(cx, prefix.iter().chain(suffix.iter()).map(|p| mkpat(&*p))); } PatKind::Or { .. } => { ctor = Or; @@ -1442,15 +1447,15 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> { let is_wildcard = |pat: &Pat<'_>| { - matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) + matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) }; - let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx)); - let pat = match &self.ctor { + let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx))); + let kind = match &self.ctor { Single | Variant(_) => match self.ty.kind() { ty::Tuple(..) => PatKind::Leaf { subpatterns: subpatterns .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern }) .collect(), }, ty::Adt(adt_def, _) if adt_def.is_box() => { @@ -1485,7 +1490,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { FixedLen(_) => PatKind::Slice { prefix: subpatterns.collect(), slice: None, - suffix: vec![], + suffix: Box::new([]), }, VarLen(prefix, _) => { let mut subpatterns = subpatterns.peekable(); @@ -1504,14 +1509,18 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { subpatterns.next(); } } - let suffix: Vec<_> = subpatterns.collect(); + let suffix: Box<[_]> = subpatterns.collect(); let wild = Pat::wildcard_from_ty(self.ty); - PatKind::Slice { prefix, slice: Some(wild), suffix } + PatKind::Slice { + prefix: prefix.into_boxed_slice(), + slice: Some(Box::new(wild)), + suffix, + } } } } &Str(value) => PatKind::Constant { value }, - &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), + &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })), IntRange(range) => return range.to_pat(cx.tcx, self.ty), Wildcard | NonExhaustive => PatKind::Wild, Missing { .. } => bug!( @@ -1523,7 +1532,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } }; - Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) } + Pat { ty: self.ty, span: DUMMY_SP, kind } } pub(super) fn is_or_pat(&self) -> bool { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a13748a2d..0edf6a983 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -29,27 +29,27 @@ use rustc_span::{Span, Symbol}; use std::cmp::Ordering; #[derive(Clone, Debug)] -pub(crate) enum PatternError { +enum PatternError { AssocConstInPattern(Span), ConstParamInPattern(Span), StaticInPattern(Span), NonConstPath(Span), } -pub(crate) struct PatCtxt<'a, 'tcx> { - pub(crate) tcx: TyCtxt<'tcx>, - pub(crate) param_env: ty::ParamEnv<'tcx>, - pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>, - pub(crate) errors: Vec, +struct PatCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + errors: Vec, include_lint_checks: bool, } -pub(crate) fn pat_from_hir<'a, 'tcx>( +pub(super) fn pat_from_hir<'a, 'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, -) -> Pat<'tcx> { +) -> Box> { let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { @@ -61,7 +61,7 @@ pub(crate) fn pat_from_hir<'a, 'tcx>( } impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - pub(crate) fn new( + fn new( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -69,12 +69,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false } } - pub(crate) fn include_lint_checks(&mut self) -> &mut Self { + fn include_lint_checks(&mut self) -> &mut Self { self.include_lint_checks = true; self } - pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { + fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: // @@ -97,13 +97,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let unadjusted_pat = self.lower_pattern_unadjusted(pat); self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( unadjusted_pat, - |pat, ref_ty| { + |pat: Box<_>, ref_ty| { debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); - Pat { + Box::new(Pat { span: pat.span, ty: *ref_ty, - kind: Box::new(PatKind::Deref { subpattern: pat }), - } + kind: PatKind::Deref { subpattern: pat }, + }) }, ) } @@ -113,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> (PatKind<'tcx>, Option>) { match self.lower_lit(expr) { - PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => { + PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { (kind, Some(ascription)) } kind => (kind, None), @@ -134,7 +134,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. - (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Excluded, Some(Ordering::Less)) => { + PatKind::Range(Box::new(PatRange { lo, hi, end })) + } // `x..y` where `x >= y`. The range is empty => error. (RangeEnd::Excluded, _) => { struct_span_err!( @@ -149,7 +151,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // `x..=y` where `x == y`. (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, // `x..=y` where `x < y`. - (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Included, Some(Ordering::Less)) => { + PatKind::Range(Box::new(PatRange { lo, hi, end })) + } // `x..=y` where `x > y` hence the range is empty => error. (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -196,8 +200,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } - fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { + fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { let mut ty = self.typeck_results.node_type(pat.hir_id); + let mut span = pat.span; let kind = match pat.kind { hir::PatKind::Wild => PatKind::Wild, @@ -228,7 +233,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // constants somewhere. Have them on the range pattern. for end in &[lo, hi] { if let Some((_, Some(ascription))) = end { - let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) }; + let subpattern = Box::new(Pat { span: pat.span, ty, kind }); kind = PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; } @@ -258,6 +263,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Binding(_, id, ident, ref sub) => { + if let Some(ident_span) = ident.span.find_ancestor_inside(span) { + span = span.with_hi(ident_span.hi()); + } + let bm = *self .typeck_results .pat_binding_modes() @@ -322,14 +331,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, }; - Pat { span: pat.span, ty, kind: Box::new(kind) } + Box::new(Pat { span, ty, kind }) } fn lower_tuple_subpats( &mut self, pats: &'tcx [hir::Pat<'tcx>], expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> Vec> { pats.iter() .enumerate_and_adjust(expected_len, gap_pos) @@ -340,11 +349,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .collect() } - fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec> { + fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box>]> { pats.iter().map(|p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option> { + fn lower_opt_pattern( + &mut self, + pat: &'tcx Option<&'tcx hir::Pat<'tcx>>, + ) -> Option>> { pat.as_ref().map(|p| self.lower_pattern(p)) } @@ -436,12 +448,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results.node_type(hir_id), }; kind = PatKind::AscribeUserType { - subpattern: Pat { span, ty, kind: Box::new(kind) }, + subpattern: Box::new(Pat { span, ty, kind }), ascription: Ascription { annotation, variance: ty::Variance::Covariant }, }; } @@ -453,11 +465,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// it to `const_to_pat`. Any other path (like enum variants without fields) /// is converted to the corresponding pattern via `lower_variant_or_leaf`. #[instrument(skip(self), level = "debug")] - fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> { + fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box> { let ty = self.typeck_results.node_type(id); let res = self.typeck_results.qpath_res(qpath, id); - let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) }; + let pat_from_kind = |kind| Box::new(Pat { span, ty, kind }); let (def_id, is_associated_const) = match res { Res::Def(DefKind::Const, def_id) => (def_id, false), @@ -469,7 +481,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Use `Reveal::All` here because patterns are always monomorphic even if their function // isn't. let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); - let substs = self.typeck_results.node_substs(id); + // N.B. There is no guarantee that substs collected in typeck results are fully normalized, + // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE + // if given unnormalized types. + let substs = self + .tcx + .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_substs(id)); let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) { Ok(Some(i)) => i, Ok(None) => { @@ -505,13 +522,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let user_provided_types = self.typeck_results().user_provided_types(); if let Some(&user_ty) = user_provided_types.get(id) { let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results().node_type(id), }; - Pat { + Box::new(Pat { span, - kind: Box::new(PatKind::AscribeUserType { + kind: PatKind::AscribeUserType { subpattern: pattern, ascription: Ascription { annotation, @@ -519,9 +536,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// `variance` field documentation for details. variance: ty::Variance::Contravariant, }, - }), + }, ty: const_.ty(), - } + }) } else { pattern } @@ -553,23 +570,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let value = value.eval(self.tcx, self.param_env); match value { - mir::ConstantKind::Ty(c) => { - match c.kind() { - ConstKind::Param(_) => { - self.errors.push(PatternError::ConstParamInPattern(span)); - return PatKind::Wild; - } - ConstKind::Unevaluated(_) => { - // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx - .sess - .span_err(span, "constant pattern depends on a generic parameter"); - return PatKind::Wild; - } - _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"), + mir::ConstantKind::Ty(c) => match c.kind() { + ConstKind::Param(_) => { + self.errors.push(PatternError::ConstParamInPattern(span)); + return PatKind::Wild; } + _ => bug!("Expected ConstKind::Param"), + }, + mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, + mir::ConstantKind::Unevaluated(..) => { + // If we land here it means the const can't be evaluated because it's `TooGeneric`. + self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter"); + return PatKind::Wild; } - mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind, } } @@ -580,7 +593,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { let (lit, neg) = match expr.kind { hir::ExprKind::Path(ref qpath) => { - return *self.lower_path(qpath, expr.hir_id, expr.span).kind; + return self.lower_path(qpath, expr.hir_id, expr.span).kind; } hir::ExprKind::ConstBlock(ref anon_const) => { return self.lower_inline_const(anon_const, expr.hir_id, expr.span); @@ -598,7 +611,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) { - Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, + Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, Err(LitToConstError::Reported) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } @@ -615,7 +628,7 @@ impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { } } -pub(crate) trait PatternFoldable<'tcx>: Sized { +trait PatternFoldable<'tcx>: Sized { fn fold_with>(&self, folder: &mut F) -> Self { self.super_fold_with(folder) } @@ -623,7 +636,7 @@ pub(crate) trait PatternFoldable<'tcx>: Sized { fn super_fold_with>(&self, folder: &mut F) -> Self; } -pub(crate) trait PatternFolder<'tcx>: Sized { +trait PatternFolder<'tcx>: Sized { fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { pattern.super_fold_with(self) } @@ -646,6 +659,12 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { } } +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { fn super_fold_with>(&self, folder: &mut F) -> Self { self.as_ref().map(|t| t.fold_with(folder)) @@ -732,7 +751,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { PatKind::Deref { subpattern: subpattern.fold_with(folder) } } PatKind::Constant { value } => PatKind::Constant { value }, - PatKind::Range(range) => PatKind::Range(range), + PatKind::Range(ref range) => PatKind::Range(range.clone()), PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { prefix: prefix.fold_with(folder), slice: slice.fold_with(folder), diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 0a660ef30..115d34ff8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. #[derive(Clone)] -struct PatStack<'p, 'tcx> { - pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, +pub(crate) struct PatStack<'p, 'tcx> { + pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, } impl<'p, 'tcx> PatStack<'p, 'tcx> { @@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { }) } + // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix. + fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) { + if !self.is_empty() && self.head().is_or_pat() { + for pat in self.head().iter_fields() { + let mut new_patstack = PatStack::from_pattern(pat); + new_patstack.pats.extend_from_slice(&self.pats[1..]); + if !new_patstack.is_empty() && new_patstack.head().is_or_pat() { + new_patstack.expand_and_extend(matrix); + } else if !new_patstack.is_empty() { + matrix.push(new_patstack); + } + } + } + } + /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. /// /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing @@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { /// A 2D matrix. #[derive(Clone)] pub(super) struct Matrix<'p, 'tcx> { - patterns: Vec>, + pub patterns: Vec>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { @@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { - self.patterns.extend(row.expand_or_pat()); + row.expand_and_extend(self); } else { self.patterns.push(row); } @@ -739,8 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( hir_id: HirId, witnesses: Vec>, ) { - let joined_patterns = joined_uncovered_patterns(cx, &witnesses); cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| { + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); let mut lint = build.build("some variants are not matched explicitly"); lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); lint.help( @@ -776,7 +791,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( /// `is_under_guard` is used to inform if the pattern has a guard. If it /// has one it must not be inserted into the matrix. This shouldn't be /// relied on for soundness. -#[instrument(level = "debug", skip(cx, matrix, hir_id))] +#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)] fn is_useful<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, @@ -902,7 +917,6 @@ fn is_useful<'p, 'tcx>( v.head().set_reachable(); } - debug!(?ret); ret } diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index baf9735fb..385e9ba74 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -13,10 +13,13 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs new file mode 100644 index 000000000..cc1425787 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/errors.rs @@ -0,0 +1,71 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::path_must_end_in_filename)] +pub(crate) struct PathMustEndInFilename { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::unknown_formatter)] +pub(crate) struct UnknownFormatter { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::duplicate_values_for)] +pub(crate) struct DuplicateValuesFor { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::requires_an_argument)] +pub(crate) struct RequiresAnArgument { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)] +pub(crate) struct StopAfterDataFlowEndedCompilation; + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_must_be_place_or_ref_place)] +pub(crate) struct PeekMustBePlaceOrRefPlace { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_must_be_not_temporary)] +pub(crate) struct PeekMustBeNotTemporary { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_bit_not_set)] +pub(crate) struct PeekBitNotSet { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_argument_not_a_local)] +pub(crate) struct PeekArgumentNotALocal { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_argument_untracked)] +pub(crate) struct PeekArgumentUntracked { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index f374658ce..bc75645e7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -1,5 +1,8 @@ //! A solver for dataflow problems. +use crate::errors::{ + DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, +}; use crate::framework::BitSetExt; use std::ffi::OsString; @@ -108,9 +111,9 @@ where // Otherwise, compute and store the cumulative transfer function for each block. let identity = GenKillSet::identity(analysis.bottom_value(body).domain_size()); - let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks()); + let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks); - for (block, block_data) in body.basic_blocks().iter_enumerated() { + for (block, block_data) in body.basic_blocks.iter_enumerated() { let trans = &mut trans_for_block[block]; A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data); } @@ -144,7 +147,7 @@ where apply_trans_for_block: Option>, ) -> Self { let bottom_value = analysis.bottom_value(body); - let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks()); + let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), &body.basic_blocks); analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != bottom_value { @@ -197,8 +200,7 @@ where .. } = self; - let mut dirty_queue: WorkQueue = - WorkQueue::with_none(body.basic_blocks().len()); + let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks.len()); if A::Direction::IS_FORWARD { for (bb, _) in traversal::reverse_postorder(body) { @@ -347,7 +349,7 @@ impl RustcMirAttrs { match path.file_name() { Some(_) => Ok(path), None => { - tcx.sess.span_err(attr.span(), "path must end in a filename"); + tcx.sess.emit_err(PathMustEndInFilename { span: attr.span() }); Err(()) } } @@ -356,7 +358,7 @@ impl RustcMirAttrs { Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { sym::gen_kill | sym::two_phase => Ok(s), _ => { - tcx.sess.span_err(attr.span(), "unknown formatter"); + tcx.sess.emit_err(UnknownFormatter { span: attr.span() }); Err(()) } }) @@ -377,8 +379,7 @@ impl RustcMirAttrs { mapper: impl FnOnce(Symbol) -> Result, ) -> Result<(), ()> { if field.is_some() { - tcx.sess - .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty())); + tcx.sess.emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() }); return Err(()); } @@ -387,8 +388,7 @@ impl RustcMirAttrs { *field = Some(mapper(s)?); Ok(()) } else { - tcx.sess - .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty())); + tcx.sess.emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() }); Err(()) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index c94198c56..579fe68a1 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -108,12 +108,12 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body.basic_blocks().indices().collect::>().into() + self.body.basic_blocks.indices().collect::>().into() } fn edges(&self) -> dot::Edges<'_, Self::Edge> { self.body - .basic_blocks() + .basic_blocks .indices() .flat_map(|bb| dataflow_successors(self.body, bb)) .collect::>() diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index f9fd6c9c5..d9aff94fe 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -256,6 +256,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// .iterate_to_fixpoint() /// .into_results_cursor(body); /// ``` + #[inline] fn into_engine<'mir>( self, tcx: TyCtxt<'tcx>, @@ -413,7 +414,7 @@ where } /* Extension methods */ - + #[inline] fn into_engine<'mir>( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index d9461fd3a..17102454a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -100,9 +100,9 @@ impl MockAnalysis<'_, D> { fn mock_entry_sets(&self) -> IndexVec> { let empty = self.bottom_value(self.body); - let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks()); + let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); - for (bb, _) in self.body.basic_blocks().iter_enumerated() { + for (bb, _) in self.body.basic_blocks.iter_enumerated() { ret[bb] = self.mock_entry_set(bb); } @@ -169,7 +169,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { const NAME: &'static str = "mock"; fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len()) + BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { @@ -271,9 +271,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { cursor.allow_unreachable(); let every_target = || { - body.basic_blocks() - .iter_enumerated() - .flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb)) + body.basic_blocks.iter_enumerated().flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb)) }; let mut seek_to_target = |targ| { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 21132eb99..3e08a8799 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -23,12 +23,6 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; -impl MaybeLiveLocals { - fn transfer_function<'a, T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> { - TransferFunction(trans) - } -} - impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { type Domain = ChunkedBitSet; type Direction = Backward; @@ -54,7 +48,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { statement: &mir::Statement<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_statement(statement, location); + TransferFunction(trans).visit_statement(statement, location); } fn terminator_effect( @@ -63,7 +57,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { terminator: &mir::Terminator<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_terminator(terminator, location); + TransferFunction(trans).visit_terminator(terminator, location); } fn call_return_effect( @@ -85,9 +79,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.kill(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } @@ -98,28 +94,51 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - let local = place.local; - - // We purposefully do not call `super_place` here to avoid calling `visit_local` for this - // place with one of the `Projection` variants of `PlaceContext`. - self.visit_projection(place.as_ref(), context, location); + if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { + // The resume place is evaluated and assigned to only after generator resumes, so its + // effect is handled separately in `yield_resume_effect`. + return; + } match DefUse::for_place(*place, context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), + Some(DefUse::Def) => { + if let PlaceContext::MutatingUse( + MutatingUseContext::Call | MutatingUseContext::AsmOutput, + ) = context + { + // For the associated terminators, this is only a `Def` when the terminator returns + // "successfully." As such, we handle this case separately in `call_return_effect` + // above. However, if the place looks like `*_5`, this is still unconditionally a use of + // `_5`. + } else { + self.0.kill(place.local); + } + } + Some(DefUse::Use) => self.0.gen(place.local), None => {} } + + self.visit_projection(place.as_ref(), context, location); } fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - // Because we do not call `super_place` above, `visit_local` is only called for locals that - // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use - // of the return place in a `Return` terminator or the index in an `Index` projection. - match DefUse::for_place(local.into(), context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - None => {} - } + DefUse::apply(self.0, local.into(), context); + } +} + +struct YieldResumeEffect<'a, T>(&'a mut T); + +impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> +where + T: GenKill, +{ + fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + DefUse::apply(self.0, *place, context); + self.visit_projection(place.as_ref(), context, location); + } + + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + DefUse::apply(self.0, local.into(), context); } } @@ -130,11 +149,25 @@ enum DefUse { } impl DefUse { + fn apply<'tcx>(trans: &mut impl GenKill, place: Place<'tcx>, context: PlaceContext) { + match DefUse::for_place(place, context) { + Some(DefUse::Def) => trans.kill(place.local), + Some(DefUse::Use) => trans.gen(place.local), + None => {} + } + } + fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option { match context { PlaceContext::NonUse(_) => None, - PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => { + PlaceContext::MutatingUse( + MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::AsmOutput + | MutatingUseContext::Store + | MutatingUseContext::Deinit, + ) => { if place.is_indirect() { // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a // use. @@ -152,16 +185,6 @@ impl DefUse { place.is_indirect().then_some(DefUse::Use) } - // For the associated terminators, this is only a `Def` when the terminator returns - // "successfully." As such, we handle this case separately in `call_return_effect` - // above. However, if the place looks like `*_5`, this is still unconditionally a use of - // `_5`. - PlaceContext::MutatingUse( - MutatingUseContext::Call - | MutatingUseContext::Yield - | MutatingUseContext::AsmOutput, - ) => place.is_indirect().then_some(DefUse::Use), - // All other contexts are uses... PlaceContext::MutatingUse( MutatingUseContext::AddressOf @@ -247,7 +270,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::Retag(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => None, }; if let Some(destination) = destination { @@ -290,8 +313,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.remove(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index f6b5af90a..18760b6c6 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -142,7 +142,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc | StatementKind::FakeRead(..) | StatementKind::Nop | StatementKind::Retag(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::StorageLive(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 5793a286b..b45c32ee9 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,12 +1,14 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(once_cell)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -33,6 +35,7 @@ use self::move_paths::MoveData; pub mod drop_flag_effects; pub mod elaborate_drops; +mod errors; mod framework; pub mod impls; pub mod move_paths; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 116e5c1f3..f46fd118b 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -243,7 +243,7 @@ pub(super) fn gather_moves<'tcx>( builder.gather_args(); - for (bb, block) in body.basic_blocks().iter_enumerated() { + for (bb, block) in body.basic_blocks.iter_enumerated() { for (i, stmt) in block.statements.iter().enumerate() { let source = Location { block: bb, statement_index: i }; builder.gather_statement(source, stmt); @@ -330,7 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index a951c5b0b..b36e268cf 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -217,7 +217,7 @@ where fn new(body: &Body<'_>) -> Self { LocationMap { map: body - .basic_blocks() + .basic_blocks .iter() .map(|block| vec![T::default(); block.statements.len() + 1]) .collect(), diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index f2471f37a..7cae68efb 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -6,6 +6,10 @@ use rustc_middle::mir::MirPass; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::errors::{ + PeekArgumentNotALocal, PeekArgumentUntracked, PeekBitNotSet, PeekMustBeNotTemporary, + PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation, +}; use crate::framework::BitSetExt; use crate::impls::{ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces, @@ -64,7 +68,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { } if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { - tcx.sess.fatal("stop_after_dataflow ended compilation"); + tcx.sess.emit_fatal(StopAfterDataFlowEndedCompilation); } } } @@ -97,7 +101,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>( let mut cursor = ResultsCursor::new(body, results); - let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| { + let peek_calls = body.basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| { PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call)) }); @@ -133,9 +137,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>( } _ => { - let msg = "rustc_peek: argument expression \ - must be either `place` or `&place`"; - tcx.sess.span_err(call.span, msg); + tcx.sess.emit_err(PeekMustBePlaceOrRefPlace { span: call.span }); } } } @@ -204,18 +206,12 @@ impl PeekCall { if let Some(local) = place.as_local() { local } else { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); + tcx.sess.emit_err(PeekMustBeNotTemporary { span }); return None; } } _ => { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); + tcx.sess.emit_err(PeekMustBeNotTemporary { span }); return None; } }; @@ -255,12 +251,12 @@ where let bit_state = flow_state.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); if !bit_state { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + tcx.sess.emit_err(PeekBitNotSet { span: call.span }); } } LookupResult::Parent(..) => { - tcx.sess.span_err(call.span, "rustc_peek: argument untracked"); + tcx.sess.emit_err(PeekArgumentUntracked { span: call.span }); } } } @@ -276,12 +272,12 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { ) { info!(?place, "peek_at"); let Some(local) = place.as_local() else { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + tcx.sess.emit_err(PeekArgumentNotALocal { span: call.span }); return; }; if !flow_state.contains(local) { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + tcx.sess.emit_err(PeekBitNotSet { span: call.span }); } } } diff --git a/compiler/rustc_mir_dataflow/src/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs index c909648ea..e5a0e1d31 100644 --- a/compiler/rustc_mir_dataflow/src/storage.rs +++ b/compiler/rustc_mir_dataflow/src/storage.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::{self, Local}; pub fn always_storage_live_locals(body: &mir::Body<'_>) -> BitSet { let mut always_live_locals = BitSet::new_filled(body.local_decls.len()); - for block in body.basic_blocks() { + for block in &*body.basic_blocks { for statement in &block.statements { use mir::StatementKind::{StorageDead, StorageLive}; if let StorageLive(l) | StorageDead(l) = statement.kind { diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 2502e8b60..d8f85d2e3 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -56,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { // example. let mut calls_to_terminate = Vec::new(); let mut cleanups_to_remove = Vec::new(); - for (id, block) in body.basic_blocks().iter_enumerated() { + for (id, block) in body.basic_blocks.iter_enumerated() { if block.is_cleanup { continue; } diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index f12c8560c..30966d22e 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -45,7 +45,7 @@ impl AddCallGuards { // We need a place to store the new blocks generated let mut new_blocks = Vec::new(); - let cur_len = body.basic_blocks().len(); + let cur_len = body.basic_blocks.len(); for block in body.basic_blocks_mut() { match block.terminator { diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 8de0aad04..ffb5d8c6d 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -55,7 +55,7 @@ fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) let mut patch = MirPatch::new(body); let param_env = tcx.param_env(def_id); - for (bb, data) in body.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks.iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 9c5896c4e..036b55898 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -66,7 +66,6 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // We need an `AllCallEdges` pass before we can do any work. super::add_call_guards::AllCallEdges.run_pass(tcx, body); - let (span, arg_count) = (body.span, body.arg_count); let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { @@ -90,20 +89,18 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // PART 1 // Retag arguments at the beginning of the start block. { - // FIXME: Consider using just the span covering the function - // argument declaration. - let source_info = SourceInfo::outermost(span); // Gather all arguments, skip return value. - let places = local_decls - .iter_enumerated() - .skip(1) - .take(arg_count) - .map(|(local, _)| Place::from(local)) - .filter(needs_retag); + let places = local_decls.iter_enumerated().skip(1).take(body.arg_count).filter_map( + |(local, decl)| { + let place = Place::from(local); + needs_retag(&place).then_some((place, decl.source_info)) + }, + ); + // Emit their retags. basic_blocks[START_BLOCK].statements.splice( 0..0, - places.map(|place| Statement { + places.map(|(place, source_info)| Statement { source_info, kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), }), diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d564f4801..beff19a3a 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -1,17 +1,16 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::{lint, mir::*}; use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; -use std::collections::hash_map; use std::ops::Bound; pub struct UnsafetyChecker<'a, 'tcx> { @@ -23,10 +22,7 @@ pub struct UnsafetyChecker<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint. - /// - /// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether - /// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`. - used_unsafe_blocks: FxHashMap, + used_unsafe_blocks: FxHashSet, } impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { @@ -109,7 +105,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // safe (at least as emitted during MIR construction) } - StatementKind::CopyNonOverlapping(..) => unreachable!(), + // Move to above list once mir construction uses it. + StatementKind::Intrinsic(..) => unreachable!(), } self.super_statement(statement, location); } @@ -130,10 +127,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => { let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = self.tcx.unsafety_check_result(def_id); - self.register_violations( - violations, - used_unsafe_blocks.iter().map(|(&h, &d)| (h, d)), - ); + self.register_violations(violations, used_unsafe_blocks.iter().copied()); } }, _ => {} @@ -257,22 +251,8 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { fn register_violations<'a>( &mut self, violations: impl IntoIterator, - new_used_unsafe_blocks: impl IntoIterator, + new_used_unsafe_blocks: impl IntoIterator, ) { - use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn}; - - let update_entry = |this: &mut Self, hir_id, new_usage| { - match this.used_unsafe_blocks.entry(hir_id) { - hash_map::Entry::Occupied(mut entry) => { - if new_usage == SomeDisallowedInUnsafeFn { - *entry.get_mut() = SomeDisallowedInUnsafeFn; - } - } - hash_map::Entry::Vacant(entry) => { - entry.insert(new_usage); - } - }; - }; let safety = self.body.source_scopes[self.source_info.scope] .local_data .as_ref() @@ -299,22 +279,14 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { } }), Safety::BuiltinUnsafe => {} - Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|violation| { - update_entry( - self, - hir_id, - match self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, violation.lint_root).0 - { - Level::Allow => AllAllowedInUnsafeFn(violation.lint_root), - _ => SomeDisallowedInUnsafeFn, - }, - ) + Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| { + self.used_unsafe_blocks.insert(hir_id); }), }; - new_used_unsafe_blocks - .into_iter() - .for_each(|(hir_id, usage_data)| update_entry(self, hir_id, usage_data)); + new_used_unsafe_blocks.into_iter().for_each(|hir_id| { + self.used_unsafe_blocks.insert(hir_id); + }); } fn check_mut_borrowing_layout_constrained_field( &mut self, @@ -411,34 +383,28 @@ enum Context { struct UnusedUnsafeVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, - used_unsafe_blocks: &'a FxHashMap, + used_unsafe_blocks: &'a FxHashSet, context: Context, unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>, } impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { - use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn}; - if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules { let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) { - (Level::Allow, _) => Some(SomeDisallowedInUnsafeFn), - _ => self.used_unsafe_blocks.get(&block.hir_id).copied(), + (Level::Allow, _) => true, + _ => self.used_unsafe_blocks.contains(&block.hir_id), }; let unused_unsafe = match (self.context, used) { - (_, None) => UnusedUnsafe::Unused, - (Context::Safe, Some(_)) - | (Context::UnsafeFn(_), Some(SomeDisallowedInUnsafeFn)) => { + (_, false) => UnusedUnsafe::Unused, + (Context::Safe, true) | (Context::UnsafeFn(_), true) => { let previous_context = self.context; self.context = Context::UnsafeBlock(block.hir_id); intravisit::walk_block(self, block); self.context = previous_context; return; } - (Context::UnsafeFn(hir_id), Some(AllAllowedInUnsafeFn(lint_root))) => { - UnusedUnsafe::InUnsafeFn(hir_id, lint_root) - } - (Context::UnsafeBlock(hir_id), Some(_)) => UnusedUnsafe::InUnsafeBlock(hir_id), + (Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id), }; self.unused_unsafes.push((block.hir_id, unused_unsafe)); } @@ -462,7 +428,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { fn check_unused_unsafe( tcx: TyCtxt<'_>, def_id: LocalDefId, - used_unsafe_blocks: &FxHashMap, + used_unsafe_blocks: &FxHashSet, ) -> Vec<(HirId, UnusedUnsafe)> { let body_id = tcx.hir().maybe_body_owned_by(def_id); @@ -535,25 +501,6 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) { "because it's nested under this `unsafe` block", ); } - UnusedUnsafe::InUnsafeFn(id, usage_lint_root) => { - db.span_label( - tcx.sess.source_map().guess_head_span(tcx.hir().span(id)), - "because it's nested under this `unsafe` fn", - ) - .note( - "this `unsafe` block does contain unsafe operations, \ - but those are already allowed in an `unsafe fn`", - ); - let (level, source) = - tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, usage_lint_root); - assert_eq!(level, Level::Allow); - lint::explain_lint_level_source( - UNSAFE_OP_IN_UNSAFE_FN, - Level::Allow, - source, - &mut db, - ); - } } db.emit(); diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 611d29a4e..3378923c2 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> { impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut delete = DeleteNonCodegenStatements { tcx }; - delete.visit_body(body); + delete.visit_body_preserves_cfg(body); body.user_type_annotations.raw.clear(); for decl in &mut body.local_decls { diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 5acf939f0..0a305a402 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -61,14 +61,14 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> { let _: Option<_> = try { let target = terminator.kind.as_goto()?; // We only apply this optimization if the last statement is a const assignment - let last_statement = self.body.basic_blocks()[location.block].statements.last()?; + let last_statement = self.body.basic_blocks[location.block].statements.last()?; if let (place, Rvalue::Use(Operand::Constant(_const))) = last_statement.kind.as_assign()? { // We found a constant being assigned to `place`. // Now check that the target of this Goto switches on this place. - let target_bb = &self.body.basic_blocks()[target]; + let target_bb = &self.body.basic_blocks[target]; // The `StorageDead(..)` statement does not affect the functionality of mir. // We can move this part of the statement up to the predecessor. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index fbc0a767f..7a2a15a84 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -28,7 +28,7 @@ use crate::MirPass; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, - Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, + Pointer, Scalar, StackPopCleanup, StackPopUnwind, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -131,7 +131,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { let dummy_body = &Body::new( body.source, - body.basic_blocks().clone(), + (*body.basic_blocks).clone(), body.source_scopes.clone(), body.local_decls.clone(), Default::default(), @@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; + #[inline(always)] + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, _instance: ty::InstanceDef<'tcx>, @@ -231,24 +243,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand> { - let l = &frame.locals[local]; - - if matches!( - l.value, - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) - ) { - // For us "uninit" means "we don't know its value, might be initiailized or not". - // So stop here. - throw_machine_stop_str!("tried to access alocal with unknown value ") - } - - l.access() - } - fn access_local_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, @@ -419,7 +413,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option> { let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => op, + Ok(op) => { + if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + // Make sure nobody accidentally uses this value. + return None; + } + op + } Err(e) => { trace!("get_const failed: {}", e); return None; @@ -428,7 +428,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Try to read the local as an immediate so that if it is representable as a scalar, we can // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) { + Some(match self.ecx.read_immediate_raw(&op) { Ok(Ok(imm)) => imm.into(), _ => op, }) @@ -520,8 +520,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let left_ty = left.ty(self.local_decls, self.tcx); let left_size = self.ecx.layout_of(left_ty).ok()?.size; let right_size = r.layout.size; - let r_bits = r.to_scalar().ok(); - let r_bits = r_bits.and_then(|r| r.to_bits(right_size).ok()); + let r_bits = r.to_scalar().to_bits(right_size).ok(); if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { return None; } @@ -550,7 +549,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // and use it to do const-prop here and everywhere else // where it makes sense. if let interpret::Operand::Immediate(interpret::Immediate::Scalar( - ScalarMaybeUninit::Scalar(scalar), + scalar, )) = *value { *operand = self.operand_from_scalar( @@ -632,6 +631,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.needs_subst() { return None; } + if !rvalue + .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) + .is_sized(self.ecx.tcx, self.param_env) + { + // the interpreter doesn't support unsized locals (only unsized arguments), + // but rustc does (in a kinda broken way), so we have to skip them here + return None; + } if self.tcx.sess.mir_opt_level() >= 4 { self.eval_rvalue_with_identities(rvalue, place) @@ -649,21 +656,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { self.use_ecx(|this| match rvalue { Rvalue::BinaryOp(op, box (left, right)) | Rvalue::CheckedBinaryOp(op, box (left, right)) => { - let l = this.ecx.eval_operand(left, None); - let r = this.ecx.eval_operand(right, None); + let l = this.ecx.eval_operand(left, None).and_then(|x| this.ecx.read_immediate(&x)); + let r = + this.ecx.eval_operand(right, None).and_then(|x| this.ecx.read_immediate(&x)); let const_arg = match (l, r) { - (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?, - (Err(e), Err(_)) => return Err(e), - (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), + (Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known + (Err(e), Err(_)) => return Err(e), // neither side is known + (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), // both sides are known }; if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) { // We cannot handle Scalar Pair stuff. - return this.ecx.eval_rvalue_into_place(rvalue, place); + // No point in calling `eval_rvalue_into_place`, since only one side is known + throw_machine_stop_str!("cannot optimize this") } - let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?; + let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size)?; let dest = this.ecx.eval_place(place)?; match op { @@ -677,7 +686,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => { if let Rvalue::CheckedBinaryOp(_, _) = rvalue { let val = Immediate::ScalarPair( - const_arg.to_scalar()?.into(), + const_arg.to_scalar().into(), Scalar::from_bool(false).into(), ); this.ecx.write_immediate(val, &dest) @@ -685,7 +694,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { this.ecx.write_immediate(*const_arg, &dest) } } - _ => this.ecx.eval_rvalue_into_place(rvalue, place), + _ => throw_machine_stop_str!("cannot optimize this"), } } _ => this.ecx.eval_rvalue_into_place(rvalue, place), @@ -731,21 +740,18 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } // FIXME> figure out what to do when read_immediate_raw fails - let imm = self.use_ecx(|this| this.ecx.read_immediate_raw(value, /*force*/ false)); + let imm = self.use_ecx(|this| this.ecx.read_immediate_raw(value)); if let Some(Ok(imm)) = imm { match *imm { - interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar)) => { + interpret::Immediate::Scalar(scalar) => { *rval = Rvalue::Use(self.operand_from_scalar( scalar, value.layout.ty, source_info.span, )); } - Immediate::ScalarPair( - ScalarMaybeUninit::Scalar(_), - ScalarMaybeUninit::Scalar(_), - ) => { + Immediate::ScalarPair(..) => { // Found a value represented as a pair. For now only do const-prop if the type // of `rvalue` is also a tuple with two scalars. // FIXME: enable the general case stated above ^. @@ -800,13 +806,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } match **op { - interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => { - s.try_to_int().is_ok() + interpret::Operand::Immediate(Immediate::Scalar(s)) => s.try_to_int().is_ok(), + interpret::Operand::Immediate(Immediate::ScalarPair(l, r)) => { + l.try_to_int().is_ok() && r.try_to_int().is_ok() } - interpret::Operand::Immediate(Immediate::ScalarPair( - ScalarMaybeUninit::Scalar(l), - ScalarMaybeUninit::Scalar(r), - )) => l.try_to_int().is_ok() && r.try_to_int().is_ok(), _ => false, } } @@ -951,7 +954,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { } fn visit_body(&mut self, body: &mut Body<'tcx>) { - for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { self.visit_basic_block_data(bb, data); } } @@ -1063,26 +1066,28 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { let source_info = terminator.source_info; self.source_info = Some(source_info); self.super_terminator(terminator, location); + // Do NOT early return in this function, it does some crucial fixup of the state at the end! match &mut terminator.kind { TerminatorKind::Assert { expected, ref mut cond, .. } => { if let Some(ref value) = self.eval_operand(&cond) { trace!("assertion on {:?} should be {:?}", value, expected); - let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); - let value_const = self.ecx.read_scalar(&value).unwrap(); - if expected != value_const { - // Poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - Self::remove_const(&mut self.ecx, place.local); + let expected = Scalar::from_bool(*expected); + // FIXME should be used use_ecx rather than a local match... but we have + // quite a few of these read_scalar/read_immediate that need fixing. + if let Ok(value_const) = self.ecx.read_scalar(&value) { + if expected != value_const { + // Poison all places this operand references so that further code + // doesn't use the invalid value + match cond { + Operand::Move(ref place) | Operand::Copy(ref place) => { + Self::remove_const(&mut self.ecx, place.local); + } + Operand::Constant(_) => {} } - Operand::Constant(_) => {} - } - } else { - if self.should_const_prop(value) { - if let ScalarMaybeUninit::Scalar(scalar) = value_const { + } else { + if self.should_const_prop(value) { *cond = self.operand_from_scalar( - scalar, + value_const, self.tcx.types.bool, source_info.span, ); diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index c2ea55af4..37e78f4ac 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -6,9 +6,9 @@ use crate::const_prop::ConstPropMachine; use crate::const_prop::ConstPropMode; use crate::MirLint; use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::interpret::Immediate; use rustc_const_eval::interpret::{ - self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, - ScalarMaybeUninit, StackPopCleanup, + self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup, }; use rustc_hir::def::DefKind; use rustc_hir::HirId; @@ -22,9 +22,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{ - self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable, -}; +use rustc_middle::ty::{self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable}; use rustc_session::lint; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; @@ -106,7 +104,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp { let dummy_body = &Body::new( body.source, - body.basic_blocks().clone(), + (*body.basic_blocks).clone(), body.source_scopes.clone(), body.local_decls.clone(), Default::default(), @@ -230,7 +228,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option> { let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => op, + Ok(op) => { + if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + // Make sure nobody accidentally uses this value. + return None; + } + op + } Err(e) => { trace!("get_const failed: {}", e); return None; @@ -239,7 +243,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Try to read the local as an immediate so that if it is representable as a scalar, we can // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) { + Some(match self.ecx.read_immediate_raw(&op) { Ok(Ok(imm)) => imm.into(), _ => op, }) @@ -295,18 +299,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal { - ConstantKind::Ty(ct) => match ct.kind() { + ConstantKind::Ty(ct) => ct.needs_subst(), + ConstantKind::Unevaluated( + ty::Unevaluated { def: _, substs: _, promoted: Some(_) }, + _, + ) => { // Promoteds must lint and not error as the user didn't ask for them - ConstKind::Unevaluated(ty::Unevaluated { - def: _, - substs: _, - promoted: Some(_), - }) => true, - // Out of backwards compatibility we cannot report hard errors in unused - // generic functions using associated constants of the generic parameters. - _ => c.literal.needs_subst(), - }, - ConstantKind::Val(_, ty) => ty.needs_subst(), + true + } + ConstantKind::Unevaluated(..) | ConstantKind::Val(..) => c.needs_subst(), }; if lint_only { // Out of backwards compatibility we cannot report hard errors in unused @@ -401,8 +402,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let left_ty = left.ty(self.local_decls, self.tcx); let left_size = self.ecx.layout_of(left_ty).ok()?.size; let right_size = r.layout.size; - let r_bits = r.to_scalar().ok(); - let r_bits = r_bits.and_then(|r| r.to_bits(right_size).ok()); + let r_bits = r.to_scalar().to_bits(right_size).ok(); if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { debug!("check_binary_op: reporting assert for {:?}", source_info); self.report_assert_as_lint( @@ -517,6 +517,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.needs_subst() { return None; } + if !rvalue + .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) + .is_sized(self.ecx.tcx, self.param_env) + { + // the interpreter doesn't support unsized locals (only unsized arguments), + // but rustc does (in a kinda broken way), so we have to skip them here + return None; + } self.use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, place)) } @@ -524,7 +532,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_body(&mut self, body: &Body<'tcx>) { - for (bb, data) in body.basic_blocks().iter_enumerated() { + for (bb, data) in body.basic_blocks.iter_enumerated() { self.visit_basic_block_data(bb, data); } } @@ -625,8 +633,12 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { TerminatorKind::Assert { expected, ref msg, ref cond, .. } => { if let Some(ref value) = self.eval_operand(&cond, source_info) { trace!("assertion on {:?} should be {:?}", value, expected); - let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); - let value_const = self.ecx.read_scalar(&value).unwrap(); + let expected = Scalar::from_bool(*expected); + let Ok(value_const) = self.ecx.read_scalar(&value) else { + // FIXME should be used use_ecx rather than a local match... but we have + // quite a few of these read_scalar/read_immediate that need fixing. + return + }; if expected != value_const { enum DbgVal { Val(T), @@ -643,9 +655,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { let mut eval_to_int = |op| { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. - self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| { - DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int()) - }) + self.eval_operand(op, source_info) + .and_then(|op| self.ecx.read_immediate(&op).ok()) + .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; let msg = match msg { AssertKind::DivisionByZero(op) => { diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 759ea7cd3..782129be0 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -713,7 +713,7 @@ impl< ShortCircuitPreorder { body, - visited: BitSet::new_empty(body.basic_blocks().len()), + visited: BitSet::new_empty(body.basic_blocks.len()), worklist, filtered_successors, } @@ -747,7 +747,7 @@ impl< } fn size_hint(&self) -> (usize, Option) { - let size = self.body.basic_blocks().len() - self.visited.count(); + let size = self.body.basic_blocks.len() - self.visited.count(); (size, Some(size)) } } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 2619626a5..604810144 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -80,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { return; } - match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { + match mir_body.basic_blocks[mir::START_BLOCK].terminator().kind { TerminatorKind::Unreachable => { trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); return; @@ -541,7 +541,7 @@ fn fn_sig_and_body<'tcx>( // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) + (hir_node.fn_sig(), tcx.hir().body(fn_body_id)) } fn get_body_span<'tcx>( diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 9d02f58ae..dc1e68b25 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -84,7 +84,7 @@ impl CoverageVisitor { } fn visit_body(&mut self, body: &Body<'_>) { - for bb_data in body.basic_blocks().iter() { + for bb_data in body.basic_blocks.iter() { for statement in bb_data.statements.iter() { if let StatementKind::Coverage(box ref coverage) = statement.kind { if is_inlined(body, statement) { @@ -138,7 +138,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { let body = mir_body(tcx, def_id); - body.basic_blocks() + body.basic_blocks .iter() .flat_map(|data| { data.statements.iter().filter_map(|statement| match statement.kind { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 423e78317..9f842c929 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -825,7 +825,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option // Retain spans from all other statements StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Assign(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 6380f0352..9c9ed5fa5 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -176,7 +176,7 @@ fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String { format!( "{:?}", mir_body - .basic_blocks() + .basic_blocks .iter_enumerated() .map(|(bb, data)| { let term = &data.terminator(); @@ -213,7 +213,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { "digraph {} {{\n{}\n}}", name, mir_body - .basic_blocks() + .basic_blocks .iter_enumerated() .map(|(bb, data)| { format!( @@ -653,7 +653,7 @@ fn test_traverse_coverage_with_loops() { fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span { let mut some_span: Option = None; - for (_, data) in mir_body.basic_blocks().iter_enumerated() { + for (_, data) in mir_body.basic_blocks.iter_enumerated() { let term_span = data.terminator().source_info.span; if let Some(span) = some_span.as_mut() { *span = span.to(term_span); diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 9163672f5..3f3870cc7 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -52,7 +52,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Coverage(_) - | StatementKind::CopyNonOverlapping(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => (), StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { diff --git a/compiler/rustc_mir_transform/src/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs index b93fe5879..fe272de20 100644 --- a/compiler/rustc_mir_transform/src/deaggregator.rs +++ b/compiler/rustc_mir_transform/src/deaggregator.rs @@ -6,10 +6,6 @@ use rustc_middle::ty::TyCtxt; pub struct Deaggregator; impl<'tcx> MirPass<'tcx> for Deaggregator { - fn phase_change(&self) -> Option { - Some(MirPhase::Deaggregated) - } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for bb in basic_blocks { diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index d1977ed49..909116a77 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -58,7 +58,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap { let mut duplicates = FxHashMap::default(); let bbs_to_go_through = - body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); + body.basic_blocks.iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); let mut same_hashes = FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default()); @@ -71,8 +71,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap { // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list // with replacement bb3. // When the duplicates are removed, we will end up with only bb3. - for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) - { + for (bb, bbd) in body.basic_blocks.iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) { // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks // that are unlikely to have duplicates, we stop early. The early bail number has been // found experimentally by eprintln while compiling the crates in the rustc-perf suite. diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index a00bb16f7..7508df92d 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -28,8 +28,6 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { let mut last_len = 0; let mut last_deref_idx = 0; - let mut prev_temp: Option = None; - for (idx, elem) in place.projection[0..].iter().enumerate() { if *elem == ProjectionElem::Deref { last_deref_idx = idx; @@ -39,14 +37,12 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { let ty = p_ref.ty(&self.local_decls, self.tcx).ty; - let temp = self.patcher.new_local_with_info( + let temp = self.patcher.new_internal_with_info( ty, self.local_decls[p_ref.local].source_info.span, Some(Box::new(LocalInfo::DerefTemp)), ); - self.patcher.add_statement(loc, StatementKind::StorageLive(temp)); - // We are adding current p_ref's projections to our // temp value, excluding projections we already covered. let deref_place = Place::from(place_local) @@ -66,22 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { Place::from(temp).project_deeper(&place.projection[idx..], self.tcx); *place = temp_place; } - - // We are destroying the previous temp since it's no longer used. - if let Some(prev_temp) = prev_temp { - self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp)); - } - - prev_temp = Some(temp); } } - - // Since we won't be able to reach final temp, we destroy it outside the loop. - if let Some(prev_temp) = prev_temp { - let last_loc = - Location { block: loc.block, statement_index: loc.statement_index + 1 }; - self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp)); - } } } } @@ -90,7 +72,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() }; - for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { checker.visit_basic_block_data(bb, data); } @@ -100,6 +82,5 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { impl<'tcx> MirPass<'tcx> for Derefer { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { deref_finder(tcx, body); - body.phase = MirPhase::Derefered; } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 33572068f..9bc47613e 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -150,7 +150,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { def_id, body.local_decls.len(), relevant, - body.basic_blocks().len() + body.basic_blocks.len() ); if relevant > MAX_LOCALS { warn!( @@ -159,11 +159,11 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { ); return; } - if body.basic_blocks().len() > MAX_BLOCKS { + if body.basic_blocks.len() > MAX_BLOCKS { warn!( "too many blocks in {:?} ({}, max is {}), not optimizing", def_id, - body.basic_blocks().len(), + body.basic_blocks.len(), MAX_BLOCKS ); return; @@ -537,7 +537,7 @@ impl<'a> Conflicts<'a> { | StatementKind::FakeRead(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index dba42f7af..32e738bbc 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -104,8 +104,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { let mut should_cleanup = false; // Also consider newly generated bbs in the same pass - for i in 0..body.basic_blocks().len() { - let bbs = body.basic_blocks(); + for i in 0..body.basic_blocks.len() { + let bbs = &*body.basic_blocks; let parent = BasicBlock::from_usize(i); let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue @@ -316,7 +316,7 @@ fn evaluate_candidate<'tcx>( body: &Body<'tcx>, parent: BasicBlock, ) -> Option> { - let bbs = body.basic_blocks(); + let bbs = &body.basic_blocks; let TerminatorKind::SwitchInt { targets, switch_ty: parent_ty, diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 44e3945d6..294af2455 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -69,10 +69,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { let (unique_ty, nonnull_ty, ptr_ty) = build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did); - let ptr_local = self.patch.new_temp(ptr_ty, source_info.span); - self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span)); - - self.patch.add_statement(location, StatementKind::StorageLive(ptr_local)); + let ptr_local = self.patch.new_internal(ptr_ty, source_info.span); self.patch.add_assign( location, @@ -84,11 +81,6 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { ); place.local = ptr_local; - - self.patch.add_statement( - Location { block: location.block, statement_index: location.statement_index + 1 }, - StatementKind::StorageDead(ptr_local), - ); } self.super_place(place, context, location); @@ -115,34 +107,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { let mut visitor = ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; - for (block, BasicBlockData { statements, terminator, .. }) in - body.basic_blocks.as_mut().iter_enumerated_mut() - { - let mut index = 0; - for statement in statements { - let location = Location { block, statement_index: index }; - visitor.visit_statement(statement, location); - index += 1; - } - - if let Some(terminator) = terminator - && !matches!(terminator.kind, TerminatorKind::Yield{..}) - { - let location = Location { block, statement_index: index }; - visitor.visit_terminator(terminator, location); - } - - let location = Location { block, statement_index: index }; - match terminator { - // yielding into a box is handled when lowering generators - Some(Terminator { kind: TerminatorKind::Yield { value, .. }, .. }) => { - visitor.visit_operand(value, location); - } - Some(terminator) => { - visitor.visit_terminator(terminator, location); - } - None => {} - } + for (block, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, data); } visitor.patch.apply(body); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 9c1fcbaa6..65f4956d2 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -21,10 +21,6 @@ use std::fmt; pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { - fn phase_change(&self) -> Option { - Some(MirPhase::DropsLowered) - } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); @@ -89,13 +85,13 @@ fn find_dead_unwinds<'tcx>( debug!("find_dead_unwinds({:?})", body.span); // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. - let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); + let mut dead_unwinds = BitSet::new_empty(body.basic_blocks.len()); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body) .pass_name("find_dead_unwinds") .iterate_to_fixpoint() .into_results_cursor(body); - for (bb, bb_data) in body.basic_blocks().iter_enumerated() { + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { let place = match bb_data.terminator().kind { TerminatorKind::Drop { ref place, unwind: Some(_), .. } | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => { @@ -303,7 +299,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn collect_drop_flags(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks.iter_enumerated() { let terminator = data.terminator(); let place = match terminator.kind { TerminatorKind::Drop { ref place, .. } @@ -358,7 +354,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn elaborate_drops(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks.iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); @@ -515,7 +511,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_for_fn_rets(&mut self) { - for (bb, data) in self.body.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks.iter_enumerated() { if let TerminatorKind::Call { destination, target: Some(tgt), cleanup: Some(_), .. } = data.terminator().kind @@ -550,7 +546,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // drop flags by themselves, to avoid the drop flags being // clobbered before they are read. - for (bb, data) in self.body.basic_blocks().iter_enumerated() { + for (bb, data) in self.body.basic_blocks.iter_enumerated() { debug!("drop_flags_for_locs({:?})", data); for i in 0..(data.statements.len() + 1) { debug!("drop_flag_for_locs: stmt {}", i); diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 7728fdaff..7522a50a8 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -65,7 +65,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let mut tainted = false; - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { if block.is_cleanup { continue; } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 91ecf3879..705cf776f 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -490,12 +490,12 @@ fn locals_live_across_suspend_points<'tcx>( .iterate_to_fixpoint() .into_results_cursor(body_ref); - let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); + let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); let mut live_locals_at_suspension_points = Vec::new(); let mut source_info_at_suspension_points = Vec::new(); let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); - for (block, data) in body.basic_blocks().iter_enumerated() { + for (block, data) in body.basic_blocks.iter_enumerated() { if let TerminatorKind::Yield { .. } = data.terminator().kind { let loc = Location { block, statement_index: data.statements.len() }; @@ -704,7 +704,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx> impl StorageConflictVisitor<'_, '_, '_> { fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { // Ignore unreachable blocks. - if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable { + if self.body.basic_blocks[loc.block].terminator().kind == TerminatorKind::Unreachable { return; } @@ -886,7 +886,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env }; - for (block, block_data) in body.basic_blocks().iter_enumerated() { + for (block, block_data) in body.basic_blocks.iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { if let Some(local) = place.as_local() { @@ -991,7 +991,7 @@ fn insert_panic_block<'tcx>( body: &mut Body<'tcx>, message: AssertMessage<'tcx>, ) -> BasicBlock { - let assert_block = BasicBlock::new(body.basic_blocks().len()); + let assert_block = BasicBlock::new(body.basic_blocks.len()); let term = TerminatorKind::Assert { cond: Operand::Constant(Box::new(Constant { span: body.span, @@ -1021,7 +1021,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEn } // If there's a return terminator the function may return. - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { if let TerminatorKind::Return = block.terminator().kind { return true; } @@ -1038,7 +1038,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { } // Unwinds can only start at certain terminators. - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { match block.terminator().kind { // These never unwind. TerminatorKind::Goto { .. } @@ -1182,8 +1182,6 @@ fn create_cases<'tcx>( transform: &TransformVisitor<'tcx>, operation: Operation, ) -> Vec<(usize, BasicBlock)> { - let tcx = transform.tcx; - let source_info = SourceInfo::outermost(body.span); transform @@ -1216,85 +1214,13 @@ fn create_cases<'tcx>( if operation == Operation::Resume { // Move the resume argument to the destination place of the `Yield` terminator let resume_arg = Local::new(2); // 0 = return, 1 = self - - // handle `box yield` properly - let box_place = if let [projection @ .., ProjectionElem::Deref] = - &**point.resume_arg.projection - { - let box_place = - Place::from(point.resume_arg.local).project_deeper(projection, tcx); - - let box_ty = box_place.ty(&body.local_decls, tcx).ty; - - if box_ty.is_box() { Some((box_place, box_ty)) } else { None } - } else { - None - }; - - if let Some((box_place, box_ty)) = box_place { - let unique_did = box_ty - .ty_adt_def() - .expect("expected Box to be an Adt") - .non_enum_variant() - .fields[0] - .did; - - let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else { - span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") - }; - - let nonnull_did = nonnull_def.non_enum_variant().fields[0].did; - - let (unique_ty, nonnull_ty, ptr_ty) = - crate::elaborate_box_derefs::build_ptr_tys( - tcx, - box_ty.boxed_ty(), - unique_did, - nonnull_did, - ); - - let ptr_local = body.local_decls.push(LocalDecl::new(ptr_ty, body.span)); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageLive(ptr_local), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local), - Rvalue::Use(Operand::Copy(box_place.project_deeper( - &crate::elaborate_box_derefs::build_projection( - unique_ty, nonnull_ty, ptr_ty, - ), - tcx, - ))), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local) - .project_deeper(&[ProjectionElem::Deref], tcx), - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageDead(ptr_local), - }); - } else { - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - point.resume_arg, - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - } + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + point.resume_arg, + Rvalue::Use(Operand::Move(resume_arg.into())), + ))), + }); } // Then jump to the real target @@ -1314,10 +1240,6 @@ fn create_cases<'tcx>( } impl<'tcx> MirPass<'tcx> for StateTransform { - fn phase_change(&self) -> Option { - Some(MirPhase::GeneratorsLowered) - } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Some(yield_ty) = body.yield_ty() else { // This only applies to generators @@ -1530,7 +1452,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | StatementKind::Retag(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 76b1522f3..d00a384cb 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -8,8 +8,11 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_session::config::OptLevel; +use rustc_span::def_id::DefId; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; +use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use super::simplify::{remove_dead_blocks, CfgSimplifier}; @@ -43,8 +46,15 @@ impl<'tcx> MirPass<'tcx> for Inline { return enabled; } - // rust-lang/rust#101004: reverted to old inlining decision logic - sess.mir_opt_level() >= 3 + match sess.mir_opt_level() { + 0 | 1 => false, + 2 => { + (sess.opts.optimize == OptLevel::Default + || sess.opts.optimize == OptLevel::Aggressive) + && sess.opts.incremental == None + } + _ => true, + } } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -85,7 +95,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { history: Vec::new(), changed: false, }; - let blocks = BasicBlock::new(0)..body.basic_blocks().next_index(); + let blocks = BasicBlock::new(0)..body.basic_blocks.next_index(); this.process_blocks(body, blocks); this.changed } @@ -95,8 +105,12 @@ struct Inliner<'tcx> { param_env: ParamEnv<'tcx>, /// Caller codegen attributes. codegen_fn_attrs: &'tcx CodegenFnAttrs, - /// Stack of inlined Instances. - history: Vec>, + /// Stack of inlined instances. + /// We only check the `DefId` and not the substs because we want to + /// avoid inlining cases of polymorphic recursion. + /// The number of `DefId`s is finite, so checking history is enough + /// to ensure that we do not loop endlessly while inlining. + history: Vec, /// Indicates that the caller body has been modified. changed: bool, } @@ -124,7 +138,7 @@ impl<'tcx> Inliner<'tcx> { Ok(new_blocks) => { debug!("inlined {}", callsite.callee); self.changed = true; - self.history.push(callsite.callee); + self.history.push(callsite.callee.def_id()); self.process_blocks(caller_body, new_blocks); self.history.pop(); } @@ -203,9 +217,9 @@ impl<'tcx> Inliner<'tcx> { } } - let old_blocks = caller_body.basic_blocks().next_index(); + let old_blocks = caller_body.basic_blocks.next_index(); self.inline_call(caller_body, &callsite, callee_body); - let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); + let new_blocks = old_blocks..caller_body.basic_blocks.next_index(); Ok(new_blocks) } @@ -300,7 +314,7 @@ impl<'tcx> Inliner<'tcx> { return None; } - if self.history.contains(&callee) { + if self.history.contains(&callee.def_id()) { return None; } @@ -395,124 +409,66 @@ impl<'tcx> Inliner<'tcx> { // Give a bonus functions with a small number of blocks, // We normally have two or three blocks for even // very small functions. - if callee_body.basic_blocks().len() <= 3 { + if callee_body.basic_blocks.len() <= 3 { threshold += threshold / 4; } debug!(" final inline threshold = {}", threshold); // FIXME: Give a bonus to functions with only a single caller - let mut first_block = true; - let mut cost = 0; + let diverges = matches!( + callee_body.basic_blocks[START_BLOCK].terminator().kind, + TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. } + ); + if diverges && !matches!(callee_attrs.inline, InlineAttr::Always) { + return Err("callee diverges unconditionally"); + } - // Traverse the MIR manually so we can account for the effects of - // inlining on the CFG. + let mut checker = CostChecker { + tcx: self.tcx, + param_env: self.param_env, + instance: callsite.callee, + callee_body, + cost: 0, + validation: Ok(()), + }; + + // Traverse the MIR manually so we can account for the effects of inlining on the CFG. let mut work_list = vec![START_BLOCK]; - let mut visited = BitSet::new_empty(callee_body.basic_blocks().len()); + let mut visited = BitSet::new_empty(callee_body.basic_blocks.len()); while let Some(bb) = work_list.pop() { if !visited.insert(bb.index()) { continue; } - let blk = &callee_body.basic_blocks()[bb]; - for stmt in &blk.statements { - // Don't count StorageLive/StorageDead in the inlining cost. - match stmt.kind { - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Deinit(_) - | StatementKind::Nop => {} - _ => cost += INSTR_COST, - } - } - let term = blk.terminator(); - let mut is_drop = false; - match term.kind { - TerminatorKind::Drop { ref place, target, unwind } - | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => { - is_drop = true; - work_list.push(target); - // If the place doesn't actually need dropping, treat it like - // a regular goto. - let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); - if ty.needs_drop(tcx, self.param_env) { - cost += CALL_PENALTY; - if let Some(unwind) = unwind { - cost += LANDINGPAD_PENALTY; - work_list.push(unwind); - } - } else { - cost += INSTR_COST; - } - } + let blk = &callee_body.basic_blocks[bb]; + checker.visit_basic_block_data(bb, blk); - TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. } - if first_block => - { - // If the function always diverges, don't inline - // unless the cost is zero - threshold = 0; - } - - TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, _) = - *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() - { - // Don't give intrinsics the extra penalty for calls - if tcx.is_intrinsic(def_id) { - cost += INSTR_COST; - } else { - cost += CALL_PENALTY; - } - } else { - cost += CALL_PENALTY; - } - if cleanup.is_some() { - cost += LANDINGPAD_PENALTY; - } - } - TerminatorKind::Assert { cleanup, .. } => { - cost += CALL_PENALTY; - - if cleanup.is_some() { - cost += LANDINGPAD_PENALTY; - } - } - TerminatorKind::Resume => cost += RESUME_PENALTY, - TerminatorKind::InlineAsm { cleanup, .. } => { - cost += INSTR_COST; + let term = blk.terminator(); + if let TerminatorKind::Drop { ref place, target, unwind } + | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } = term.kind + { + work_list.push(target); - if cleanup.is_some() { - cost += LANDINGPAD_PENALTY; + // If the place doesn't actually need dropping, treat it like a regular goto. + let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); + if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind { + work_list.push(unwind); } - } - _ => cost += INSTR_COST, - } - - if !is_drop { - for succ in term.successors() { - work_list.push(succ); - } + } else { + work_list.extend(term.successors()) } - - first_block = false; } // Count up the cost of local variables and temps, if we know the size // use that, otherwise we use a moderately-large dummy cost. - - let ptr_size = tcx.data_layout.pointer_size.bytes(); - for v in callee_body.vars_and_temps_iter() { - let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty); - // Cost of the var is the size in machine-words, if we know - // it. - if let Some(size) = type_size_of(tcx, self.param_env, ty) { - cost += ((size + ptr_size - 1) / ptr_size) as usize; - } else { - cost += UNKNOWN_SIZE_COST; - } + checker.visit_local_decl(v, &callee_body.local_decls[v]); } + // Abort if type validation found anything fishy. + checker.validation?; + + let cost = checker.cost; if let InlineAttr::Always = callee_attrs.inline { debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); Ok(()) @@ -585,7 +541,7 @@ impl<'tcx> Inliner<'tcx> { args: &args, new_locals: Local::new(caller_body.local_decls.len()).., new_scopes: SourceScope::new(caller_body.source_scopes.len()).., - new_blocks: BasicBlock::new(caller_body.basic_blocks().len()).., + new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., destination: dest, callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite, @@ -603,7 +559,9 @@ impl<'tcx> Inliner<'tcx> { // If there are any locals without storage markers, give them storage only for the // duration of the call. for local in callee_body.vars_and_temps_iter() { - if integrator.always_live_locals.contains(local) { + if !callee_body.local_decls[local].internal + && integrator.always_live_locals.contains(local) + { let new_local = integrator.map_local(local); caller_body[callsite.block].statements.push(Statement { source_info: callsite.source_info, @@ -616,7 +574,9 @@ impl<'tcx> Inliner<'tcx> { // the slice once. let mut n = 0; for local in callee_body.vars_and_temps_iter().rev() { - if integrator.always_live_locals.contains(local) { + if !callee_body.local_decls[local].internal + && integrator.always_live_locals.contains(local) + { let new_local = integrator.map_local(local); caller_body[block].statements.push(Statement { source_info: callsite.source_info, @@ -644,11 +604,11 @@ impl<'tcx> Inliner<'tcx> { // `required_consts`, here we may not only have `ConstKind::Unevaluated` // because we are calling `subst_and_normalize_erasing_regions`. caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&ct| { - match ct.literal.const_for_ty() { - Some(ct) => matches!(ct.kind(), ConstKind::Unevaluated(_)), - None => true, + callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal { + ConstantKind::Ty(_) => { + bug!("should never encounter ty::Unevaluated in `required_consts`") } + ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true, }), ); } @@ -782,6 +742,193 @@ fn type_size_of<'tcx>( tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) } +/// Verify that the callee body is compatible with the caller. +/// +/// This visitor mostly computes the inlining cost, +/// but also needs to verify that types match because of normalization failure. +struct CostChecker<'b, 'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + cost: usize, + callee_body: &'b Body<'tcx>, + instance: ty::Instance<'tcx>, + validation: Result<(), &'static str>, +} + +impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Don't count StorageLive/StorageDead in the inlining cost. + match statement.kind { + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Deinit(_) + | StatementKind::Nop => {} + _ => self.cost += INSTR_COST, + } + + self.super_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + let tcx = self.tcx; + match terminator.kind { + TerminatorKind::Drop { ref place, unwind, .. } + | TerminatorKind::DropAndReplace { ref place, unwind, .. } => { + // If the place doesn't actually need dropping, treat it like a regular goto. + let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty); + if ty.needs_drop(tcx, self.param_env) { + self.cost += CALL_PENALTY; + if unwind.is_some() { + self.cost += LANDINGPAD_PENALTY; + } + } else { + self.cost += INSTR_COST; + } + } + TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { + let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty()); + self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { + // Don't give intrinsics the extra penalty for calls + INSTR_COST + } else { + CALL_PENALTY + }; + if cleanup.is_some() { + self.cost += LANDINGPAD_PENALTY; + } + } + TerminatorKind::Assert { cleanup, .. } => { + self.cost += CALL_PENALTY; + if cleanup.is_some() { + self.cost += LANDINGPAD_PENALTY; + } + } + TerminatorKind::Resume => self.cost += RESUME_PENALTY, + TerminatorKind::InlineAsm { cleanup, .. } => { + self.cost += INSTR_COST; + if cleanup.is_some() { + self.cost += LANDINGPAD_PENALTY; + } + } + _ => self.cost += INSTR_COST, + } + + self.super_terminator(terminator, location); + } + + /// Count up the cost of local variables and temps, if we know the size + /// use that, otherwise we use a moderately-large dummy cost. + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + let tcx = self.tcx; + let ptr_size = tcx.data_layout.pointer_size.bytes(); + + let ty = self.instance.subst_mir(tcx, &local_decl.ty); + // Cost of the var is the size in machine-words, if we know + // it. + if let Some(size) = type_size_of(tcx, self.param_env, ty) { + self.cost += ((size + ptr_size - 1) / ptr_size) as usize; + } else { + self.cost += UNKNOWN_SIZE_COST; + } + + self.super_local_decl(local, local_decl) + } + + /// This method duplicates code from MIR validation in an attempt to detect type mismatches due + /// to normalization failure. + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let ProjectionElem::Field(f, ty) = elem { + let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) }; + let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx); + let check_equal = |this: &mut Self, f_ty| { + if !equal_up_to_regions(this.tcx, this.param_env, ty, f_ty) { + trace!(?ty, ?f_ty); + this.validation = Err("failed to normalize projection type"); + return; + } + }; + + let kind = match parent_ty.ty.kind() { + &ty::Opaque(def_id, substs) => { + self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind() + } + kind => kind, + }; + + match kind { + ty::Tuple(fields) => { + let Some(f_ty) = fields.get(f.as_usize()) else { + self.validation = Err("malformed MIR"); + return; + }; + check_equal(self, *f_ty); + } + ty::Adt(adt_def, substs) => { + let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0)); + let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else { + self.validation = Err("malformed MIR"); + return; + }; + check_equal(self, field.ty(self.tcx, substs)); + } + ty::Closure(_, substs) => { + let substs = substs.as_closure(); + let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else { + self.validation = Err("malformed MIR"); + return; + }; + check_equal(self, f_ty); + } + &ty::Generator(def_id, substs, _) => { + let f_ty = if let Some(var) = parent_ty.variant_index { + let gen_body = if def_id == self.callee_body.source.def_id() { + self.callee_body + } else { + self.tcx.optimized_mir(def_id) + }; + + let Some(layout) = gen_body.generator_layout() else { + self.validation = Err("malformed MIR"); + return; + }; + + let Some(&local) = layout.variant_fields[var].get(f) else { + self.validation = Err("malformed MIR"); + return; + }; + + let Some(&f_ty) = layout.field_tys.get(local) else { + self.validation = Err("malformed MIR"); + return; + }; + + f_ty + } else { + let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { + self.validation = Err("malformed MIR"); + return; + }; + + f_ty + }; + + check_equal(self, f_ty); + } + _ => self.validation = Err("malformed MIR"), + } + } + + self.super_projection_elem(local, proj_base, elem, context, location); + } +} + /** * Integrator. * diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 7810218fd..b027f9492 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -153,7 +153,7 @@ pub(crate) fn mir_inliner_callees<'tcx>( _ => tcx.instance_mir(instance), }; let mut calls = FxIndexSet::default(); - for bb_data in body.basic_blocks() { + for bb_data in body.basic_blocks.iter() { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func, .. } = &terminator.kind { let ty = func.ty(&body.local_decls, tcx); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d968a4885..e6fc85595 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,7 +1,7 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(never_type)] @@ -10,6 +10,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(if_let_guard)] #![recursion_limit = "256"] #[macro_use] @@ -26,10 +27,14 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; -use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; +use rustc_middle::mir::{ + traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand, + Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, + TerminatorKind, +}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; -use rustc_span::{Span, Symbol}; +use rustc_span::sym; #[macro_use] mod pass_manager; @@ -139,6 +144,64 @@ pub fn provide(providers: &mut Providers) { }; } +fn remap_mir_for_const_eval_select<'tcx>( + tcx: TyCtxt<'tcx>, + mut body: Body<'tcx>, + context: hir::Constness, +) -> Body<'tcx> { + for bb in body.basic_blocks.as_mut().iter_mut() { + let terminator = bb.terminator.as_mut().expect("invalid terminator"); + match terminator.kind { + TerminatorKind::Call { + func: Operand::Constant(box Constant { ref literal, .. }), + ref mut args, + destination, + target, + cleanup, + fn_span, + .. + } if let ty::FnDef(def_id, _) = *literal.ty().kind() + && tcx.item_name(def_id) == sym::const_eval_select + && tcx.is_intrinsic(def_id) => + { + let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap(); + let ty = tupled_args.ty(&body.local_decls, tcx); + let fields = ty.tuple_fields(); + let num_args = fields.len(); + let func = if context == hir::Constness::Const { called_in_const } else { called_at_rt }; + let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args { + Operand::Constant(_) => { + // there is no good way of extracting a tuple arg from a constant (const generic stuff) + // so we just create a temporary and deconstruct that. + let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); + bb.statements.push(Statement { + source_info: SourceInfo::outermost(fn_span), + kind: StatementKind::Assign(Box::new((local.into(), Rvalue::Use(tupled_args.clone())))), + }); + (Operand::Move, local.into()) + } + Operand::Move(place) => (Operand::Move, place), + Operand::Copy(place) => (Operand::Copy, place), + }; + let place_elems = place.projection; + let arguments = (0..num_args).map(|x| { + let mut place_elems = place_elems.to_vec(); + place_elems.push(ProjectionElem::Field(x.into(), fields[x])); + let projection = tcx.intern_place_elems(&place_elems); + let place = Place { + local: place.local, + projection, + }; + method(place) + }).collect(); + terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span }; + } + _ => {} + } + } + body +} + fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let def_id = def_id.expect_local(); tcx.mir_keys(()).contains(&def_id) @@ -159,14 +222,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { set: &'a mut FxIndexSet, } impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> { - fn visit_variant_data( - &mut self, - v: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &'tcx hir::Generics<'tcx>, - _: hir::HirId, - _: Span, - ) { + fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) { if let hir::VariantData::Tuple(_, hir_id) = *v { self.set.insert(self.tcx.hir().local_def_id(hir_id)); } @@ -208,6 +264,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> } /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! +/// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). +/// We used to have this for pre-miri MIR based const eval. fn mir_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -243,7 +301,6 @@ fn mir_const<'tcx>( // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, // Just a lint - &marker::PhaseChange(MirPhase::Const), ], ); tcx.alloc_steal_mir(body) @@ -330,7 +387,9 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - .body_const_context(def.did) .expect("mir_for_ctfe should not be used for runtime functions"); - let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); match context { // Do not const prop functions, either they get executed at runtime or exported to metadata, @@ -349,7 +408,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - pm::run_passes( tcx, &mut body, - &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimized)], + &[ + &const_prop::ConstProp, + &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), + ], ); } } @@ -389,38 +451,61 @@ fn mir_drops_elaborated_and_const_checked<'tcx>( body.tainted_by_errors = Some(error_reported); } - // IMPORTANT - pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]); + run_analysis_to_runtime_passes(tcx, &mut body); + + tcx.alloc_steal_mir(body) +} + +fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial)); + let did = body.source.def_id(); + + debug!("analysis_mir_cleanup({:?})", did); + run_analysis_cleanup_passes(tcx, body); + assert!(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup)); // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled. if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) { pm::run_passes( tcx, - &mut body, + body, &[ - &simplify::SimplifyCfg::new("remove-false-edges"), &remove_uninit_drops::RemoveUninitDrops, + &simplify::SimplifyCfg::new("remove-false-edges"), ], ); check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint } - run_post_borrowck_cleanup_passes(tcx, &mut body); - assert!(body.phase == MirPhase::Deaggregated); - tcx.alloc_steal_mir(body) + debug!("runtime_mir_lowering({:?})", did); + run_runtime_lowering_passes(tcx, body); + assert!(body.phase == MirPhase::Runtime(RuntimePhase::Initial)); + + debug!("runtime_mir_cleanup({:?})", did); + run_runtime_cleanup_passes(tcx, body); + assert!(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)); } -/// After this series of passes, no lifetime analysis based on borrowing can be done. -fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("post_borrowck_cleanup({:?})", body.source.def_id()); +// FIXME(JakobDegen): Can we make these lists of passes consts? - let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[ - // Remove all things only needed by analysis +/// After this series of passes, no lifetime analysis based on borrowing can be done. +fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let passes: &[&dyn MirPass<'tcx>] = &[ + &remove_false_edges::RemoveFalseEdges, &simplify_branches::SimplifyConstCondition::new("initial"), &remove_noop_landing_pads::RemoveNoopLandingPads, &cleanup_post_borrowck::CleanupNonCodegenStatements, &simplify::SimplifyCfg::new("early-opt"), &deref_separator::Derefer, + &marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)), + ]; + + pm::run_passes(tcx, body, passes); +} + +/// Returns the sequence of passes that lowers analysis to runtime MIR. +fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let passes: &[&dyn MirPass<'tcx>] = &[ // These next passes must be executed together &add_call_guards::CriticalCallEdges, &elaborate_drops::ElaborateDrops, @@ -434,16 +519,27 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. &elaborate_box_derefs::ElaborateBoxDerefs, + &generator::StateTransform, &add_retag::AddRetag, - &lower_intrinsics::LowerIntrinsics, - &simplify::SimplifyCfg::new("elaborate-drops"), - // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening - // and it can help optimizations. + // Deaggregator is necessary for const prop. We may want to consider implementing + // CTFE support for aggregates. &deaggregator::Deaggregator, &Lint(const_prop_lint::ConstProp), + &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)), + ]; + pm::run_passes_no_validate(tcx, body, passes); +} + +/// Returns the sequence of passes that do the initial cleanup of runtime MIR. +fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let passes: &[&dyn MirPass<'tcx>] = &[ + &elaborate_box_derefs::ElaborateBoxDerefs, + &lower_intrinsics::LowerIntrinsics, + &simplify::SimplifyCfg::new("elaborate-drops"), + &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)), ]; - pm::run_passes(tcx, body, post_borrowck_cleanup); + pm::run_passes(tcx, body, passes); } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -451,9 +547,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { WithMinOptLevel(1, x) } - // Lowering generator control-flow and variables has to happen before we do anything else - // to them. We run some optimizations before that, because they may be harder to do on the state - // machine than on MIR with async primitives. + // The main optimizations that we do on MIR. pm::run_passes( tcx, body, @@ -465,17 +559,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &uninhabited_enum_branching::UninhabitedEnumBranching, &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), &inline::Inline, - &generator::StateTransform, - ], - ); - - assert!(body.phase == MirPhase::GeneratorsLowered); - - // The main optimizations that we do on MIR. - pm::run_passes( - tcx, - body, - &[ &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, &const_goto::ConstGoto, @@ -507,7 +590,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &deduplicate_blocks::DeduplicateBlocks, // Some cleanup necessary at least for LLVM and potentially other codegen backends. &add_call_guards::CriticalCallEdges, - &marker::PhaseChange(MirPhase::Optimized), + &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), // Dump the end result for testing and debugging purposes. &dump_mir::Marker("PreCodegen"), ], @@ -539,8 +622,9 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), } debug!("about to call mir_drops_elaborated..."); - let mut body = + let body = tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); debug!("body: {:#?}", body); run_optimization_passes(tcx, &mut body); @@ -566,7 +650,7 @@ fn promoted_mir<'tcx>( if let Some(error_reported) = tainted_by_errors { body.tainted_by_errors = Some(error_reported); } - run_post_borrowck_cleanup_passes(tcx, body); + run_analysis_to_runtime_passes(tcx, body); } debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR"); diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index b7ba61651..9892580e6 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -46,12 +46,31 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { let mut args = args.drain(..); block.statements.push(Statement { source_info: terminator.source_info, - kind: StatementKind::CopyNonOverlapping(Box::new( - rustc_middle::mir::CopyNonOverlapping { - src: args.next().unwrap(), - dst: args.next().unwrap(), - count: args.next().unwrap(), - }, + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { + src: args.next().unwrap(), + dst: args.next().unwrap(), + count: args.next().unwrap(), + }, + ), + )), + }); + assert_eq!( + args.next(), + None, + "Extra argument for copy_non_overlapping intrinsic" + ); + drop(args); + terminator.kind = TerminatorKind::Goto { target }; + } + sym::assume => { + let target = target.unwrap(); + let mut args = args.drain(..); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::Assume(args.next().unwrap()), )), }); assert_eq!( diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index 22b6dead9..3957cd92c 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -15,7 +15,7 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // find basic blocks with no statement and a return terminator - let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); + let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks.len()); let def_id = body.source.def_id(); let bbs = body.basic_blocks_mut(); for idx in bbs.indices() { diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index c0217a105..a159e6171 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -21,10 +21,10 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // early returns for edge cases of highly unrolled functions - if body.basic_blocks().len() > MAX_NUM_BLOCKS { + if body.basic_blocks.len() > MAX_NUM_BLOCKS { return; } - if body.local_decls().len() > MAX_NUM_LOCALS { + if body.local_decls.len() > MAX_NUM_LOCALS { return; } normalize_array_len_calls(tcx, body) diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index bb063915f..4291e81c7 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -53,10 +53,10 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { def_id, returned_local ); - RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); + RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body); // Clean up the `NOP`s we inserted for statements made useless by our renaming. - for block_data in body.basic_blocks_mut() { + for block_data in body.basic_blocks.as_mut_preserves_cfg() { block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); } @@ -89,7 +89,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option { } let mut copied_to_return_place = None; - for block in body.basic_blocks().indices() { + for block in body.basic_blocks.indices() { // Look for blocks with a `Return` terminator. if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) { continue; @@ -122,7 +122,7 @@ fn find_local_assigned_to_return_place( body: &mut mir::Body<'_>, ) -> Option { let mut block = start; - let mut seen = HybridBitSet::new_empty(body.basic_blocks().len()); + let mut seen = HybridBitSet::new_empty(body.basic_blocks.len()); // Iterate as long as `block` has exactly one predecessor that we have not yet visited. while seen.insert(block) { diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index e27d4ab16..67dae7146 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use rustc_middle::mir::{self, Body, MirPhase}; +use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -72,48 +72,62 @@ where } } +/// Run the sequence of passes without validating the MIR after each pass. The MIR is still +/// validated at the end. +pub fn run_passes_no_validate<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + passes: &[&dyn MirPass<'tcx>], +) { + run_passes_inner(tcx, body, passes, false); +} + pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) { + run_passes_inner(tcx, body, passes, true); +} + +fn run_passes_inner<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + passes: &[&dyn MirPass<'tcx>], + validate_each: bool, +) { let start_phase = body.phase; let mut cnt = 0; - let validate = tcx.sess.opts.unstable_opts.validate_mir; + let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); - if validate { - validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase)); - } - for pass in passes { let name = pass.name(); - if let Some((_, polarity)) = overridden_passes.iter().rev().find(|(s, _)| s == &*name) { - trace!( - pass = %name, - "{} as requested by flag", - if *polarity { "Running" } else { "Not running" }, - ); - if !polarity { - continue; - } - } else { - if !pass.is_enabled(&tcx.sess) { - continue; - } - } - let dump_enabled = pass.is_mir_dump_enabled(); + // Gather information about what we should be doing for this pass + let overridden = + overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| { + trace!( + pass = %name, + "{} as requested by flag", + if *polarity { "Running" } else { "Not running" }, + ); + *polarity + }); + let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)); + let new_phase = pass.phase_change(); + let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some(); + let validate = (validate && is_enabled) + || new_phase == Some(MirPhase::Runtime(RuntimePhase::Optimized)); if dump_enabled { dump_mir(tcx, body, start_phase, &name, cnt, false); } - - pass.run_pass(tcx, body); - + if is_enabled { + pass.run_pass(tcx, body); + } if dump_enabled { dump_mir(tcx, body, start_phase, &name, cnt, true); cnt += 1; } - if let Some(new_phase) = pass.phase_change() { if body.phase >= new_phase { panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); @@ -121,15 +135,10 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn body.phase = new_phase; } - if validate { - validate_body(tcx, body, format!("after pass {}", pass.name())); + validate_body(tcx, body, format!("after pass {}", name)); } } - - if validate || body.phase == MirPhase::Optimized { - validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase)); - } } pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { @@ -144,7 +153,7 @@ pub fn dump_mir<'tcx>( cnt: usize, is_after: bool, ) { - let phase_index = phase as u32; + let phase_index = phase.phase_index(); mir::dump_mir( tcx, diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 5c441c5b1..f1bbf2ea7 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -51,7 +51,7 @@ impl RemoveNoopLandingPads { StatementKind::Assign { .. } | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) - | StatementKind::CopyNonOverlapping(..) + | StatementKind::Intrinsic(..) | StatementKind::Retag { .. } => { return false; } @@ -94,7 +94,7 @@ impl RemoveNoopLandingPads { let mut jumps_folded = 0; let mut landing_pads_removed = 0; - let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len()); + let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len()); // This is a post-order traversal, so that if A post-dominates B // then A will be visited before B. diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 96b715402..78b6f714a 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -35,7 +35,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops { .into_results_cursor(body); let mut to_remove = vec![]; - for (bb, block) in body.basic_blocks().iter_enumerated() { + for (bb, block) in body.basic_blocks.iter_enumerated() { let terminator = block.terminator(); let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. }) = &terminator.kind diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 827ce0c02..cc75947d9 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Constant, Location}; +use rustc_middle::mir::{Constant, ConstantKind, Location}; use rustc_middle::ty::ConstKind; pub struct RequiredConstsVisitor<'a, 'tcx> { @@ -15,8 +15,13 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { let literal = constant.literal; - if let Some(ct) = literal.const_for_ty() && let ConstKind::Unevaluated(_) = ct.kind() { - self.required_consts.push(*constant); + match literal { + ConstantKind::Ty(c) => match c.kind() { + ConstKind::Param(_) => {} + _ => bug!("only ConstKind::Param should be encountered here, got {:#?}", c), + }, + ConstantKind::Unevaluated(..) => self.required_consts.push(*constant), + ConstantKind::Val(..) => {} } } } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 4919ad400..abe6cb285 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll { } let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - RevealAllVisitor { tcx, param_env }.visit_body(body); + RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body); } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 925eb10a1..2f116aaa9 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -62,7 +62,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { pub fn separate_const_switch(body: &mut Body<'_>) -> usize { let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new(); let predecessors = body.basic_blocks.predecessors(); - 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() { + 'block_iter: for (block_id, block) in body.basic_blocks.iter_enumerated() { if let TerminatorKind::SwitchInt { discr: Operand::Copy(switch_place) | Operand::Move(switch_place), .. @@ -90,7 +90,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { let mut predecessors_left = predecessors[block_id].len(); 'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() { - let predecessor = &body.basic_blocks()[predecessor_id]; + let predecessor = &body.basic_blocks[predecessor_id]; // First we make sure the predecessor jumps // in a reasonable way @@ -249,7 +249,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) | StatementKind::StorageDead(_) - | StatementKind::CopyNonOverlapping(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => {} } } @@ -317,7 +317,7 @@ fn find_determining_place<'tcx>( | StatementKind::Retag(_, _) | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) - | StatementKind::CopyNonOverlapping(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => {} // If the discriminant is set, it is always set diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 3620e94be..882136200 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -17,8 +17,8 @@ use std::iter; use crate::util::expand_aggregate; use crate::{ - abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm, - remove_noop_landing_pads, simplify, + abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker, + pass_manager as pm, remove_noop_landing_pads, simplify, }; use rustc_middle::mir::patch::MirPatch; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; @@ -92,11 +92,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' &mut result, &[ &add_moves_for_packed_drops::AddMovesForPackedDrops, + &deref_separator::Derefer, &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("make_shim"), &add_call_guards::CriticalCallEdges, &abort_unwinding_calls::AbortUnwindingCalls, - &marker::PhaseChange(MirPhase::Const), + &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), ], ); @@ -322,6 +323,9 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) } ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), + ty::Generator(gen_def_id, substs, hir::Movability::Movable) => { + builder.generator_shim(dest, src, *gen_def_id, substs.as_generator()) + } _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty), }; @@ -387,7 +391,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { /// offset=0 will give you the index of the next BasicBlock, /// offset=1 will give the index of the next-to-next block, /// offset=-1 will give you the index of the last-created block - fn block_index_offset(&mut self, offset: usize) -> BasicBlock { + fn block_index_offset(&self, offset: usize) -> BasicBlock { BasicBlock::new(self.blocks.len() + offset) } @@ -460,49 +464,106 @@ impl<'tcx> CloneShimBuilder<'tcx> { ); } - fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) + fn clone_fields( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + target: BasicBlock, + mut unwind: BasicBlock, + tys: I, + ) -> BasicBlock where I: IntoIterator>, { - let mut previous_field = None; + // For an iterator of length n, create 2*n + 1 blocks. for (i, ity) in tys.into_iter().enumerate() { + // Each iteration creates two blocks, referred to here as block 2*i and block 2*i + 1. + // + // Block 2*i attempts to clone the field. If successful it branches to 2*i + 2 (the + // next clone block). If unsuccessful it branches to the previous unwind block, which + // is initially the `unwind` argument passed to this function. + // + // Block 2*i + 1 is the unwind block for this iteration. It drops the cloned value + // created by block 2*i. We store this block in `unwind` so that the next clone block + // will unwind to it if cloning fails. + let field = Field::new(i); let src_field = self.tcx.mk_place_field(src, field, ity); let dest_field = self.tcx.mk_place_field(dest, field, ity); - // #(2i + 1) is the cleanup block for the previous clone operation - let cleanup_block = self.block_index_offset(1); - // #(2i + 2) is the next cloning block - // (or the Return terminator if this is the last block) + let next_unwind = self.block_index_offset(1); let next_block = self.block_index_offset(2); + self.make_clone_call(dest_field, src_field, ity, next_block, unwind); + self.block( + vec![], + TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None }, + true, + ); + unwind = next_unwind; + } + // If all clones succeed then we end up here. + self.block(vec![], TerminatorKind::Goto { target }, false); + unwind + } - // BB #(2i) - // `dest.i = Clone::clone(&src.i);` - // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens. - self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block); - - // BB #(2i + 1) (cleanup) - if let Some((previous_field, previous_cleanup)) = previous_field.take() { - // Drop previous field and goto previous cleanup block. - self.block( - vec![], - TerminatorKind::Drop { - place: previous_field, - target: previous_cleanup, - unwind: None, - }, - true, - ); - } else { - // Nothing to drop, just resume. - self.block(vec![], TerminatorKind::Resume, true); - } + fn tuple_like_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) + where + I: IntoIterator>, + { + self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); + let unwind = self.block(vec![], TerminatorKind::Resume, true); + let target = self.block(vec![], TerminatorKind::Return, false); - previous_field = Some((dest_field, cleanup_block)); - } + let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys); + } - self.block(vec![], TerminatorKind::Return, false); + fn generator_shim( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + gen_def_id: DefId, + substs: GeneratorSubsts<'tcx>, + ) { + self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); + let unwind = self.block(vec![], TerminatorKind::Resume, true); + // This will get overwritten with a switch once we know the target blocks + let switch = self.block(vec![], TerminatorKind::Unreachable, false); + let unwind = self.clone_fields(dest, src, switch, unwind, substs.upvar_tys()); + let target = self.block(vec![], TerminatorKind::Return, false); + let unreachable = self.block(vec![], TerminatorKind::Unreachable, false); + let mut cases = Vec::with_capacity(substs.state_tys(gen_def_id, self.tcx).count()); + for (index, state_tys) in substs.state_tys(gen_def_id, self.tcx).enumerate() { + let variant_index = VariantIdx::new(index); + let dest = self.tcx.mk_place_downcast_unnamed(dest, variant_index); + let src = self.tcx.mk_place_downcast_unnamed(src, variant_index); + let clone_block = self.block_index_offset(1); + let start_block = self.block( + vec![self.make_statement(StatementKind::SetDiscriminant { + place: Box::new(Place::return_place()), + variant_index, + })], + TerminatorKind::Goto { target: clone_block }, + false, + ); + cases.push((index as u128, start_block)); + let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, state_tys); + } + let discr_ty = substs.discr_ty(self.tcx); + let temp = self.make_place(Mutability::Mut, discr_ty); + let rvalue = Rvalue::Discriminant(src); + let statement = self.make_statement(StatementKind::Assign(Box::new((temp, rvalue)))); + match &mut self.blocks[switch] { + BasicBlockData { statements, terminator: Some(Terminator { kind, .. }), .. } => { + statements.push(statement); + *kind = TerminatorKind::SwitchInt { + discr: Operand::Move(temp), + switch_ty: discr_ty, + targets: SwitchTargets::new(cases.into_iter(), unreachable), + }; + } + BasicBlockData { terminator: None, .. } => unreachable!(), + } } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 180f4c7dc..57d372fda 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -74,7 +74,7 @@ pub struct CfgSimplifier<'a, 'tcx> { impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { pub fn new(body: &'a mut Body<'tcx>) -> Self { - let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks()); + let mut pred_count = IndexVec::from_elem(0u32, &body.basic_blocks); // we can't use mir.predecessors() here because that counts // dead blocks, which we don't want to. @@ -263,7 +263,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let reachable = traversal::reachable_as_bitset(body); - let num_blocks = body.basic_blocks().len(); + let num_blocks = body.basic_blocks.len(); if num_blocks == reachable.count() { return; } @@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { if map.iter().any(Option::is_none) { // Update references to all vars and tmps now let mut updater = LocalUpdater { map, tcx }; - updater.visit_body(body); + updater.visit_body_preserves_cfg(body); body.local_decls.shrink_to_fit(); } @@ -499,7 +499,7 @@ impl UsedLocals { impl<'tcx> Visitor<'tcx> for UsedLocals { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match statement.kind { - StatementKind::CopyNonOverlapping(..) + StatementKind::Intrinsic(..) | StatementKind::Retag(..) | StatementKind::Coverage(..) | StatementKind::FakeRead(..) @@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) while modified { modified = false; - for data in body.basic_blocks_mut() { + for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|statement| { let keep = match &statement.kind { diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index bbfaace70..321d8c63b 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -151,7 +151,7 @@ struct OptimizationFinder<'a, 'tcx> { impl<'tcx> OptimizationFinder<'_, 'tcx> { fn find_optimizations(&self) -> Vec> { self.body - .basic_blocks() + .basic_blocks .iter_enumerated() .filter_map(|(bb_idx, bb)| { // find switch diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs index d52f1261b..baeb620ef 100644 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ b/compiler/rustc_mir_transform/src/simplify_try.rs @@ -596,7 +596,7 @@ struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> { fn find(&self) -> Vec { self.body - .basic_blocks() + .basic_blocks .iter_enumerated() .filter_map(|(bb_idx, bb)| { let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { @@ -632,7 +632,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> { let mut iter_bbs_reachable = targets_and_values .iter() - .map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target])) + .map(|target_and_value| (target_and_value, &self.body.basic_blocks[target_and_value.target])) .filter(|(_, bb)| { // Reaching `unreachable` is UB so assume it doesn't happen. bb.terminator().kind != TerminatorKind::Unreachable diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 30be64f5b..96ea15f1b 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -79,7 +79,7 @@ fn ensure_otherwise_unreachable<'tcx>( targets: &SwitchTargets, ) -> Option> { let otherwise = targets.otherwise(); - let bb = &body.basic_blocks()[otherwise]; + let bb = &body.basic_blocks[otherwise]; if bb.terminator().kind == TerminatorKind::Unreachable && bb.statements.iter().all(|s| matches!(&s.kind, StatementKind::StorageDead(_))) { @@ -102,10 +102,10 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("UninhabitedEnumBranching starting for {:?}", body.source); - for bb in body.basic_blocks().indices() { + for bb in body.basic_blocks.indices() { trace!("processing block {:?}", bb); - let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else { + let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks[bb], tcx, body) else { continue; }; diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index f916ca362..95fda2eaf 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -12,9 +12,8 @@ pub struct UnreachablePropagation; impl MirPass<'_> for UnreachablePropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt - // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code. - sess.mir_opt_level() >= 4 + // Enable only under -Zmir-opt-level=2 as this can make programs less debuggable. + sess.mir_opt_level() >= 2 } fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -38,7 +37,19 @@ impl MirPass<'_> for UnreachablePropagation { } } + // We do want do keep some unreachable blocks, but make them empty. + for bb in unreachable_blocks { + if !tcx.consider_optimizing(|| { + format!("UnreachablePropagation {:?} ", body.source.def_id()) + }) { + break; + } + + body.basic_blocks_mut()[bb].statements.clear(); + } + let replaced = !replacements.is_empty(); + for (bb, terminator_kind) in replacements { if !tcx.consider_optimizing(|| { format!("UnreachablePropagation {:?} ", body.source.def_id()) @@ -57,42 +68,55 @@ impl MirPass<'_> for UnreachablePropagation { fn remove_successors<'tcx, F>( terminator_kind: &TerminatorKind<'tcx>, - predicate: F, + is_unreachable: F, ) -> Option> where F: Fn(BasicBlock) -> bool, { - let terminator = match *terminator_kind { - TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable, - TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + let terminator = match terminator_kind { + // This will unconditionally run into an unreachable and is therefore unreachable as well. + TerminatorKind::Goto { target } if is_unreachable(*target) => TerminatorKind::Unreachable, + TerminatorKind::SwitchInt { targets, discr, switch_ty } => { let otherwise = targets.otherwise(); - let original_targets_len = targets.iter().len() + 1; - let (mut values, mut targets): (Vec<_>, Vec<_>) = - targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip(); + // If all targets are unreachable, we can be unreachable as well. + if targets.all_targets().iter().all(|bb| is_unreachable(*bb)) { + TerminatorKind::Unreachable + } else if is_unreachable(otherwise) { + // If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise) + // unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with + // the otherwise, keeping its unreachable. + // This looses information about reachability causing worse codegen. + // For example (see src/test/codegen/match-optimizes-away.rs) + // + // pub enum Two { A, B } + // pub fn identity(x: Two) -> Two { + // match x { + // Two::A => Two::A, + // Two::B => Two::B, + // } + // } + // + // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or LLVM to + // turn it into just `x` later. Without the unreachable, such a transformation would be illegal. + // If the otherwise branch is unreachable, we can delete all other unreacahble targets, as they will + // still point to the unreachable and therefore not lose reachability information. + let reachable_iter = targets.iter().filter(|(_, bb)| !is_unreachable(*bb)); - if !predicate(otherwise) { - targets.push(otherwise); - } else { - values.pop(); - } + let new_targets = SwitchTargets::new(reachable_iter, otherwise); - let retained_targets_len = targets.len(); + // No unreachable branches were removed. + if new_targets.all_targets().len() == targets.all_targets().len() { + return None; + } - if targets.is_empty() { - TerminatorKind::Unreachable - } else if targets.len() == 1 { - TerminatorKind::Goto { target: targets[0] } - } else if original_targets_len != retained_targets_len { TerminatorKind::SwitchInt { discr: discr.clone(), - switch_ty, - targets: SwitchTargets::new( - values.iter().copied().zip(targets.iter().copied()), - *targets.last().unwrap(), - ), + switch_ty: *switch_ty, + targets: new_targets, } } else { + // If the otherwise branch is reachable, we don't want to delete any unreachable branches. return None; } } diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 41ba4d4b6..59ca04ec8 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -7,11 +7,13 @@ edition = "2021" doctest = false [dependencies] -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] } tracing = "0.1" rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 68b65658c..f1a25a60d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -112,12 +112,6 @@ //! method in operand position, we treat it as a neighbor of the current //! mono item. Calls are just a special case of that. //! -//! #### Closures -//! In a way, closures are a simple case. Since every closure object needs to be -//! constructed somewhere, we can reliably discover them by observing -//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also -//! true for closures inlined from other crates. -//! //! #### Drop glue //! Drop glue mono items are introduced by MIR drop-statements. The //! generated mono item will again have drop-glue item neighbors if the @@ -128,7 +122,7 @@ //! #### Unsizing Casts //! A subtle way of introducing neighbor edges is by casting to a trait object. //! Since the resulting fat-pointer contains a reference to a vtable, we need to -//! instantiate all object-save methods of the trait, as we need to store +//! instantiate all object-safe methods of the trait, as we need to store //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. //! @@ -207,6 +201,8 @@ use std::iter; use std::ops::Range; use std::path::PathBuf; +use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit}; + #[derive(PartialEq)] pub enum MonoItemCollectionMode { Eager, @@ -417,7 +413,6 @@ fn collect_items_rec<'tcx>( // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.node); let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() }; let recursion_depth_reset; @@ -461,7 +456,7 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; if let Ok(alloc) = tcx.eval_static_initializer(def_id) { - for &id in alloc.inner().relocations().values() { + for &id in alloc.inner().provenance().values() { collect_miri(tcx, id, &mut neighbors); } } @@ -543,8 +538,6 @@ fn collect_items_rec<'tcx>( if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - - debug!("END collect_items_rec({})", starting_point.node); } /// Format instance name that is already known to be too long for rustc. @@ -604,17 +597,24 @@ fn check_recursion_limit<'tcx>( // more than the recursion limit is assumed to be causing an // infinite expansion. if !recursion_limit.value_within_limit(adjusted_recursion_depth) { + let def_span = tcx.def_span(def_id); + let def_path_str = tcx.def_path_str(def_id); let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let error = format!("reached the recursion limit while instantiating `{}`", shrunk); - let mut err = tcx.sess.struct_span_fatal(span, &error); - err.span_note( - tcx.def_span(def_id), - &format!("`{}` defined here", tcx.def_path_str(def_id)), - ); - if let Some(path) = written_to_path { - err.note(&format!("the full type name has been written to '{}'", path.display())); - } - err.emit() + let mut path = PathBuf::new(); + let was_written = if written_to_path.is_some() { + path = written_to_path.unwrap(); + Some(()) + } else { + None + }; + tcx.sess.emit_fatal(RecursionLimit { + span, + shrunk, + def_span, + def_path_str, + was_written, + path, + }); } recursion_depths.insert(def_id, recursion_depth + 1); @@ -642,16 +642,15 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // Bail out in these cases to avoid that bad user experience. if !tcx.type_length_limit().value_within_limit(type_length) { let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); - let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); - if let Some(path) = written_to_path { - diag.note(&format!("the full type name has been written to '{}'", path.display())); - } - diag.help(&format!( - "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", - type_length - )); - diag.emit() + let span = tcx.def_span(instance.def_id()); + let mut path = PathBuf::new(); + let was_written = if written_to_path.is_some() { + path = written_to_path.unwrap(); + Some(()) + } else { + None + }; + tcx.sess.emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length }); } } @@ -690,7 +689,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::CastKind::Pointer(PointerCast::Unsize), ref operand, target_ty, - ) => { + ) + | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { let target_ty = self.monomorphize(target_ty); let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.monomorphize(source_ty); @@ -699,7 +699,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { + if (target_ty.is_trait() && !source_ty.is_trait()) + || (target_ty.is_dyn_star() && !source_ty.is_dyn_star()) + { create_mono_items_for_vtable_methods( self.tcx, target_ty, @@ -768,7 +770,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ty::ConstKind::Unevaluated(ct) => { debug!(?ct); let param_env = ty::ParamEnv::reveal_all(); - match self.tcx.const_eval_resolve(param_env, ct, None) { + match self.tcx.const_eval_resolve(param_env, ct.expand(), None) { // The `monomorphize` call should have evaluated that constant already. Ok(val) => val, Err(ErrorHandled::Reported(_) | ErrorHandled::Linted) => return, @@ -781,44 +783,22 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } _ => return, }, - }; - collect_const_value(self.tcx, val, self.output); - self.visit_ty(literal.ty(), TyContext::Location(location)); - } - - #[instrument(skip(self), level = "debug")] - fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) { - debug!("visiting const {:?} @ {:?}", constant, location); - - let substituted_constant = self.monomorphize(constant); - let param_env = ty::ParamEnv::reveal_all(); - - match substituted_constant.kind() { - ty::ConstKind::Value(val) => { - let const_val = self.tcx.valtree_to_const_val((constant.ty(), val)); - collect_const_value(self.tcx, const_val, self.output) - } - ty::ConstKind::Unevaluated(unevaluated) => { - match self.tcx.const_eval_resolve(param_env, unevaluated, None) { + mir::ConstantKind::Unevaluated(uv, _) => { + let param_env = ty::ParamEnv::reveal_all(); + match self.tcx.const_eval_resolve(param_env, uv, None) { // The `monomorphize` call should have evaluated that constant already. - Ok(val) => span_bug!( - self.body.source_info(location).span, - "collection encountered the unevaluated constant {} which evaluated to {:?}", - substituted_constant, - val - ), - Err(ErrorHandled::Reported(_) | ErrorHandled::Linted) => {} + Ok(val) => val, + Err(ErrorHandled::Reported(_) | ErrorHandled::Linted) => return, Err(ErrorHandled::TooGeneric) => span_bug!( self.body.source_info(location).span, - "collection encountered polymorphic constant: {}", - substituted_constant + "collection encountered polymorphic constant: {:?}", + literal ), } } - _ => {} - } - - self.super_const(constant); + }; + collect_const_value(self.tcx, val, self.output); + MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location)); } fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { @@ -830,7 +810,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); + visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output) } mir::TerminatorKind::Drop { ref place, .. } | mir::TerminatorKind::DropAndReplace { ref place, .. } => { @@ -914,17 +894,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // but correct span? This would make the lint at least accept crate-level lint attributes. return; }; - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( LARGE_ASSIGNMENTS, lint_root, source_info.span, - |lint| { - let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes())); - err.span_label(source_info.span, "value moved from here"); - err.note(&format!(r#"The current maximum size is {}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`"#, limit.bytes())); - err.emit(); + LargeAssignmentsLint { + span: source_info.span, + size: layout.size.bytes(), + limit: limit.bytes(), }, - ); + ) } } } @@ -1027,6 +1006,11 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> return false; } + if let DefKind::Static(_) = tcx.def_kind(def_id) { + // We cannot monomorphize statics from upstream crates. + return false; + } + if !tcx.is_mir_available(def_id) { bug!("no MIR available for {:?}", def_id); } @@ -1039,10 +1023,12 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> /// them. /// /// For example, the source type might be `&SomeStruct` and the target type -/// might be `&SomeTrait` in a cast like: +/// might be `&dyn SomeTrait` in a cast like: /// +/// ```rust,ignore (not real code) /// let src: &SomeStruct = ...; -/// let target = src as &SomeTrait; +/// let target = src as &dyn SomeTrait; +/// ``` /// /// Then the output of this function would be (SomeStruct, SomeTrait) since for /// constructing the `target` fat-pointer we need the vtable for that pair. @@ -1063,8 +1049,10 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> /// for the pair of `T` (which is a trait) and the concrete type that `T` was /// originally coerced from: /// +/// ```rust,ignore (not real code) /// let src: &ComplexStruct = ...; -/// let target = src as &ComplexStruct; +/// let target = src as &ComplexStruct; +/// ``` /// /// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair /// `(SomeStruct, SomeTrait)`. @@ -1105,6 +1093,9 @@ fn find_vtable_types_for_unsizing<'tcx>( ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } + // T as dyn* Trait + (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), + (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); @@ -1132,23 +1123,18 @@ fn find_vtable_types_for_unsizing<'tcx>( } } -#[instrument(skip(tcx), level = "debug")] +#[instrument(skip(tcx), level = "debug", ret)] fn create_fn_mono_item<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, source: Span, ) -> Spanned> { - debug!("create_fn_mono_item(instance={})", instance); - let def_id = instance.def_id(); if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) { crate::util::dump_closure_profile(tcx, instance); } - let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx))); - debug!(?respanned); - - respanned + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) } /// Creates a `MonoItem` for each method that is referenced by the vtable for @@ -1293,7 +1279,7 @@ impl<'v> RootCollector<'_, 'v> { #[instrument(skip(self), level = "debug")] fn push_if_root(&mut self, def_id: LocalDefId) { if self.is_root(def_id) { - debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); + debug!("found root"); let instance = Instance::mono(self.tcx, def_id.to_def_id()); self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); @@ -1306,13 +1292,17 @@ impl<'v> RootCollector<'_, 'v> { /// the return type of `main`. This is not needed when /// the user writes their own `start` manually. fn push_extra_entry_roots(&mut self) { - let Some((main_def_id, EntryFnType::Main)) = self.entry_fn else { + let Some((main_def_id, EntryFnType::Main { .. })) = self.entry_fn else { return; }; let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { Ok(s) => s, - Err(err) => self.tcx.sess.fatal(&err), + Err(lang_item_err) => { + self.tcx + .sess + .emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() }); + } }; let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); @@ -1415,7 +1405,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte } GlobalAlloc::Memory(alloc) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &inner in alloc.inner().relocations().values() { + for &inner in alloc.inner().provenance().values() { rustc_data_structures::stack::ensure_sufficient_stack(|| { collect_miri(tcx, inner, output); }); @@ -1454,7 +1444,7 @@ fn collect_const_value<'tcx>( match value { ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { - for &id in alloc.inner().relocations().values() { + for &id in alloc.inner().provenance().values() { collect_miri(tcx, id, output); } } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs new file mode 100644 index 000000000..d5f05e790 --- /dev/null +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -0,0 +1,85 @@ +use std::path::PathBuf; + +use rustc_errors::ErrorGuaranteed; +use rustc_macros::{LintDiagnostic, SessionDiagnostic}; +use rustc_session::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::recursion_limit)] +pub struct RecursionLimit { + #[primary_span] + pub span: Span, + pub shrunk: String, + #[note] + pub def_span: Span, + pub def_path_str: String, + #[note(monomorphize::written_to_path)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::type_length_limit)] +#[help(monomorphize::consider_type_length_limit)] +pub struct TypeLengthLimit { + #[primary_span] + pub span: Span, + pub shrunk: String, + #[note(monomorphize::written_to_path)] + pub was_written: Option<()>, + pub path: PathBuf, + pub type_length: usize, +} + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::requires_lang_item)] +pub struct RequiresLangItem { + pub lang_item: String, +} + +pub struct UnusedGenericParams { + pub span: Span, + pub param_spans: Vec, + pub param_names: Vec, +} + +impl SessionDiagnostic<'_> for UnusedGenericParams { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = + handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params); + diag.set_span(self.span); + for (span, name) in self.param_spans.into_iter().zip(self.param_names) { + // FIXME: I can figure out how to do a label with a fluent string with a fixed message, + // or a label with a dynamic value in a hard-coded string, but I haven't figured out + // how to combine the two. 😢 + diag.span_label(span, format!("generic parameter `{}` is unused", name)); + } + diag + } +} + +#[derive(LintDiagnostic)] +#[diag(monomorphize::large_assignments)] +#[note] +pub struct LargeAssignmentsLint { + #[label] + pub span: Span, + pub size: u64, + pub limit: u64, +} + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::unknown_partition_strategy)] +pub struct UnknownPartitionStrategy; + +#[derive(SessionDiagnostic)] +#[diag(monomorphize::symbol_already_defined)] +pub struct SymbolAlreadyDefined { + #[primary_span] + pub span: Option, + pub symbol: String, +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index ef4560b5e..ba6ce9fd4 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,8 +1,10 @@ #![feature(array_windows)] #![feature(control_flow_enum)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -16,6 +18,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; mod collector; +mod errors; mod partitioning; mod polymorphize; mod util; @@ -32,7 +35,7 @@ fn custom_coerce_unsize_info<'tcx>( substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), }); - match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { + match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index ff2d38693..932edc667 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -108,6 +108,7 @@ use rustc_span::symbol::Symbol; use crate::collector::InliningMap; use crate::collector::{self, MonoItemCollectionMode}; +use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy}; pub struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -149,7 +150,9 @@ fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box> { match strategy { "default" => Box::new(default::DefaultPartitioning), - _ => tcx.sess.fatal("unknown partitioning strategy"), + _ => { + tcx.sess.emit_fatal(UnknownPartitionStrategy); + } } } @@ -331,13 +334,7 @@ where (span1, span2) => span1.or(span2), }; - let error_message = format!("symbol `{}` is already defined", sym1); - - if let Some(span) = span { - tcx.sess.span_fatal(span, &error_message) - } else { - tcx.sess.fatal(&error_message) - } + tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() }); } } } @@ -481,7 +478,7 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe continue; } let body = tcx.instance_mir(instance.def); - for block in body.basic_blocks() { + for block in body.basic_blocks.iter() { for statement in &block.statements { let mir::StatementKind::Coverage(_) = statement.kind else { continue }; let scope = statement.source_info.scope; diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 394843e51..71cab0232 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -9,7 +9,7 @@ use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; use rustc_index::bit_set::FiniteBitSet; use rustc_middle::mir::{ visit::{TyContext, Visitor}, - Local, LocalDecl, Location, + Constant, ConstantKind, Local, LocalDecl, Location, }; use rustc_middle::ty::{ self, @@ -22,6 +22,8 @@ use rustc_span::symbol::sym; use std::convert::TryInto; use std::ops::ControlFlow; +use crate::errors::UnusedGenericParams; + /// Provide implementations of queries relating to polymorphization analysis. pub fn provide(providers: &mut Providers) { providers.unused_generic_params = unused_generic_params; @@ -31,7 +33,6 @@ pub fn provide(providers: &mut Providers) { /// /// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all /// parameters are used). -#[instrument(level = "debug", skip(tcx))] fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, @@ -169,6 +170,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm @@ -206,22 +208,23 @@ fn emit_unused_generic_params_error<'tcx>( _ => tcx.def_span(def_id), }; - let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters"); - + let mut param_spans = Vec::new(); + let mut param_names = Vec::new(); let mut next_generics = Some(generics); while let Some(generics) = next_generics { for param in &generics.params { if unused_parameters.contains(param.index).unwrap_or(false) { debug!(?param); let def_span = tcx.def_span(param.def_id); - err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name)); + param_spans.push(def_span); + param_names.push(param.name.to_string()); } } next_generics = generics.parent.map(|did| tcx.generics_of(did)); } - err.emit(); + tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names }); } /// Visitor used to aggregate generic parameter uses. @@ -267,8 +270,15 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_const(&mut self, c: Const<'tcx>, _: Location) { - c.visit_with(self); + fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) { + match ct.literal { + ConstantKind::Ty(c) => { + c.visit_with(self); + } + ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => { + Visitor::visit_ty(self, ty, TyContext::Location(location)) + } + } } fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) { @@ -289,7 +299,26 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.unused_parameters.clear(param.index); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)}) + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) + if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => + { + assert_eq!(promoted, ()); + + self.visit_child_body(def.did, substs); + ControlFlow::CONTINUE + } + _ => c.super_visit_with(self), + } + } + + fn visit_mir_const(&mut self, constant: ConstantKind<'tcx>) -> ControlFlow { + if !constant.has_param_types_or_consts() { + return ControlFlow::CONTINUE; + } + + match constant { + ConstantKind::Ty(ct) => ct.visit_with(self), + ConstantKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p) }, _) // Avoid considering `T` unused when constants are of the form: // `>::foo::promoted[p]` if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => @@ -300,13 +329,9 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.visit_body(&promoted[p]); ControlFlow::CONTINUE } - ty::ConstKind::Unevaluated(uv) - if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) => - { - self.visit_child_body(uv.def.did, uv.substs); - ControlFlow::CONTINUE + ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => { + constant.super_visit_with(self) } - _ => c.super_visit_with(self), } } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 847e64dc2..6a4d2df1e 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -13,7 +13,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In .append(true) .open(&format!("closure_profile_{}.csv", std::process::id())) else { - eprintln!("Cound't open file for writing closure profile"); + eprintln!("Couldn't open file for writing closure profile"); return; }; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 848e142e5..63819a2f9 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -14,8 +14,6 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{edition::Edition, BytePos, Pos, Span}; -use tracing::debug; - mod tokentrees; mod unescape_error_reporting; mod unicode_chars; diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 273827864..77c4fadab 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -20,13 +20,9 @@ pub(crate) fn emit_unescape_error( range: Range, error: EscapeError, ) { - tracing::debug!( + debug!( "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", - lit, - span_with_quotes, - mode, - range, - error + lit, span_with_quotes, mode, range, error ); let last_char = || { let c = lit[range.clone()].chars().rev().next().unwrap(); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 8c087c65c..a37327f42 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,7 +4,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] @@ -63,7 +63,7 @@ pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<' pub fn parse_crate_attrs_from_file<'a>( input: &Path, sess: &'a ParseSess, -) -> PResult<'a, Vec> { +) -> PResult<'a, ast::AttrVec> { let mut parser = new_parser_from_file(sess, input, None); parser.parse_inner_attributes() } @@ -80,7 +80,7 @@ pub fn parse_crate_attrs_from_source_str( name: FileName, source: String, sess: &ParseSess, -) -> PResult<'_, Vec> { +) -> PResult<'_, ast::AttrVec> { new_parser_from_source_str(sess, name, source).parse_inner_attributes() } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index acdbddf40..5fd69b15e 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -7,8 +7,6 @@ use rustc_errors::{error_code, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use std::convert::TryInto; -use tracing::debug; - // Public for rustfmt usage #[derive(Debug)] pub enum InnerAttrPolicy<'a> { @@ -34,7 +32,7 @@ enum OuterAttributeType { impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { - let mut outer_attrs: Vec = Vec::new(); + let mut outer_attrs = ast::AttrVec::new(); let mut just_parsed_doc_comment = false; let start_pos = self.token_cursor.num_next_calls; loop { @@ -89,6 +87,7 @@ impl<'a> Parser<'a> { // Always make an outer attribute - this allows us to recover from a misplaced // inner attribute. Some(attr::mk_doc_comment( + &self.sess.attr_id_generator, comment_kind, ast::AttrStyle::Outer, data, @@ -106,7 +105,7 @@ impl<'a> Parser<'a> { break; } } - Ok(AttrWrapper::new(outer_attrs.into(), start_pos)) + Ok(AttrWrapper::new(outer_attrs, start_pos)) } /// Matches `attribute = # ! [ meta_item ]`. @@ -140,7 +139,13 @@ impl<'a> Parser<'a> { this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); } - Ok(attr::mk_attr_from_item(item, None, style, attr_sp)) + Ok(attr::mk_attr_from_item( + &self.sess.attr_id_generator, + item, + None, + style, + attr_sp, + )) } else { let token_str = pprust::token_to_string(&this.token); let msg = &format!("expected `#`, found `{token_str}`"); @@ -283,8 +288,8 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// /// Matches `inner_attrs*`. - pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { - let mut attrs: Vec = vec![]; + pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { + let mut attrs = ast::AttrVec::new(); loop { let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap(); // Only try to parse if it is an inner attribute (has `!`). @@ -293,7 +298,13 @@ impl<'a> Parser<'a> { } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style == ast::AttrStyle::Inner { self.bump(); - Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span)) + Some(attr::mk_doc_comment( + &self.sess.attr_id_generator, + comment_kind, + attr_style, + data, + self.prev_token.span, + )) } else { None } @@ -303,9 +314,9 @@ impl<'a> Parser<'a> { if let Some(attr) = attr { let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap(); // If we are currently capturing tokens, mark the location of this inner attribute. - // If capturing ends up creating a `LazyTokenStream`, we will include + // If capturing ends up creating a `LazyAttrTokenStream`, we will include // this replace range with it, removing the inner attribute from the final - // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note. + // `AttrTokenStream`. Inner attributes are stored in the parsed AST note. // During macro expansion, they are selectively inserted back into the // token stream (the first inner attribute is removed each time we invoke the // corresponding macro). diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 6c750ff42..5fdafd187 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,7 +1,7 @@ use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream}; -use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing}; +use rustc_ast::tokenstream::{AttrTokenStream, AttributesData, ToAttrTokenStream}; +use rustc_ast::tokenstream::{AttrTokenTree, DelimSpan, LazyAttrTokenStream, Spacing}; use rustc_ast::{self as ast}; use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; use rustc_errors::PResult; @@ -15,11 +15,11 @@ use std::ops::Range; /// for the attribute target. This allows us to perform cfg-expansion on /// a token stream before we invoke a derive proc-macro. /// -/// This wrapper prevents direct access to the underlying `Vec`. +/// This wrapper prevents direct access to the underlying `ast::AttrVec>`. /// Parsing code can only get access to the underlying attributes /// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`. /// This makes it difficult to accidentally construct an AST node -/// (which stores a `Vec`) without first collecting tokens. +/// (which stores an `ast::AttrVec`) without first collecting tokens. /// /// This struct has its own module, to ensure that the parser code /// cannot directly access the `attrs` field @@ -49,9 +49,10 @@ impl AttrWrapper { self.attrs } + // Prepend `self.attrs` to `attrs`. // FIXME: require passing an NT to prevent misuse of this method - pub(crate) fn prepend_to_nt_inner(self, attrs: &mut Vec) { - let mut self_attrs: Vec<_> = self.attrs.into(); + pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) { + let mut self_attrs = self.attrs; std::mem::swap(attrs, &mut self_attrs); attrs.extend(self_attrs); } @@ -87,7 +88,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. #[derive(Clone)] -struct LazyTokenStreamImpl { +struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, num_calls: usize, @@ -96,10 +97,10 @@ struct LazyTokenStreamImpl { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(LazyTokenStreamImpl, 144); +rustc_data_structures::static_assert_size!(LazyAttrTokenStreamImpl, 144); -impl CreateTokenStream for LazyTokenStreamImpl { - fn create_token_stream(&self) -> AttrAnnotatedTokenStream { +impl ToAttrTokenStream for LazyAttrTokenStreamImpl { + fn to_attr_token_stream(&self) -> AttrTokenStream { // The token produced by the final call to `{,inlined_}next` was not // actually consumed by the callback. The combination of chaining the // initial token and using `take` produces the desired result - we @@ -116,7 +117,7 @@ impl CreateTokenStream for LazyTokenStreamImpl { if !self.replace_ranges.is_empty() { let mut tokens: Vec<_> = tokens.collect(); - let mut replace_ranges = self.replace_ranges.clone(); + let mut replace_ranges = self.replace_ranges.to_vec(); replace_ranges.sort_by_key(|(range, _)| range.start); #[cfg(debug_assertions)] @@ -146,7 +147,7 @@ impl CreateTokenStream for LazyTokenStreamImpl { // start position, we ensure that any replace range which encloses // another replace range will capture the *replaced* tokens for the inner // range, not the original tokens. - for (range, new_tokens) in replace_ranges.iter().rev() { + for (range, new_tokens) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {:?}", range); // Replace ranges are only allowed to decrease the number of tokens. assert!( @@ -165,7 +166,7 @@ impl CreateTokenStream for LazyTokenStreamImpl { tokens.splice( (range.start as usize)..(range.end as usize), - new_tokens.clone().into_iter().chain(filler), + new_tokens.into_iter().chain(filler), ); } make_token_stream(tokens.into_iter(), self.break_last_token) @@ -178,7 +179,7 @@ impl CreateTokenStream for LazyTokenStreamImpl { impl<'a> Parser<'a> { /// Records all tokens consumed by the provided callback, /// including the current token. These tokens are collected - /// into a `LazyTokenStream`, and returned along with the result + /// into a `LazyAttrTokenStream`, and returned along with the result /// of the callback. /// /// Note: If your callback consumes an opening delimiter @@ -196,7 +197,7 @@ impl<'a> Parser<'a> { &mut self, attrs: AttrWrapper, force_collect: ForceCollect, - f: impl FnOnce(&mut Self, Vec) -> PResult<'a, (R, TrailingToken)>, + f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, TrailingToken)>, ) -> PResult<'a, R> { // We only bail out when nothing could possibly observe the collected tokens: // 1. We cannot be force collecting tokens (since force-collecting requires tokens @@ -212,7 +213,7 @@ impl<'a> Parser<'a> { // or `#[cfg_attr]` attributes. && !self.capture_cfg { - return Ok(f(self, attrs.attrs.into())?.0); + return Ok(f(self, attrs.attrs)?.0); } let start_token = (self.token.clone(), self.token_spacing); @@ -222,7 +223,7 @@ impl<'a> Parser<'a> { let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let replace_ranges_start = self.capture_state.replace_ranges.len(); - let ret = f(self, attrs.attrs.into()); + let ret = f(self, attrs.attrs); self.capture_state.capturing = prev_capturing; @@ -296,8 +297,8 @@ impl<'a> Parser<'a> { // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), // then extend the range of captured tokens to include it, since the parser - // was not actually bumped past it. When the `LazyTokenStream` gets converted - // into an `AttrAnnotatedTokenStream`, we will create the proper token. + // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted + // into an `AttrTokenStream`, we will create the proper token. if self.token_cursor.break_last_token { assert_eq!( trailing, @@ -315,20 +316,20 @@ impl<'a> Parser<'a> { Box::new([]) } else { // Grab any replace ranges that occur *inside* the current AST node. - // We will perform the actual replacement when we convert the `LazyTokenStream` - // to an `AttrAnnotatedTokenStream` + // We will perform the actual replacement when we convert the `LazyAttrTokenStream` + // to an `AttrTokenStream`. let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap(); self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] .iter() .cloned() - .chain(inner_attr_replace_ranges.clone().into_iter()) + .chain(inner_attr_replace_ranges.iter().cloned()) .map(|(range, tokens)| { ((range.start - start_calls)..(range.end - start_calls), tokens) }) .collect() }; - let tokens = LazyTokenStream::new(LazyTokenStreamImpl { + let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { start_token, num_calls, cursor_snapshot, @@ -352,9 +353,9 @@ impl<'a> Parser<'a> { // on the captured token stream. if self.capture_cfg && matches!(self.capture_state.capturing, Capturing::Yes) - && has_cfg_or_cfg_attr(&final_attrs) + && has_cfg_or_cfg_attr(final_attrs) { - let attr_data = AttributesData { attrs: final_attrs.to_vec().into(), tokens }; + let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; // Replace the entire AST node that we just parsed, including attributes, // with a `FlatToken::AttrTarget`. If this AST node is inside an item @@ -391,12 +392,12 @@ impl<'a> Parser<'a> { fn make_token_stream( mut iter: impl Iterator, break_last_token: bool, -) -> AttrAnnotatedTokenStream { +) -> AttrTokenStream { #[derive(Debug)] struct FrameData { // This is `None` for the first frame, `Some` for all others. open_delim_sp: Option<(Delimiter, Span)>, - inner: Vec<(AttrAnnotatedTokenTree, Spacing)>, + inner: Vec, } let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; let mut token_and_spacing = iter.next(); @@ -417,48 +418,47 @@ fn make_token_stream( open_delim, span ); let dspan = DelimSpan::from_pair(open_sp, span); - let stream = AttrAnnotatedTokenStream::new(frame_data.inner); - let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream); + let stream = AttrTokenStream::new(frame_data.inner); + let delimited = AttrTokenTree::Delimited(dspan, delim, stream); stack .last_mut() .unwrap_or_else(|| { panic!("Bottom token frame is missing for token: {:?}", token) }) .inner - .push((delimited, Spacing::Alone)); + .push(delimited); } FlatToken::Token(token) => stack .last_mut() .expect("Bottom token frame is missing!") .inner - .push((AttrAnnotatedTokenTree::Token(token), spacing)), + .push(AttrTokenTree::Token(token, spacing)), FlatToken::AttrTarget(data) => stack .last_mut() .expect("Bottom token frame is missing!") .inner - .push((AttrAnnotatedTokenTree::Attributes(data), spacing)), + .push(AttrTokenTree::Attributes(data)), FlatToken::Empty => {} } token_and_spacing = iter.next(); } let mut final_buf = stack.pop().expect("Missing final buf!"); if break_last_token { - let (last_token, spacing) = final_buf.inner.pop().unwrap(); - if let AttrAnnotatedTokenTree::Token(last_token) = last_token { + let last_token = final_buf.inner.pop().unwrap(); + if let AttrTokenTree::Token(last_token, spacing) = last_token { let unglued_first = last_token.kind.break_two_token_op().unwrap().0; // An 'unglued' token is always two ASCII characters let mut first_span = last_token.span.shrink_to_lo(); first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1)); - final_buf.inner.push(( - AttrAnnotatedTokenTree::Token(Token::new(unglued_first, first_span)), - spacing, - )); + final_buf + .inner + .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing)); } else { panic!("Unexpected last token {:?}", last_token) } } assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack); - AttrAnnotatedTokenStream::new(final_buf.inner) + AttrTokenStream::new(final_buf.inner) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a2155ac1d..be524db78 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -10,26 +10,25 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ - AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat, - PatKind, Path, PathSegment, QSelf, Ty, TyKind, + AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block, + BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, + Path, PathSegment, QSelf, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; use std::ops::{Deref, DerefMut}; use std::mem::take; use crate::parser; -use tracing::{debug, trace}; const TURBOFISH_SUGGESTION_STR: &str = "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"; @@ -38,7 +37,7 @@ const TURBOFISH_SUGGESTION_STR: &str = pub(super) fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None), + kind: PatKind::Ident(BindingAnnotation::NONE, ident, None), span: ident.span, tokens: None, }); @@ -228,13 +227,13 @@ struct MultiSugg { } impl MultiSugg { - fn emit(self, err: &mut DiagnosticBuilder<'_, G>) { + fn emit(self, err: &mut Diagnostic) { err.multipart_suggestion(&self.msg, self.patches, self.applicability); } /// Overrides individual messages and applicabilities. - fn emit_many( - err: &mut DiagnosticBuilder<'_, G>, + fn emit_many( + err: &mut Diagnostic, msg: &str, applicability: Applicability, suggestions: impl Iterator, @@ -244,7 +243,7 @@ impl MultiSugg { } #[derive(SessionDiagnostic)] -#[error(parser::maybe_report_ambiguous_plus)] +#[diag(parser::maybe_report_ambiguous_plus)] struct AmbiguousPlus { pub sum_ty: String, #[primary_span] @@ -253,7 +252,7 @@ struct AmbiguousPlus { } #[derive(SessionDiagnostic)] -#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")] +#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")] struct BadTypePlus { pub ty: String, #[primary_span] @@ -287,7 +286,7 @@ pub enum BadTypePlusSub { } #[derive(SessionDiagnostic)] -#[error(parser::maybe_recover_from_bad_qpath_stage_2)] +#[diag(parser::maybe_recover_from_bad_qpath_stage_2)] struct BadQPathStage2 { #[primary_span] #[suggestion(applicability = "maybe-incorrect")] @@ -296,7 +295,7 @@ struct BadQPathStage2 { } #[derive(SessionDiagnostic)] -#[error(parser::incorrect_semicolon)] +#[diag(parser::incorrect_semicolon)] struct IncorrectSemicolon<'a> { #[primary_span] #[suggestion_short(applicability = "machine-applicable")] @@ -307,7 +306,7 @@ struct IncorrectSemicolon<'a> { } #[derive(SessionDiagnostic)] -#[error(parser::incorrect_use_of_await)] +#[diag(parser::incorrect_use_of_await)] struct IncorrectUseOfAwait { #[primary_span] #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")] @@ -315,7 +314,7 @@ struct IncorrectUseOfAwait { } #[derive(SessionDiagnostic)] -#[error(parser::incorrect_use_of_await)] +#[diag(parser::incorrect_use_of_await)] struct IncorrectAwait { #[primary_span] span: Span, @@ -326,7 +325,7 @@ struct IncorrectAwait { } #[derive(SessionDiagnostic)] -#[error(parser::in_in_typo)] +#[diag(parser::in_in_typo)] struct InInTypo { #[primary_span] span: Span, @@ -334,6 +333,394 @@ struct InInTypo { sugg_span: Span, } +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_variable_declaration)] +pub struct InvalidVariableDeclaration { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: InvalidVariableDeclarationSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidVariableDeclarationSub { + #[suggestion( + parser::switch_mut_let_order, + applicability = "maybe-incorrect", + code = "let mut" + )] + SwitchMutLetOrder(#[primary_span] Span), + #[suggestion( + parser::missing_let_before_mut, + applicability = "machine-applicable", + code = "let mut" + )] + MissingLet(#[primary_span] Span), + #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")] + UseLetNotAuto(#[primary_span] Span), + #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")] + UseLetNotVar(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_comparison_operator)] +pub(crate) struct InvalidComparisonOperator { + #[primary_span] + pub span: Span, + pub invalid: String, + #[subdiagnostic] + pub sub: InvalidComparisonOperatorSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidComparisonOperatorSub { + #[suggestion_short( + parser::use_instead, + applicability = "machine-applicable", + code = "{correct}" + )] + Correctable { + #[primary_span] + span: Span, + invalid: String, + correct: String, + }, + #[label(parser::spaceship_operator_invalid)] + Spaceship(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_logical_operator)] +#[note] +pub(crate) struct InvalidLogicalOperator { + #[primary_span] + pub span: Span, + pub incorrect: String, + #[subdiagnostic] + pub sub: InvalidLogicalOperatorSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidLogicalOperatorSub { + #[suggestion_short( + parser::use_amp_amp_for_conjunction, + applicability = "machine-applicable", + code = "&&" + )] + Conjunction(#[primary_span] Span), + #[suggestion_short( + parser::use_pipe_pipe_for_disjunction, + applicability = "machine-applicable", + code = "||" + )] + Disjunction(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::tilde_is_not_unary_operator)] +pub(crate) struct TildeAsUnaryOperator( + #[primary_span] + #[suggestion_short(applicability = "machine-applicable", code = "!")] + pub Span, +); + +#[derive(SessionDiagnostic)] +#[diag(parser::unexpected_token_after_not)] +pub(crate) struct NotAsNegationOperator { + #[primary_span] + pub negated: Span, + pub negated_desc: String, + #[suggestion_short(applicability = "machine-applicable", code = "!")] + pub not: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::malformed_loop_label)] +pub(crate) struct MalformedLoopLabel { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "{correct_label}")] + pub span: Span, + pub correct_label: Ident, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::lifetime_in_borrow_expression)] +pub(crate) struct LifetimeInBorrowExpression { + #[primary_span] + pub span: Span, + #[suggestion(applicability = "machine-applicable", code = "")] + #[label] + pub lifetime_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::field_expression_with_generic)] +pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span); + +#[derive(SessionDiagnostic)] +#[diag(parser::macro_invocation_with_qualified_path)] +pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span); + +#[derive(SessionDiagnostic)] +#[diag(parser::unexpected_token_after_label)] +pub(crate) struct UnexpectedTokenAfterLabel( + #[primary_span] + #[label(parser::unexpected_token_after_label)] + pub Span, +); + +#[derive(SessionDiagnostic)] +#[diag(parser::require_colon_after_labeled_expression)] +#[note] +pub(crate) struct RequireColonAfterLabeledExpression { + #[primary_span] + pub span: Span, + #[label] + pub label: Span, + #[suggestion_short(applicability = "machine-applicable", code = ": ")] + pub label_end: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::do_catch_syntax_removed)] +#[note] +pub(crate) struct DoCatchSyntaxRemoved { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "try")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::float_literal_requires_integer_part)] +pub(crate) struct FloatLiteralRequiresIntegerPart { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "{correct}")] + pub span: Span, + pub correct: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_int_literal_width)] +#[help] +pub(crate) struct InvalidIntLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_base_prefix)] +#[note] +pub(crate) struct InvalidNumLiteralBasePrefix { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")] + pub span: Span, + pub fixed: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_suffix)] +#[help] +pub(crate) struct InvalidNumLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_width)] +#[help] +pub(crate) struct InvalidFloatLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_suffix)] +#[help] +pub(crate) struct InvalidFloatLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::int_literal_too_large)] +pub(crate) struct IntLiteralTooLarge { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_semicolon_before_array)] +pub(crate) struct MissingSemicolonBeforeArray { + #[primary_span] + pub open_delim: Span, + #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")] + pub semicolon: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_block_macro_segment)] +pub(crate) struct InvalidBlockMacroSegment { + #[primary_span] + pub span: Span, + #[label] + pub context: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::if_expression_missing_then_block)] +pub(crate) struct IfExpressionMissingThenBlock { + #[primary_span] + pub if_span: Span, + #[subdiagnostic] + pub sub: IfExpressionMissingThenBlockSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum IfExpressionMissingThenBlockSub { + #[help(parser::condition_possibly_unfinished)] + UnfinishedCondition(#[primary_span] Span), + #[help(parser::add_then_block)] + AddThenBlock(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::if_expression_missing_condition)] +pub(crate) struct IfExpressionMissingCondition { + #[primary_span] + #[label(parser::condition_label)] + pub if_span: Span, + #[label(parser::block_label)] + pub block_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::expected_expression_found_let)] +pub(crate) struct ExpectedExpressionFoundLet { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::expected_else_block)] +pub(crate) struct ExpectedElseBlock { + #[primary_span] + pub first_tok_span: Span, + pub first_tok: String, + #[label] + pub else_span: Span, + #[suggestion(applicability = "maybe-incorrect", code = "if ")] + pub condition_start: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::outer_attribute_not_allowed_on_if_else)] +pub(crate) struct OuterAttributeNotAllowedOnIfElse { + #[primary_span] + pub last: Span, + + #[label(parser::branch_label)] + pub branch_span: Span, + + #[label(parser::ctx_label)] + pub ctx_span: Span, + pub ctx: String, + + #[suggestion(applicability = "machine-applicable", code = "")] + pub attributes: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_in_in_for_loop)] +pub(crate) struct MissingInInForLoop { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: MissingInInForLoopSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum MissingInInForLoopSub { + // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect + #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")] + InNotOf(#[primary_span] Span), + #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")] + AddIn(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_comma_after_match_arm)] +pub(crate) struct MissingCommaAfterMatchArm { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = ",")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::catch_after_try)] +#[help] +pub(crate) struct CatchAfterTry { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::comma_after_base_struct)] +#[note] +pub(crate) struct CommaAfterBaseStruct { + #[primary_span] + pub span: Span, + #[suggestion_short(applicability = "machine-applicable", code = "")] + pub comma: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::eq_field_init)] +pub(crate) struct EqFieldInit { + #[primary_span] + pub span: Span, + #[suggestion(applicability = "machine-applicable", code = ":")] + pub eq: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::dotdotdot)] +pub(crate) struct DotDotDot { + #[primary_span] + #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] + #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::left_arrow_operator)] +pub(crate) struct LeftArrowOperator { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "< -")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::remove_let)] +pub(crate) struct RemoveLet { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::use_eq_instead)] +pub(crate) struct UseEqInstead { + #[primary_span] + #[suggestion_short(applicability = "machine-applicable", code = "=")] + pub span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. @@ -387,7 +774,7 @@ impl<'a> Parser<'a> { /// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears. pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) { *self = snapshot.parser; - self.unclosed_delims.extend(snapshot.unclosed_delims.clone()); + self.unclosed_delims.extend(snapshot.unclosed_delims); } pub fn unclosed_delims(&self) -> &[UnmatchedBrace] { @@ -555,10 +942,12 @@ impl<'a> Parser<'a> { return Ok(true); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(Delimiter::Brace) - || (t.can_begin_expr() && t != &token::Semi && t != &token::Pound) + || ((t.can_begin_expr() || t.can_begin_item()) + && t != &token::Semi + && t != &token::Pound) // Avoid triggering with too many trailing `#` in raw string. || (sm.is_multiline( - self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()) + self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()), ) && t == &token::Pound) }) && !expected.contains(&TokenType::Token(token::Comma)) { @@ -576,6 +965,14 @@ impl<'a> Parser<'a> { } } + if self.token.kind == TokenKind::EqEq + && self.prev_token.is_ident() + && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq))) + { + // Likely typo: `=` → `==` in let expr or enum item + return Err(self.sess.create_err(UseEqInstead { span: self.token.span })); + } + let expect = tokens_to_string(&expected); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { @@ -590,7 +987,7 @@ impl<'a> Parser<'a> { ) } else if expected.is_empty() { ( - format!("unexpected token: {}", actual), + format!("unexpected token: {actual}"), (self.prev_token.span, "unexpected token after this".to_string()), ) } else { @@ -603,16 +1000,29 @@ impl<'a> Parser<'a> { let mut err = self.struct_span_err(self.token.span, &msg_exp); if let TokenKind::Ident(symbol, _) = &self.prev_token.kind { - if symbol.as_str() == "public" { + if ["def", "fun", "func", "function"].contains(&symbol.as_str()) { err.span_suggestion_short( self.prev_token.span, - "write `pub` instead of `public` to make the item public", - "pub", + &format!("write `fn` instead of `{symbol}` to declare a function"), + "fn", appl, ); } } + // `pub` may be used for an item or `pub(crate)` + if self.prev_token.is_ident_named(sym::public) + && (self.token.can_begin_item() + || self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) + { + err.span_suggestion_short( + self.prev_token.span, + "write `pub` instead of `public` to make the item public", + "pub", + appl, + ); + } + // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens // there are unclosed angle brackets if self.unmatched_angle_bracket_count > 0 @@ -734,7 +1144,7 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); let path = Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None }; - let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false); + let struct_expr = snapshot.parse_struct_expr(None, path, false); let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No); return Some(match (struct_expr, block_tail) { (Ok(expr), Err(mut err)) => { @@ -1188,8 +1598,7 @@ impl<'a> Parser<'a> { outer_op.node, ); - let mk_err_expr = - |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new()))); + let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err))); match inner_op.kind { ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => { @@ -1497,7 +1906,7 @@ impl<'a> Parser<'a> { MultiSugg { msg: format!("use `{}= 1` instead", kind.op.chr()), patches: vec![ - (pre_span, format!("{{ let {} = ", tmp_var)), + (pre_span, format!("{{ let {tmp_var} = ")), (post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)), ], applicability: Applicability::HasPlaceholders, @@ -1647,7 +2056,6 @@ impl<'a> Parser<'a> { &mut self, lo: Span, await_sp: Span, - attrs: AttrVec, ) -> PResult<'a, P> { let (hi, expr, is_question) = if self.token == token::Not { // Handle `await!()`. @@ -1662,7 +2070,7 @@ impl<'a> Parser<'a> { ExprKind::Try(_) => ExprKind::Err, _ => ExprKind::Await(expr), }; - let expr = self.mk_expr(lo.to(sp), kind, attrs); + let expr = self.mk_expr(lo.to(sp), kind); self.maybe_recover_from_bad_qpath(expr) } @@ -1680,7 +2088,7 @@ impl<'a> Parser<'a> { // Handle `await { }`. // This needs to be handled separately from the next arm to avoid // interpreting `await { }?` as `?.await`. - self.parse_block_expr(None, self.token.span, BlockCheckMode::Default, AttrVec::new()) + self.parse_block_expr(None, self.token.span, BlockCheckMode::Default) } else { self.parse_expr() } @@ -1823,7 +2231,7 @@ impl<'a> Parser<'a> { err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err, AttrVec::new()) + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) } } } @@ -2334,7 +2742,7 @@ impl<'a> Parser<'a> { fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { let snapshot = self.create_snapshot_for_diagnostic(); - let param = match self.parse_const_param(vec![]) { + let param = match self.parse_const_param(AttrVec::new()) { Ok(param) => param, Err(err) => { err.cancel(); @@ -2577,7 +2985,7 @@ impl<'a> Parser<'a> { } _ => {} }, - PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, ident, None) => { match &first_pat.kind { PatKind::Ident(_, old_ident, _) => { let path = PatKind::Path( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0719a0ef0..725768c1f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,14 @@ -use super::diagnostics::SnapshotParser; +use super::diagnostics::{ + CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, + ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric, + FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock, + IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, + InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub, + LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, + MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, + NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression, + SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel, +}; use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ @@ -6,6 +16,11 @@ use super::{ SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; use crate::maybe_recover_from_interpolated_ty_qpath; +use crate::parser::diagnostics::{ + IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, + InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, + MissingCommaAfterMatchArm, +}; use core::mem; use rustc_ast::ptr::P; @@ -20,10 +35,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{ClosureBinder, StmtKind}; use rustc_ast_pretty::pprust; -use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, Diagnostic, PResult}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::SessionDiagnostic; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; @@ -45,20 +60,12 @@ macro_rules! maybe_whole_expr { token::NtPath(path) => { let path = (**path).clone(); $p.bump(); - return Ok($p.mk_expr( - $p.prev_token.span, - ExprKind::Path(None, path), - AttrVec::new(), - )); + return Ok($p.mk_expr($p.prev_token.span, ExprKind::Path(None, path))); } token::NtBlock(block) => { let block = block.clone(); $p.bump(); - return Ok($p.mk_expr( - $p.prev_token.span, - ExprKind::Block(block, None), - AttrVec::new(), - )); + return Ok($p.mk_expr($p.prev_token.span, ExprKind::Block(block, None))); } _ => {} }; @@ -120,7 +127,7 @@ impl<'a> Parser<'a> { // Special-case handling of `foo(_, _, _)` err.emit(); self.bump(); - Ok(self.mk_expr(self.prev_token.span, ExprKind::Err, AttrVec::new())) + Ok(self.mk_expr(self.prev_token.span, ExprKind::Err)) } _ => Err(err), }, @@ -225,15 +232,18 @@ impl<'a> Parser<'a> { AssocOp::Equal => "==", AssocOp::NotEqual => "!=", _ => unreachable!(), - }; - self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`")) - .span_suggestion_short( - sp, - &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg), - sugg, - Applicability::MachineApplicable, - ) - .emit(); + } + .into(); + let invalid = format!("{}=", &sugg); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: invalid.clone(), + sub: InvalidComparisonOperatorSub::Correctable { + span: sp, + invalid, + correct: sugg, + }, + }); self.bump(); } @@ -243,14 +253,15 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.struct_span_err(sp, "invalid comparison operator `<>`") - .span_suggestion_short( - sp, - "`<>` is not a valid comparison operator, use `!=`", - "!=", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: "<>".into(), + sub: InvalidComparisonOperatorSub::Correctable { + span: sp, + invalid: "<>".into(), + correct: "!=".into(), + }, + }); self.bump(); } @@ -260,12 +271,11 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.struct_span_err(sp, "invalid comparison operator `<=>`") - .span_label( - sp, - "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`", - ) - .emit(); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: "<=>".into(), + sub: InvalidComparisonOperatorSub::Spaceship(sp), + }); self.bump(); } @@ -329,11 +339,9 @@ impl<'a> Parser<'a> { | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(span, binary, AttrVec::new()) - } - AssocOp::Assign => { - self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span), AttrVec::new()) + self.mk_expr(span, binary) } + AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -348,7 +356,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(span, aopexpr, AttrVec::new()) + self.mk_expr(span, aopexpr) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { self.span_bug(span, "AssocOp should have been handled by special case") @@ -441,11 +449,19 @@ impl<'a> Parser<'a> { } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) => { - self.error_bad_logical_op("and", "&&", "conjunction"); + self.sess.emit_err(InvalidLogicalOperator { + span: self.token.span, + incorrect: "and".into(), + sub: InvalidLogicalOperatorSub::Conjunction(self.token.span), + }); (AssocOp::LAnd, span) } (None, Some((Ident { name: sym::or, span }, false))) => { - self.error_bad_logical_op("or", "||", "disjunction"); + self.sess.emit_err(InvalidLogicalOperator { + span: self.token.span, + incorrect: "or".into(), + sub: InvalidLogicalOperatorSub::Disjunction(self.token.span), + }); (AssocOp::LOr, span) } _ => return None, @@ -453,19 +469,6 @@ impl<'a> Parser<'a> { Some(source_map::respan(span, op)) } - /// Error on `and` and `or` suggesting `&&` and `||` respectively. - fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) { - self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator")) - .span_suggestion_short( - self.token.span, - &format!("use `{good}` to perform logical {english}"), - good, - Applicability::MachineApplicable, - ) - .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators") - .emit(); - } - /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) @@ -491,7 +494,7 @@ impl<'a> Parser<'a> { let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); - Ok(self.mk_expr(span, range, AttrVec::new())) + Ok(self.mk_expr(span, range)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -540,7 +543,7 @@ impl<'a> Parser<'a> { (lo, None) }; let range = this.mk_range(None, opt_end, limits); - Ok(this.mk_expr(span, range, attrs.into())) + Ok(this.mk_expr_with_attrs(span, range, attrs)) }) } @@ -553,7 +556,7 @@ impl<'a> Parser<'a> { ($this:ident, $attrs:expr, |this, _| $body:expr) => { $this.collect_tokens_for_expr($attrs, |$this, attrs| { let (hi, ex) = $body?; - Ok($this.mk_expr(lo.to(hi), ex, attrs.into())) + Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs)) }) }; } @@ -630,14 +633,7 @@ impl<'a> Parser<'a> { // Recover on `!` suggesting for bitwise negation instead. fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - self.struct_span_err(lo, "`~` cannot be used as a unary operator") - .span_suggestion_short( - lo, - "use `!` to perform bitwise not", - "!", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(TildeAsUnaryOperator(lo)); self.parse_unary_expr(lo, UnOp::Not) } @@ -663,20 +659,14 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { // Emit the error... - let not_token = self.look_ahead(1, |t| t.clone()); - self.struct_span_err( - not_token.span, - &format!("unexpected {} after identifier", super::token_descr(¬_token)), - ) - .span_suggestion_short( + let negated_token = self.look_ahead(1, |t| t.clone()); + self.sess.emit_err(NotAsNegationOperator { + negated: negated_token.span, + negated_desc: super::token_descr(&negated_token), // Span the `not` plus trailing whitespace to avoid // trailing whitespace after the `!` in our suggestion - self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)), - "use `!` to perform logical negation", - "!", - Applicability::MachineApplicable, - ) - .emit(); + not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)), + }); // ...and recover! self.parse_unary_expr(lo, UnOp::Not) @@ -705,11 +695,7 @@ impl<'a> Parser<'a> { expr_kind: fn(P, P) -> ExprKind, ) -> PResult<'a, P> { let mk_expr = |this: &mut Self, lhs: P, rhs: P| { - this.mk_expr( - this.mk_expr_sp(&lhs, lhs_span, rhs.span), - expr_kind(lhs, rhs), - AttrVec::new(), - ) + this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -737,17 +723,13 @@ impl<'a> Parser<'a> { segments[0].ident.span, ), }; - match self.parse_labeled_expr(label, AttrVec::new(), false) { + match self.parse_labeled_expr(label, false) { Ok(expr) => { type_err.cancel(); - self.struct_span_err(label.ident.span, "malformed loop label") - .span_suggestion( - label.ident.span, - "use the correct loop label format", - label.ident, - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(MalformedLoopLabel { + span: label.ident.span, + correct_label: label.ident, + }); return Ok(expr); } Err(err) => { @@ -859,7 +841,7 @@ impl<'a> Parser<'a> { ); let mut err = self.struct_span_err(span, &msg); - let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| { + let suggest_parens = |err: &mut Diagnostic| { let suggestions = vec![ (span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string()), @@ -925,15 +907,7 @@ impl<'a> Parser<'a> { } fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) { - self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes") - .span_label(lt_span, "annotated with lifetime here") - .span_suggestion( - lt_span, - "remove the lifetime annotation", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } /// Parse `mut?` or `raw [ const | mut ]`. @@ -965,18 +939,23 @@ impl<'a> Parser<'a> { &mut self, e0: P, lo: Span, - mut attrs: Vec, + mut attrs: ast::AttrVec, ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure - self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| { - expr.map(|mut expr| { - attrs.extend::>(expr.attrs.into()); - expr.attrs = attrs.into(); - expr + let res = self.parse_dot_or_call_expr_with_(e0, lo); + if attrs.is_empty() { + res + } else { + res.map(|expr| { + expr.map(|mut expr| { + attrs.extend(expr.attrs); + expr.attrs = attrs; + expr + }) }) - }) + } } fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { @@ -990,7 +969,7 @@ impl<'a> Parser<'a> { }; if has_question { // `expr?` - e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e), AttrVec::new()); + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); continue; } let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { @@ -1168,7 +1147,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span; let field = ExprKind::Field(base, Ident::new(field, span)); self.expect_no_suffix(span, "a tuple index", suffix); - self.mk_expr(lo.to(span), field, AttrVec::new()) + self.mk_expr(lo.to(span), field) } /// Parse a function call expression, `expr(...)`. @@ -1182,9 +1161,9 @@ impl<'a> Parser<'a> { }; let open_paren = self.token.span; - let mut seq = self.parse_paren_expr_seq().map(|args| { - self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args), AttrVec::new()) - }); + let mut seq = self + .parse_paren_expr_seq() + .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))); if let Some(expr) = self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot) { @@ -1258,10 +1237,13 @@ impl<'a> Parser<'a> { /// Parse an indexing expression `expr[...]`. fn parse_index_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { + let prev_span = self.prev_token.span; + let open_delim_span = self.token.span; self.bump(); // `[` let index = self.parse_expr()?; + self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?; self.expect(&token::CloseDelim(Delimiter::Bracket))?; - Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new())) + Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index))) } /// Assuming we have just parsed `.`, continue parsing into an expression. @@ -1282,19 +1264,15 @@ impl<'a> Parser<'a> { let fn_span = fn_span_lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span); - Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new())) + Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span))) } else { // Field access `expr.f` if let Some(args) = segment.args { - self.struct_span_err( - args.span(), - "field expressions cannot have generic arguments", - ) - .emit(); + self.sess.emit_err(FieldExpressionWithGeneric(args.span())); } let span = lo.to(self.prev_token.span); - Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new())) + Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident))) } } @@ -1309,10 +1287,6 @@ impl<'a> Parser<'a> { // Outer attributes are already parsed and will be // added to the return value after the fact. - // - // Therefore, prevent sub-parser from parsing - // attributes by giving them an empty "already-parsed" list. - let attrs = AttrVec::new(); // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. let lo = self.token.span; @@ -1320,13 +1294,13 @@ impl<'a> Parser<'a> { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. - self.parse_lit_expr(attrs) + self.parse_lit_expr() } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - self.parse_tuple_parens_expr(attrs) + self.parse_tuple_parens_expr() } else if self.check(&token::OpenDelim(Delimiter::Brace)) { - self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs) + self.parse_block_expr(None, lo, BlockCheckMode::Default) } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) { - self.parse_closure_expr(attrs).map_err(|mut err| { + self.parse_closure_expr().map_err(|mut err| { // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }` // then suggest parens around the lhs. if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) { @@ -1335,65 +1309,66 @@ impl<'a> Parser<'a> { err }) } else if self.check(&token::OpenDelim(Delimiter::Bracket)) { - self.parse_array_or_repeat_expr(attrs, Delimiter::Bracket) + self.parse_array_or_repeat_expr(Delimiter::Bracket) } else if self.check_path() { - self.parse_path_start_expr(attrs) + self.parse_path_start_expr() } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { - self.parse_closure_expr(attrs) + self.parse_closure_expr() } else if self.eat_keyword(kw::If) { - self.parse_if_expr(attrs) + self.parse_if_expr() } else if self.check_keyword(kw::For) { if self.choose_generics_over_qpath(1) { - self.parse_closure_expr(attrs) + self.parse_closure_expr() } else { assert!(self.eat_keyword(kw::For)); - self.parse_for_expr(None, self.prev_token.span, attrs) + self.parse_for_expr(None, self.prev_token.span) } } else if self.eat_keyword(kw::While) { - self.parse_while_expr(None, self.prev_token.span, attrs) + self.parse_while_expr(None, self.prev_token.span) } else if let Some(label) = self.eat_label() { - self.parse_labeled_expr(label, attrs, true) + self.parse_labeled_expr(label, true) } else if self.eat_keyword(kw::Loop) { let sp = self.prev_token.span; - self.parse_loop_expr(None, self.prev_token.span, attrs).map_err(|mut err| { + self.parse_loop_expr(None, self.prev_token.span).map_err(|mut err| { err.span_label(sp, "while parsing this `loop` expression"); err }) } else if self.eat_keyword(kw::Continue) { let kind = ExprKind::Continue(self.eat_label()); - Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs)) + Ok(self.mk_expr(lo.to(self.prev_token.span), kind)) } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_token.span; - self.parse_match_expr(attrs).map_err(|mut err| { + self.parse_match_expr().map_err(|mut err| { err.span_label(match_sp, "while parsing this `match` expression"); err }) } else if self.eat_keyword(kw::Unsafe) { let sp = self.prev_token.span; - self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) - .map_err(|mut err| { + self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err( + |mut err| { err.span_label(sp, "while parsing this `unsafe` expression"); err - }) + }, + ) } else if self.check_inline_const(0) { self.parse_const_block(lo.to(self.token.span), false) } else if self.is_do_catch_block() { - self.recover_do_catch(attrs) + self.recover_do_catch() } else if self.is_try_block() { self.expect_keyword(kw::Try)?; - self.parse_try_block(lo, attrs) + self.parse_try_block(lo) } else if self.eat_keyword(kw::Return) { - self.parse_return_expr(attrs) + self.parse_return_expr() } else if self.eat_keyword(kw::Break) { - self.parse_break_expr(attrs) + self.parse_break_expr() } else if self.eat_keyword(kw::Yield) { - self.parse_yield_expr(attrs) + self.parse_yield_expr() } else if self.is_do_yeet() { - self.parse_yeet_expr(attrs) + self.parse_yeet_expr() } else if self.check_keyword(kw::Let) { - self.parse_let_expr(attrs) + self.parse_let_expr() } else if self.eat_keyword(kw::Underscore) { - Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs)) + Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore)) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the @@ -1412,32 +1387,32 @@ impl<'a> Parser<'a> { if self.check_keyword(kw::Async) { if self.is_async_block() { // Check for `async {` and `async move {`. - self.parse_async_block(attrs) + self.parse_async_block() } else { - self.parse_closure_expr(attrs) + self.parse_closure_expr() } } else if self.eat_keyword(kw::Await) { - self.recover_incorrect_await_syntax(lo, self.prev_token.span, attrs) + self.recover_incorrect_await_syntax(lo, self.prev_token.span) } else { - self.parse_lit_expr(attrs) + self.parse_lit_expr() } } else { - self.parse_lit_expr(attrs) + self.parse_lit_expr() } } - fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_lit_expr(&mut self) -> PResult<'a, P> { let lo = self.token.span; match self.parse_opt_lit() { Some(literal) => { - let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal)); self.maybe_recover_from_bad_qpath(expr) } None => self.try_macro_suggestion(), } } - fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P> { let lo = self.token.span; self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; let (es, trailing_comma) = match self.parse_seq_to_end( @@ -1457,15 +1432,11 @@ impl<'a> Parser<'a> { // `(e,)` is a tuple with only one field, `e`. ExprKind::Tup(es) }; - let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind); self.maybe_recover_from_bad_qpath(expr) } - fn parse_array_or_repeat_expr( - &mut self, - attrs: AttrVec, - close_delim: Delimiter, - ) -> PResult<'a, P> { + fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `[` or other open delim @@ -1494,45 +1465,42 @@ impl<'a> Parser<'a> { ExprKind::Array(vec![first_expr]) } }; - let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind); self.maybe_recover_from_bad_qpath(expr) } - fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_path_start_expr(&mut self) -> PResult<'a, P> { let (qself, path) = if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; (Some(qself), path) } else { (None, self.parse_path(PathStyle::Expr)?) }; - let lo = path.span; // `!`, as an operator, is prefix, so we know this isn't that. - let (hi, kind) = if self.eat(&token::Not) { + let (span, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression if qself.is_some() { - self.struct_span_err(path.span, "macros cannot use qualified paths").emit(); + self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span)); } - let mac = MacCall { + let lo = path.span; + let mac = P(MacCall { path, args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, - }; - (self.prev_token.span, ExprKind::MacCall(mac)) - } else if self.check(&token::OpenDelim(Delimiter::Brace)) { - if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) { + }); + (lo.to(self.prev_token.span), ExprKind::MacCall(mac)) + } else if self.check(&token::OpenDelim(Delimiter::Brace)) && + let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path) { if qself.is_some() { self.sess.gated_spans.gate(sym::more_qualified_paths, path.span); } return expr; - } else { - (path.span, ExprKind::Path(qself, path)) - } } else { (path.span, ExprKind::Path(qself, path)) }; - let expr = self.mk_expr(lo.to(hi), kind, attrs); + let expr = self.mk_expr(span, kind); self.maybe_recover_from_bad_qpath(expr) } @@ -1540,31 +1508,30 @@ impl<'a> Parser<'a> { fn parse_labeled_expr( &mut self, label: Label, - attrs: AttrVec, mut consume_colon: bool, ) -> PResult<'a, P> { let lo = label.ident.span; let label = Some(label); let ate_colon = self.eat(&token::Colon); let expr = if self.eat_keyword(kw::While) { - self.parse_while_expr(label, lo, attrs) + self.parse_while_expr(label, lo) } else if self.eat_keyword(kw::For) { - self.parse_for_expr(label, lo, attrs) + self.parse_for_expr(label, lo) } else if self.eat_keyword(kw::Loop) { - self.parse_loop_expr(label, lo, attrs) + self.parse_loop_expr(label, lo) } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { - self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) + self.parse_block_expr(label, lo, BlockCheckMode::Default) } else if !ate_colon && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish - let msg = "expected `while`, `for`, `loop` or `{` after a label"; - self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); + self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span)); consume_colon = false; Ok(self.mk_expr_err(lo)) } else { + // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions let msg = "expected `while`, `for`, `loop` or `{` after a label"; let mut err = self.struct_span_err(self.token.span, msg); @@ -1618,10 +1585,10 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); - // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`. + // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`. let stmt = self.mk_stmt(span, StmtKind::Expr(expr)); let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span); - self.mk_expr(span, ExprKind::Block(blk, label), ThinVec::new()) + self.mk_expr(span, ExprKind::Block(blk, label)) }); err.emit(); @@ -1629,44 +1596,27 @@ impl<'a> Parser<'a> { }?; if !ate_colon && consume_colon { - self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span); + self.sess.emit_err(RequireColonAfterLabeledExpression { + span: expr.span, + label: lo, + label_end: lo.shrink_to_hi(), + }); } Ok(expr) } - fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) { - self.struct_span_err(span, "labeled expression must be followed by `:`") - .span_label(lo, "the label") - .span_suggestion_short( - lo.shrink_to_hi(), - "add `:` after the label", - ": ", - Applicability::MachineApplicable, - ) - .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them") - .emit(); - } - /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. - fn recover_do_catch(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn recover_do_catch(&mut self) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `do` self.bump(); // `catch` - let span_dc = lo.to(self.prev_token.span); - self.struct_span_err(span_dc, "found removed `do catch` syntax") - .span_suggestion( - span_dc, - "replace with the new syntax", - "try", - Applicability::MachineApplicable, - ) - .note("following RFC #2388, the new non-placeholder syntax is `try`") - .emit(); + let span = lo.to(self.prev_token.span); + self.sess.emit_err(DoCatchSyntaxRemoved { span }); - self.parse_try_block(lo, attrs) + self.parse_try_block(lo) } /// Parse an expression if the token can begin one. @@ -1675,15 +1625,15 @@ impl<'a> Parser<'a> { } /// Parse `"return" expr?`. - fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_return_expr(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); - let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind); self.maybe_recover_from_bad_qpath(expr) } /// Parse `"do" "yeet" expr?`. - fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_yeet_expr(&mut self) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `do` @@ -1693,7 +1643,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::yeet_expr, span); - let expr = self.mk_expr(span, kind, attrs); + let expr = self.mk_expr(span, kind); self.maybe_recover_from_bad_qpath(expr) } @@ -1705,13 +1655,13 @@ impl<'a> Parser<'a> { /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value /// expression only gets a warning for compatibility reasons; and a labeled break /// with a labeled loop does not even get a warning because there is no ambiguity. - fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_break_expr(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let mut label = self.eat_label(); let kind = if label.is_some() && self.token == token::Colon { // The value expression can be a labeled loop, see issue #86948, e.g.: // `loop { break 'label: loop { break 'label 42; }; }` - let lexpr = self.parse_labeled_expr(label.take().unwrap(), AttrVec::new(), true)?; + let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?; self.struct_span_err( lexpr.span, "parentheses are required around this expression to avoid confusion with a labeled break expression", @@ -1753,17 +1703,17 @@ impl<'a> Parser<'a> { } else { None }; - let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind)); self.maybe_recover_from_bad_qpath(expr) } /// Parse `"yield" expr?`. - fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { + fn parse_yield_expr(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Yield(self.parse_expr_opt()?); let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::generators, span); - let expr = self.mk_expr(span, kind, attrs); + let expr = self.mk_expr(span, kind); self.maybe_recover_from_bad_qpath(expr) } @@ -1775,8 +1725,8 @@ impl<'a> Parser<'a> { Some(lit) => match lit.kind { ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { style, - symbol: lit.token.symbol, - suffix: lit.token.suffix, + symbol: lit.token_lit.symbol, + suffix: lit.token_lit.suffix, span: lit.span, symbol_unescaped, }), @@ -1853,20 +1803,16 @@ impl<'a> Parser<'a> { let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); let lit = token::Lit::new(token::Err, symbol, lit.suffix); - Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!())) + Some(Lit::from_token_lit(lit, span).unwrap_or_else(|_| unreachable!())) } } } fn error_float_lits_must_have_int_part(&self, token: &Token) { - self.struct_span_err(token.span, "float literals must have an integer part") - .span_suggestion( - token.span, - "must have an integer part", - pprust::token_to_string(token), - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(FloatLiteralRequiresIntegerPart { + span: token.span, + correct: pprust::token_to_string(token).into_owned(), + }); } fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { @@ -1908,28 +1854,11 @@ impl<'a> Parser<'a> { let suf = suf.as_str(); if looks_like_width_suffix(&['i', 'u'], &suf) { // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for integer literal", &suf[1..]); - self.struct_span_err(span, &msg) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); + self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); } else if let Some(fixed) = fix_base_capitalisation(suf) { - let msg = "invalid base prefix for number literal"; - - self.struct_span_err(span, msg) - .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase") - .span_suggestion( - span, - "try making the prefix lowercase", - fixed, - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); } else { - let msg = format!("invalid suffix `{suf}` for number literal"); - self.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{suf}`")) - .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)") - .emit(); + self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); } } LitError::InvalidFloatSuffix => { @@ -1937,14 +1866,10 @@ impl<'a> Parser<'a> { let suf = suf.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for float literal", &suf[1..]); - self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit(); + self.sess + .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); } else { - let msg = format!("invalid suffix `{suf}` for float literal"); - self.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{suf}`")) - .help("valid suffixes are `f32` and `f64`") - .emit(); + self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); } } LitError::NonDecimalFloat(base) => { @@ -1959,7 +1884,7 @@ impl<'a> Parser<'a> { .emit(); } LitError::IntTooLarge => { - self.struct_span_err(span, "integer literal is too large").emit(); + self.sess.emit_err(IntLiteralTooLarge { span }); } } } @@ -2007,14 +1932,10 @@ impl<'a> Parser<'a> { let lo = self.token.span; let minus_present = self.eat(&token::BinOp(token::Minus)); let lit = self.parse_lit()?; - let expr = self.mk_expr(lit.span, ExprKind::Lit(lit), AttrVec::new()); + let expr = self.mk_expr(lit.span, ExprKind::Lit(lit)); if minus_present { - Ok(self.mk_expr( - lo.to(self.prev_token.span), - self.mk_unary(UnOp::Neg, expr), - AttrVec::new(), - )) + Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr))) } else { Ok(expr) } @@ -2029,13 +1950,9 @@ impl<'a> Parser<'a> { /// Emits a suggestion if it looks like the user meant an array but /// accidentally used braces, causing the code to be interpreted as a block /// expression. - fn maybe_suggest_brackets_instead_of_braces( - &mut self, - lo: Span, - attrs: AttrVec, - ) -> Option> { + fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option> { let mut snapshot = self.create_snapshot_for_diagnostic(); - match snapshot.parse_array_or_repeat_expr(attrs, Delimiter::Brace) { + match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) { Ok(arr) => { let hi = snapshot.prev_token.span; self.struct_span_err(arr.span, "this is a block expression, not an array") @@ -2056,43 +1973,76 @@ impl<'a> Parser<'a> { } } + fn suggest_missing_semicolon_before_array( + &self, + prev_span: Span, + open_delim_span: Span, + ) -> PResult<'a, ()> { + if self.token.kind == token::Comma { + if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) { + return Ok(()); + } + let mut snapshot = self.create_snapshot_for_diagnostic(); + snapshot.bump(); + match snapshot.parse_seq_to_before_end( + &token::CloseDelim(Delimiter::Bracket), + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_expr(), + ) { + Ok(_) + // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, + // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`. + // This is because the `token.kind` of the close delim is treated as the same as + // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. + // Therefore, `token.kind` should not be compared here. + if snapshot + .span_to_snippet(snapshot.token.span) + .map_or(false, |snippet| snippet == "]") => + { + return Err(MissingSemicolonBeforeArray { + open_delim: open_delim_span, + semicolon: prev_span.shrink_to_hi(), + }.into_diagnostic(&self.sess.span_diagnostic)); + } + Ok(_) => (), + Err(err) => err.cancel(), + } + } + Ok(()) + } + /// Parses a block or unsafe block. pub(super) fn parse_block_expr( &mut self, opt_label: Option { fn encode(&self, s: &mut S) { @@ -23,6 +22,19 @@ impl>> Decodable for SmallVec { } } +impl> Encodable for ThinVec { + fn encode(&self, s: &mut S) { + self.as_slice().encode(s); + } +} + +impl> Decodable for ThinVec { + fn decode(d: &mut D) -> ThinVec { + let len = d.read_usize(); + (0..len).map(|_| Decodable::decode(d)).collect() + } +} + impl> Encodable for LinkedList { fn encode(&self, s: &mut S) { s.emit_usize(self.len()); diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index e606f4273..fa9c7bd54 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -14,10 +14,13 @@ Core encoding and decoding interfaces. #![feature(min_specialization)] #![feature(core_intrinsics)] #![feature(maybe_uninit_slice)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(new_uninit)] +#![feature(allocator_api)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 36585b8d7..751b209f1 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -4,6 +4,7 @@ Core encoding and decoding interfaces. */ +use std::alloc::Allocator; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; @@ -229,9 +230,9 @@ impl Decodable for PhantomData { } } -impl> Decodable for Box<[T]> { - fn decode(d: &mut D) -> Box<[T]> { - let v: Vec = Decodable::decode(d); +impl> Decodable for Box<[T], A> { + fn decode(d: &mut D) -> Box<[T], A> { + let v: Vec = Decodable::decode(d); v.into_boxed_slice() } } @@ -264,16 +265,17 @@ impl> Encodable for Vec { } } -impl> Decodable for Vec { - default fn decode(d: &mut D) -> Vec { +impl, A: Allocator + Default> Decodable for Vec { + default fn decode(d: &mut D) -> Vec { let len = d.read_usize(); + let allocator = A::default(); // SAFETY: we set the capacity in advance, only write elements, and // only set the length at the end once the writing has succeeded. - let mut vec = Vec::with_capacity(len); + let mut vec = Vec::with_capacity_in(len, allocator); unsafe { let ptr: *mut T = vec.as_mut_ptr(); for i in 0..len { - std::ptr::write(ptr.offset(i as isize), Decodable::decode(d)); + std::ptr::write(ptr.add(i), Decodable::decode(d)); } vec.set_len(len); } @@ -457,13 +459,15 @@ impl> Decodable for Arc { } } -impl> Encodable for Box { +impl, A: Allocator + Default> Encodable for Box { fn encode(&self, s: &mut S) { - (**self).encode(s); + (**self).encode(s) } } -impl> Decodable for Box { - fn decode(d: &mut D) -> Box { - Box::new(Decodable::decode(d)) + +impl> Decodable for Box { + fn decode(d: &mut D) -> Box { + let allocator = A::default(); + Box::new_in(Decodable::decode(d), allocator) } } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 37cfc4a0d..6b1eaa4d3 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -15,6 +15,5 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } -num_cpus = "1.0" rustc_ast = { path = "../rustc_ast" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs index dd64e8ab7..2336d9936 100644 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ b/compiler/rustc_session/src/cgu_reuse_tracker.rs @@ -2,10 +2,14 @@ //! compilation. This is used for incremental compilation tests and debug //! output. +use crate::errors::{CguNotRecorded, IncorrectCguReuseType}; +use crate::Session; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_span::{Span, Symbol}; +use std::borrow::Cow; +use std::fmt::{self}; use std::sync::{Arc, Mutex}; -use tracing::debug; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub enum CguReuse { @@ -14,6 +18,22 @@ pub enum CguReuse { PostLto, } +impl fmt::Display for CguReuse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + CguReuse::No => write!(f, "No"), + CguReuse::PreLto => write!(f, "PreLto "), + CguReuse::PostLto => write!(f, "PostLto "), + } + } +} + +impl IntoDiagnosticArg for CguReuse { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum ComparisonKind { Exact, @@ -84,7 +104,7 @@ impl CguReuseTracker { } } - pub fn check_expected_reuse(&self, diag: &rustc_errors::Handler) { + pub fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { let data = data.lock().unwrap(); @@ -98,19 +118,17 @@ impl CguReuseTracker { }; if error { - let at_least = if at_least { "at least " } else { "" }; - let msg = format!( - "CGU-reuse for `{cgu_user_name}` is `{actual_reuse:?}` but \ - should be {at_least}`{expected_reuse:?}`" - ); - diag.span_err(error_span.0, &msg); + let at_least = if at_least { 1 } else { 0 }; + IncorrectCguReuseType { + span: error_span.0, + cgu_user_name: &cgu_user_name, + actual_reuse, + expected_reuse, + at_least, + }; } } else { - let msg = format!( - "CGU-reuse for `{cgu_user_name}` (mangled: `{cgu_name}`) was \ - not recorded" - ); - diag.span_fatal(error_span.0, &msg) + sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name }); } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 6a8298605..8bb3878fb 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_target::abi::{Align, TargetDataLayout}; -use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; -use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS}; +use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use crate::parse::{CrateCheckConfig, CrateConfig}; use rustc_feature::UnstableFeatures; @@ -36,6 +36,8 @@ use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; +pub mod sigpipe; + /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -798,7 +800,15 @@ impl UnstableOptions { // The type of entry function, so users can have their own entry functions #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)] pub enum EntryFnType { - Main, + Main { + /// Specifies what to do with `SIGPIPE` before calling `fn main()`. + /// + /// What values that are valid and what they mean must be in sync + /// across rustc and libstd, but we don't want it public in libstd, + /// so we take a bit of an unusual approach with simple constants + /// and an `include!()`. + sigpipe: u8, + }, Start, } @@ -888,10 +898,10 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.fatal(&err); + sess.emit_fatal(err); }); - let mut ret = FxHashSet::default(); + let mut ret = CrateConfig::default(); ret.reserve(7); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); @@ -949,7 +959,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { ret.insert((sym::debug_assertions, None)); } // JUSTIFICATION: before wrapper fn is available - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { ret.insert((sym::proc_macro, None)); } @@ -2198,7 +2208,7 @@ fn parse_remap_path_prefix( } // JUSTIFICATION: before wrapper fn is available -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn build_session_options(matches: &getopts::Matches) -> Options { let color = parse_color(matches); @@ -2379,16 +2389,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } - if cg.linker_flavor == Some(LinkerFlavor::L4Bender) - && !nightly_options::is_unstable_enabled(matches) - { - early_error( - error_format, - "`l4-bender` linker flavor is unstable, `-Z unstable-options` \ - flag must also be passed to explicitly use it", - ); - } - let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format); let cg = cg; @@ -2423,13 +2423,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let pretty = parse_pretty(&unstable_opts, error_format); - if !unstable_opts.unstable_options - && !target_triple.triple().contains("apple") - && cg.split_debuginfo.is_some() - { - early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform"); - } - // Try to find a directory containing the Rust `src`, for more details see // the doc comment on the `real_rust_source_base_dir` field. let tmp_buf; @@ -2537,7 +2530,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio ), ), }; - tracing::debug!("got unpretty option: {first:?}"); + debug!("got unpretty option: {first:?}"); Some(first) } diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs new file mode 100644 index 000000000..a5c94118a --- /dev/null +++ b/compiler/rustc_session/src/config/sigpipe.rs @@ -0,0 +1,22 @@ +//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`! + +/// Do not touch `SIGPIPE`. Use whatever the parent process uses. +#[allow(dead_code)] +pub const INHERIT: u8 = 1; + +/// Change `SIGPIPE` to `SIG_IGN` so that failed writes results in `EPIPE` +/// that are eventually converted to `ErrorKind::BrokenPipe`. +#[allow(dead_code)] +pub const SIG_IGN: u8 = 2; + +/// Change `SIGPIPE` to `SIG_DFL` so that the process is killed when trying +/// to write to a closed pipe. This is usually the desired behavior for CLI +/// apps that produce textual output that you want to pipe to other programs +/// such as `head -n 1`. +#[allow(dead_code)] +pub const SIG_DFL: u8 = 3; + +/// `SIG_IGN` has been the Rust default since 2014. See +/// . +#[allow(dead_code)] +pub const DEFAULT: u8 = SIG_IGN; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index c1fd3c7c6..7d4a1e212 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -68,6 +68,8 @@ pub enum LinkagePreference { pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, + /// If packed_bundled_libs enabled, actual filename of library is stored. + pub filename: Option, pub cfg: Option, pub foreign_module: Option, pub wasm_import_module: Option, @@ -81,10 +83,29 @@ impl NativeLib { } } +/// Different ways that the PE Format can decorate a symbol name. +/// From +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq, Eq)] +pub enum PeImportNameType { + /// IMPORT_ORDINAL + /// Uses the ordinal (i.e., a number) rather than the name. + Ordinal(u16), + /// Same as IMPORT_NAME + /// Name is decorated with all prefixes and suffixes. + Decorated, + /// Same as IMPORT_NAME_NOPREFIX + /// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept. + NoPrefix, + /// Same as IMPORT_NAME_UNDECORATE + /// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all + /// trailing characters) are skipped. + Undecorated, +} + #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, - pub ordinal: Option, + pub import_name_type: Option, /// Calling convention for the function. /// /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any @@ -92,6 +113,18 @@ pub struct DllImport { pub calling_convention: DllCallingConvention, /// Span of import's "extern" declaration; used for diagnostics. pub span: Span, + /// Is this for a function (rather than a static variable). + pub is_fn: bool, +} + +impl DllImport { + pub fn ordinal(&self) -> Option { + if let Some(PeImportNameType::Ordinal(ordinal)) = self.import_name_type { + Some(ordinal) + } else { + None + } + } } /// Calling convention for a function defined in an external library. diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs new file mode 100644 index 000000000..c6596ff24 --- /dev/null +++ b/compiler/rustc_session/src/errors.rs @@ -0,0 +1,221 @@ +use std::num::NonZeroU32; + +use crate::cgu_reuse_tracker::CguReuse; +use crate::{self as rustc_session, SessionDiagnostic}; +use rustc_errors::{fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, MultiSpan}; +use rustc_macros::SessionDiagnostic; +use rustc_span::{Span, Symbol}; +use rustc_target::abi::TargetDataLayoutErrors; +use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; + +#[derive(SessionDiagnostic)] +#[diag(session::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(SessionDiagnostic)] +#[diag(session::cgu_not_recorded)] +pub struct CguNotRecorded<'a> { + pub cgu_user_name: &'a str, + pub cgu_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(session::feature_gate_error, code = "E0658")] +pub struct FeatureGateError<'a> { + #[primary_span] + pub span: MultiSpan, + pub explain: &'a str, +} + +#[derive(SessionSubdiagnostic)] +#[note(session::feature_diagnostic_for_issue)] +pub struct FeatureDiagnosticForIssue { + pub n: NonZeroU32, +} + +#[derive(SessionSubdiagnostic)] +#[help(session::feature_diagnostic_help)] +pub struct FeatureDiagnosticHelp { + pub feature: Symbol, +} + +impl SessionDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { + fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, !> { + let mut diag; + match self { + TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { + diag = sess.struct_fatal(fluent::session::target_invalid_address_space); + diag.set_arg("addr_space", addr_space); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_bits); + diag.set_arg("kind", kind); + diag.set_arg("bit", bit); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::MissingAlignment { cause } => { + diag = sess.struct_fatal(fluent::session::target_missing_alignment); + diag.set_arg("cause", cause); + diag + } + TargetDataLayoutErrors::InvalidAlignment { cause, err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_alignment); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { + diag = sess.struct_fatal(fluent::session::target_inconsistent_architecture); + diag.set_arg("dl", dl); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { + diag = sess.struct_fatal(fluent::session::target_inconsistent_pointer_width); + diag.set_arg("pointer_size", pointer_size); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InvalidBitsSize { err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_bits_size); + diag.set_arg("err", err); + diag + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(session::not_circumvent_feature)] +pub struct NotCircumventFeature; + +#[derive(SessionDiagnostic)] +#[diag(session::linker_plugin_lto_windows_not_supported)] +pub struct LinkerPluginToWindowsNotSupported; + +#[derive(SessionDiagnostic)] +#[diag(session::profile_use_file_does_not_exist)] +pub struct ProfileUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::profile_sample_use_file_does_not_exist)] +pub struct ProfileSampleUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::target_requires_unwind_tables)] +pub struct TargetRequiresUnwindTables; + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizer_not_supported)] +pub struct SanitizerNotSupported { + pub us: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizers_not_supported)] +pub struct SanitizersNotSupported { + pub us: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::cannot_mix_and_match_sanitizers)] +pub struct CannotMixAndMatchSanitizers { + pub first: String, + pub second: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::cannot_enable_crt_static_linux)] +pub struct CannotEnableCrtStaticLinux; + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizer_cfi_enabled)] +pub struct SanitizerCfiEnabled; + +#[derive(SessionDiagnostic)] +#[diag(session::unstable_virtual_function_elimination)] +pub struct UnstableVirtualFunctionElimination; + +#[derive(SessionDiagnostic)] +#[diag(session::unsupported_dwarf_version)] +pub struct UnsupportedDwarfVersion { + pub dwarf_version: u32, +} + +#[derive(SessionDiagnostic)] +#[diag(session::target_stack_protector_not_supported)] +pub struct StackProtectorNotSupportedForTarget<'a> { + pub stack_protector: StackProtector, + pub target_triple: &'a TargetTriple, +} + +#[derive(SessionDiagnostic)] +#[diag(session::split_debuginfo_unstable_platform)] +pub struct SplitDebugInfoUnstablePlatform { + pub debuginfo: SplitDebuginfo, +} + +#[derive(SessionDiagnostic)] +#[diag(session::file_is_not_writeable)] +pub struct FileIsNotWriteable<'a> { + pub file: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_does_not_match)] +pub struct CrateNameDoesNotMatch<'a> { + #[primary_span] + pub span: Span, + pub s: &'a str, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_invalid)] +pub struct CrateNameInvalid<'a> { + pub s: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(session::crate_name_empty)] +pub struct CrateNameEmpty { + #[primary_span] + pub span: Option, +} + +pub struct InvalidCharacterInCrateName<'a> { + pub span: Option, + pub character: char, + pub crate_name: &'a str, +} + +impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> { + fn into_diagnostic( + self, + sess: &Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name); + if let Some(sp) = self.span { + diag.set_span(sp); + } + diag.set_arg("character", self.character); + diag.set_arg("crate_name", self.crate_name); + diag + } +} diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index c973e3140..e8edb38f5 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -7,7 +7,6 @@ use std::path::{Path, PathBuf}; use crate::search_paths::{PathKind, SearchPath}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -use tracing::debug; #[derive(Copy, Clone)] pub enum FileMatch { diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 7353c1ca0..f6bab775e 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,6 @@ #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(once_cell)] @@ -9,9 +9,15 @@ #![feature(map_many_mut)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; +pub mod errors; + +#[macro_use] +extern crate tracing; pub mod cgu_reuse_tracker; pub mod utils; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c20..d7f1bc0be 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -5,7 +5,7 @@ use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; use rustc_errors::LanguageIdentifier; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, }; @@ -127,11 +127,11 @@ top_level_options!( /// `CodegenOptions`, think about how it influences incremental compilation. If in /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to /// unnecessary re-compilation. - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] + #[rustc_lint_opt_ty] pub struct Options { /// The crate config requested for the session, which may be combined /// with additional crate configurations during the compile process. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")] crate_types: Vec [TRACKED], optimize: OptLevel [TRACKED], /// Include the `debug_assertions` flag in dependency tracking, since it @@ -178,9 +178,9 @@ top_level_options!( /// what rustc was invoked with, but massaged a bit to agree with /// commands like `--emit llvm-ir` which they're often incompatible with /// if we otherwise use the defaults of rustc. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field")] cli_forced_codegen_units: Option [UNTRACKED], - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] cli_forced_thinlto_off: bool [UNTRACKED], /// Remap source path prefixes in all output (messages, object files, debug, etc.). @@ -231,7 +231,7 @@ macro_rules! options { ),* ,) => ( #[derive(Clone)] - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] + #[rustc_lint_opt_ty] pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* } impl Default for $struct_name { @@ -282,7 +282,7 @@ macro_rules! options { impl Options { // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] pub fn time_passes(&self) -> bool { self.unstable_opts.time_passes || self.unstable_opts.time } @@ -290,7 +290,7 @@ impl Options { impl CodegenOptions { // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] pub fn instrument_coverage(&self) -> InstrumentCoverage { self.instrument_coverage.unwrap_or(InstrumentCoverage::Off) } @@ -382,7 +382,7 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; - pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); + pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_instrument_coverage: &str = @@ -582,7 +582,7 @@ mod parse { pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { match v.and_then(|s| s.parse().ok()) { Some(0) => { - *slot = ::num_cpus::get(); + *slot = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get); true } Some(i) => { @@ -763,8 +763,8 @@ mod parse { true } - pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavor::from_str) { + pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), _ => return false, } @@ -1091,7 +1091,7 @@ options! { ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")] code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option = (None, parse_opt_number, [UNTRACKED], @@ -1111,14 +1111,14 @@ options! { "extra data to put in each output filename"), force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], "force use of the frame pointers"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")] force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], "force use of unwind tables"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), inline_threshold: Option = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: Option = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1131,7 +1131,7 @@ options! { "a single extra argument to append to the linker invocation (can be used several times)"), link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], "extra arguments to append to the linker invocation (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")] link_dead_code: Option = (None, parse_opt_bool, [TRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], @@ -1139,14 +1139,14 @@ options! { on C toolchain installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), - linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], "linker flavor"), linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, parse_linker_plugin_lto, [TRACKED], "generate build artifacts that are compatible with linker-based LTO"), llvm_args: Vec = (Vec::new(), parse_list, [TRACKED], "a list of arguments to pass to LLVM (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED], "perform LLVM link-time optimizations"), metadata: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1163,10 +1163,10 @@ options! { "disable LLVM's SLP vectorization pass"), opt_level: String = ("0".to_string(), parse_string, [TRACKED], "optimization level (0-3, s, or z; default: 0)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field")] overflow_checks: Option = (None, parse_opt_bool, [TRACKED], "use overflow checks for integer arithmetic"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field")] panic: Option = (None, parse_opt_panic_strategy, [TRACKED], "panic strategy to compile crate with"), passes: Vec = (Vec::new(), parse_list, [TRACKED], @@ -1178,7 +1178,7 @@ options! { "compile the program with profiling instrumentation"), profile_use: Option = (None, parse_opt_pathbuf, [TRACKED], "use the given `.profdata` file for profile-guided optimization"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field")] relocation_model: Option = (None, parse_relocation_model, [TRACKED], "control generation of position-independent code (PIC) \ (`rustc --print relocation-models` for details)"), @@ -1190,7 +1190,7 @@ options! { "save all temporary output files during compilation (default: no)"), soft_float: bool = (false, parse_bool, [TRACKED], "use soft float ABI (*eabihf targets only) (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], @@ -1226,13 +1226,13 @@ options! { "encode MIR of all functions into the crate metadata (default: no)"), assume_incomplete_release: bool = (false, parse_bool, [TRACKED], "make cfg(version) treat the current version as incomplete (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")] asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior) (default: no)"), assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ (default: no)"), @@ -1310,7 +1310,9 @@ options! { "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")] fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), @@ -1343,6 +1345,8 @@ options! { "hash spans relative to their parent item for incr. comp. (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify incr. comp. hashes of green query instances (default: no)"), + inline_llvm: bool = (true, parse_bool, [TRACKED], + "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], "enable MIR inlining (default: no)"), inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED], @@ -1353,7 +1357,7 @@ options! { "control whether `#[inline]` functions are in all CGUs"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: Option = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1362,7 +1366,7 @@ options! { `=except-unused-generics` `=except-unused-functions` `=off` (default)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_mcount` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_mcount` instead of this field")] instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], @@ -1386,7 +1390,7 @@ options! { merge_functions: Option = (None, parse_merge_functions, [TRACKED], "control the operation of the MergeFunctions LLVM pass, taking \ the same values as the target option of the same name"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::meta_stats` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::meta_stats` instead of this field")] meta_stats: bool = (false, parse_bool, [UNTRACKED], "gather metadata statistics (default: no)"), mir_emit_retag: bool = (false, parse_bool, [TRACKED], @@ -1398,7 +1402,7 @@ options! { disabled by other flags as usual."), mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED], "use line numbers relative to the function in mir pretty printing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), move_size_limit: Option = (None, parse_opt_number, [TRACKED], @@ -1437,6 +1441,8 @@ options! { "pass `-install_name @rpath/...` to the macOS linker (default: no)"), diagnostic_width: Option = (None, parse_opt_number, [UNTRACKED], "set the current output width for diagnostic truncation"), + packed_bundled_libs: bool = (false, parse_bool, [TRACKED], + "change rlib format to store native libraries as archives"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], "support compiling tests with panic=abort (default: no)"), panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], @@ -1465,7 +1471,7 @@ options! { See #77382 and #74551."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::print_llvm_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::print_llvm_passes` instead of this field")] print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], @@ -1543,7 +1549,7 @@ options! { "exclude spans when debug-printing compiler state (default: no)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), strict_init_checks: bool = (false, parse_bool, [TRACKED], @@ -1564,7 +1570,7 @@ options! { symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), temps_dir: Option = (None, parse_opt_string, [UNTRACKED], @@ -1580,7 +1586,7 @@ options! { "emit directionality isolation markers in translated diagnostics"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] thinlto: Option = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), thir_unsafeck: bool = (false, parse_bool, [TRACKED], @@ -1589,19 +1595,19 @@ options! { /// a sequential compiler for now. This'll likely be adjusted /// in the future. Note that -Zthreads=0 is the way to get /// the num_cpus behavior. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")] threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field")] time: bool = (false, parse_bool, [UNTRACKED], "measure time of rustc processes (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field")] time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each LLVM pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field")] time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] tls_model: Option = (None, parse_tls_model, [TRACKED], "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], @@ -1636,17 +1642,17 @@ options! { "enable unsound and buggy MIR optimizations (default: no)"), /// This name is kind of confusing: Most unstable options enable something themselves, while /// this just allows "normal" options to be feature-gated. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")] unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verbose` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::verbose` instead of this field")] verbose: bool = (false, parse_bool, [UNTRACKED], "in general, enable more debug printouts (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] verify_llvm_ir: bool = (false, parse_bool, [TRACKED], "verify LLVM IR (default: no)"), virtual_function_elimination: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index e5e6579d7..2511bee46 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,5 +1,9 @@ //! Related to out filenames of compilation (e.g. save analysis, binaries). use crate::config::{CrateType, Input, OutputFilenames, OutputType}; +use crate::errors::{ + CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + InvalidCharacterInCrateName, +}; use crate::Session; use rustc_ast as ast; use rustc_span::symbol::sym; @@ -30,11 +34,7 @@ pub fn out_filename( /// read-only file. We should be consistent. pub fn check_file_is_writeable(file: &Path, sess: &Session) { if !is_writeable(file) { - sess.fatal(&format!( - "output file {} is not writeable -- check its \ - permissions", - file.display() - )); + sess.emit_fatal(FileIsNotWriteable { file }); } } @@ -61,11 +61,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { if name.as_str() != s { - let msg = format!( - "`--crate-name` and `#[crate_name]` are \ - required to match, but `{s}` != `{name}`" - ); - sess.span_err(attr.span, &msg); + sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name }); } } return validate(s.clone(), None); @@ -77,11 +73,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Input::File(ref path) = *input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { if s.starts_with('-') { - let msg = format!( - "crate names cannot start with a `-`, but \ - `{s}` has a leading hyphen" - ); - sess.err(&msg); + sess.emit_err(CrateNameInvalid { s }); } else { return validate(s.replace('-', "_"), None); } @@ -94,15 +86,9 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { let mut err_count = 0; { - let mut say = |s: &str| { - match sp { - Some(sp) => sess.span_err(sp, s), - None => sess.err(s), - }; - err_count += 1; - }; if s.is_empty() { - say("crate name must not be empty"); + err_count += 1; + sess.emit_err(CrateNameEmpty { span: sp }); } for c in s.chars() { if c.is_alphanumeric() { @@ -111,7 +97,8 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { if c == '_' { continue; } - say(&format!("invalid character `{c}` in crate name: `{s}`")); + err_count += 1; + sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s }); } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f31d52147..0389b2a06 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -2,15 +2,18 @@ //! It also serves as an input to the parser itself. use crate::config::CheckCfg; -use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; +use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError}; +use crate::lint::{ + builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId, +}; use crate::SessionDiagnostic; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ - error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, ErrorGuaranteed, MultiSpan, + fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, + DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -18,11 +21,12 @@ use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{Span, Symbol}; +use rustc_ast::attr::AttrIdGenerator; use std::str; /// The set of keys (and, optionally, values) that define the compilation /// environment of the crate, used to drive conditional compilation. -pub type CrateConfig = FxHashSet<(Symbol, Option)>; +pub type CrateConfig = FxIndexSet<(Symbol, Option)>; pub type CrateCheckConfig = CheckCfg; /// Collected spans during parsing for places where a certain feature was @@ -101,11 +105,60 @@ pub fn feature_err_issue<'a>( issue: GateIssue, explain: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658)); + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + sess.span_diagnostic + .steal_diagnostic(span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); + } + + let mut err = sess.create_err(FeatureGateError { span, explain }); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); err } +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explain: &str) { + feature_warn_issue(sess, feature, span, GateIssue::Language, explain); +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. +#[allow(rustc::diagnostic_outside_of_impl)] +#[allow(rustc::untranslatable_diagnostic)] +pub fn feature_warn_issue<'a>( + sess: &'a ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + let mut err = sess.span_diagnostic.struct_span_warn(span, explain); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); + + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level + let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; + let future_incompatible = lint.future_incompatible.as_ref().unwrap(); + err.code(DiagnosticId::Lint { + name: lint.name_lower(), + has_future_breakage: false, + is_force_warn: false, + }); + err.warn(lint.desc); + err.note(format!("for more information, see {}", future_incompatible.reference)); + + // A later feature_err call can steal and cancel this warning. + err.stash(span, StashKey::EarlySyntaxWarning); +} + /// Adds the diagnostics for a feature to an existing error. pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language); @@ -123,14 +176,12 @@ pub fn add_feature_diagnostics_for_issue<'a>( issue: GateIssue, ) { if let Some(n) = find_feature_issue(feature, issue) { - err.note(&format!( - "see issue #{n} for more information" - )); + err.subdiagnostic(FeatureDiagnosticForIssue { n }); } // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.unstable_features.is_nightly_build() { - err.help(&format!("add `#![feature({feature})]` to the crate attributes to enable")); + err.subdiagnostic(FeatureDiagnosticHelp { feature }); } } @@ -169,6 +220,8 @@ pub struct ParseSess { /// Spans passed to `proc_macro::quote_span`. Each span has a numerical /// identifier represented by its position in the vector. pub proc_macro_quoted_spans: Lock>, + /// Used to generate new `AttrId`s. Every `AttrId` is unique. + pub attr_id_generator: AttrIdGenerator, } impl ParseSess { @@ -191,7 +244,7 @@ impl ParseSess { Self { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(None), - config: FxHashSet::default(), + config: FxIndexSet::default(), check_config: CrateCheckConfig::default(), edition: ExpnId::root().expn_data().edition, raw_identifier_spans: Lock::new(Vec::new()), @@ -207,6 +260,7 @@ impl ParseSess { type_ascription_path_suggestions: Default::default(), assume_incomplete_release: false, proc_macro_quoted_spans: Default::default(), + attr_id_generator: AttrIdGenerator::new(), } } @@ -293,7 +347,7 @@ impl ParseSess { &'a self, err: impl SessionDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(self) + err.into_diagnostic(&self.span_diagnostic) } pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { @@ -304,14 +358,27 @@ impl ParseSess { &'a self, warning: impl SessionDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self) + warning.into_diagnostic(&self.span_diagnostic) } pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { self.create_warning(warning).emit() } + pub fn create_fatal<'a>( + &'a self, + fatal: impl SessionDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + fatal.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! { + self.create_fatal(fatal).emit() + } + #[rustc_lint_diagnostics] + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] pub fn struct_err( &self, msg: impl Into, @@ -320,7 +387,26 @@ impl ParseSess { } #[rustc_lint_diagnostics] + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.span_diagnostic.struct_warn(msg) } + + #[rustc_lint_diagnostics] + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { + self.span_diagnostic.struct_fatal(msg) + } + + #[rustc_lint_diagnostics] + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + pub fn struct_diagnostic( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, G> { + self.span_diagnostic.struct_diagnostic(msg) + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9669287b3..a001f87db 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -2,6 +2,13 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; +use crate::errors::{ + CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, + NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, + SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, + TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, +}; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -20,8 +27,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, - ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, + error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + EmissionGuarantee, ErrorGuaranteed, FluentBundle, Handler, LazyFallbackBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -31,7 +38,7 @@ use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ - SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, + DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, }; use std::cell::{self, RefCell}; @@ -110,6 +117,12 @@ impl Mul for Limit { } } +impl rustc_errors::IntoDiagnosticArg for Limit { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct Limits { /// The maximum recursion limit for potentially infinitely recursive @@ -214,9 +227,9 @@ pub struct PerfStats { /// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. #[rustc_diagnostic_item = "SessionDiagnostic"] pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { - /// Write out as a diagnostic out of `sess`. + /// Write out as a diagnostic out of `Handler`. #[must_use] - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>; + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; } impl Session { @@ -229,6 +242,9 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. + // FIXME(#100717): needs eager translation/lists + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] let mut diag = self.struct_warn("skipping const checks"); for &(span, feature_gate) in unleashed_features.iter() { // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. @@ -244,10 +260,7 @@ impl Session { // If we should err, make sure we did. if must_err && self.has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. - self.err( - "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \ - gates, except when testing error paths in the CTFE engine", - ); + self.emit_err(NotCircumventFeature); } } } @@ -284,6 +297,8 @@ impl Session { } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn>( &self, sp: S, @@ -292,6 +307,8 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_expectation>( &self, sp: S, @@ -301,6 +318,8 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -310,10 +329,14 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_expectation( &self, msg: impl Into, @@ -322,6 +345,8 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_allow>( &self, sp: S, @@ -330,10 +355,14 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_expect( &self, msg: impl Into, @@ -342,6 +371,8 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err>( &self, sp: S, @@ -350,6 +381,8 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err_with_code>( &self, sp: S, @@ -360,6 +393,8 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err( &self, msg: impl Into, @@ -367,6 +402,8 @@ impl Session { self.parse_sess.struct_err(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err_with_code( &self, msg: impl Into, @@ -375,6 +412,8 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_code( &self, msg: impl Into, @@ -383,6 +422,8 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal>( &self, sp: S, @@ -391,6 +432,8 @@ impl Session { self.diagnostic().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal_with_code>( &self, sp: S, @@ -400,15 +443,21 @@ impl Session { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { self.diagnostic().span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal_with_code>( &self, sp: S, @@ -418,10 +467,14 @@ impl Session { self.diagnostic().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn fatal(&self, msg: impl Into) -> ! { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_or_warn>( &self, is_warning: bool, @@ -435,6 +488,8 @@ impl Session { } } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err>( &self, sp: S, @@ -443,6 +498,8 @@ impl Session { self.diagnostic().span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_with_code>( &self, sp: S, @@ -467,6 +524,9 @@ impl Session { feature: Symbol, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = self.parse_sess.create_err(err); + if err.code.is_none() { + err.code = std::option::Option::Some(error_code!(E0658)); + } add_feature_diagnostics(&mut err, &self.parse_sess, feature); err } @@ -482,6 +542,15 @@ impl Session { pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_fatal<'a>( + &'a self, + fatal: impl SessionDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + self.parse_sess.create_fatal(fatal) + } + pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! { + self.parse_sess.emit_fatal(fatal) + } #[inline] pub fn err_count(&self) -> usize { self.diagnostic().err_count() @@ -516,9 +585,13 @@ impl Session { Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) } } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn>(&self, sp: S, msg: impl Into) { self.diagnostic().span_warn(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn_with_code>( &self, sp: S, @@ -567,6 +640,8 @@ impl Session { ) { self.diagnostic().span_note_without_error(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_note_without_error( &self, msg: impl Into, @@ -638,7 +713,7 @@ impl Session { let found_positive = requested_features.clone().any(|r| r == "+crt-static"); // JUSTIFICATION: necessary use of crate_types directly (see FIXME below) - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] if found_positive || found_negative { found_positive } else if crate_type == Some(CrateType::ProcMacro) @@ -661,8 +736,9 @@ impl Session { ) } + /// Returns `true` if the target can use the current split debuginfo configuration. pub fn target_can_use_split_dwarf(&self) -> bool { - !self.target.is_like_windows && !self.target.is_like_osx + self.target.debuginfo_kind == DebuginfoKind::Dwarf } pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { @@ -894,7 +970,7 @@ impl Session { } // JUSTIFICATION: defn of the suggested wrapper fns -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] impl Session { pub fn verbose(&self) -> bool { self.opts.unstable_opts.verbose @@ -1174,7 +1250,7 @@ impl Session { } // JUSTIFICATION: part of session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] fn default_emitter( sopts: &config::Options, registry: rustc_errors::registry::Registry, @@ -1260,7 +1336,7 @@ pub enum DiagnosticOutput { } // JUSTIFICATION: literally session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn build_session( sopts: config::Options, local_crate_source_file: Option, @@ -1277,10 +1353,8 @@ pub fn build_session( let warnings_allow = sopts .lint_opts .iter() - .filter(|&&(ref key, _)| *key == "warnings") - .map(|&(_, ref level)| *level == lint::Allow) - .last() - .unwrap_or(false); + .rfind(|&&(ref key, _)| *key == "warnings") + .map_or(false, |&(_, level)| level == lint::Allow); let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow); @@ -1437,7 +1511,7 @@ pub fn build_session( /// If it is useful to have a Session available already for validating a commandline argument, you /// can do so here. // JUSTIFICATION: needs to access args to validate them -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] fn validate_commandline_args_with_session_available(sess: &Session) { // Since we don't know if code in an rlib will be linked to statically or // dynamically downstream, rustc generates `__imp_` symbols that help linkers @@ -1450,40 +1524,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) { && sess.opts.cg.prefer_dynamic && sess.target.is_like_windows { - sess.err( - "Linker plugin based LTO is not supported together with \ - `-C prefer-dynamic` when targeting Windows-like targets", - ); + sess.emit_err(LinkerPluginToWindowsNotSupported); } // Make sure that any given profiling data actually exists so LLVM can't // decide to silently skip PGO. if let Some(ref path) = sess.opts.cg.profile_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileUseFileDoesNotExist { path }); } } // Do the same for sample profile data. if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-sample-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileSampleUseFileDoesNotExist { path }); } } // Unwind tables cannot be disabled if the target requires them. if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { if sess.target.requires_uwtable && !include_uwtables { - sess.err( - "target requires unwind tables, they cannot be disabled with \ - `-C force-unwind-tables=no`.", - ); + sess.emit_err(TargetRequiresUnwindTables); } } @@ -1493,56 +1555,56 @@ fn validate_commandline_args_with_session_available(sess: &Session) { match unsupported_sanitizers.into_iter().count() { 0 => {} 1 => { - sess.err(&format!( - "{} sanitizer is not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() }); } _ => { - sess.err(&format!( - "{} sanitizers are not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() }); } } // Cannot mix and match sanitizers. let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter(); if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) { - sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`")); + sess.emit_err(CannotMixAndMatchSanitizers { + first: first.to_string(), + second: second.to_string(), + }); } // Cannot enable crt-static with sanitizers on Linux if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() { - sess.err( - "sanitizer is incompatible with statically linked libc, \ - disable it using `-C target-feature=-crt-static`", - ); + sess.emit_err(CannotEnableCrtStaticLinux); } // LLVM CFI and VFE both require LTO. if sess.lto() != config::Lto::Fat { if sess.is_sanitizer_cfi_enabled() { - sess.err("`-Zsanitizer=cfi` requires `-Clto`"); + sess.emit_err(SanitizerCfiEnabled); } if sess.opts.unstable_opts.virtual_function_elimination { - sess.err("`-Zvirtual-function-elimination` requires `-Clto`"); + sess.emit_err(UnstableVirtualFunctionElimination); } } if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { - sess.warn(&format!( - "`-Z stack-protector={}` is not supported for target {} and will be ignored", - sess.opts.unstable_opts.stack_protector, sess.opts.target_triple - )) + sess.emit_warning(StackProtectorNotSupportedForTarget { + stack_protector: sess.opts.unstable_opts.stack_protector, + target_triple: &sess.opts.target_triple, + }); } } if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { if dwarf_version > 5 { - sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version)); + sess.emit_err(UnsupportedDwarfVersion { dwarf_version }); } } + + if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo()) + && !sess.opts.unstable_opts.unstable_options + { + sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() }); + } } /// Holds data on the current incremental compilation session, if there is one. @@ -1586,14 +1648,20 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler rustc_errors::Handler::with_emitter(true, None, emitter) } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed { early_error_handler(output).struct_err(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { early_error_handler(output).struct_fatal(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(output: config::ErrorOutputType, msg: &str) { early_error_handler(output).struct_warn(msg).emit() } diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 5c7aaf35b..3e93c6bba 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -11,6 +11,8 @@ test(attr(allow(unused_variables), deny(warnings))) )] #![cfg_attr(not(feature = "default"), feature(rustc_private))] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] pub mod mir; diff --git a/compiler/rustc_smir/src/mir.rs b/compiler/rustc_smir/src/mir.rs index 855605b1a..887e65729 100644 --- a/compiler/rustc_smir/src/mir.rs +++ b/compiler/rustc_smir/src/mir.rs @@ -1,10 +1,10 @@ +pub use crate::very_unstable::hir::ImplicitSelfKind; pub use crate::very_unstable::middle::mir::{ visit::MutVisitor, AggregateKind, AssertKind, BasicBlock, BasicBlockData, BinOp, BindingForm, BlockTailInfo, Body, BorrowKind, CastKind, ClearCrossCrate, Constant, ConstantKind, - CopyNonOverlapping, Coverage, FakeReadCause, Field, GeneratorInfo, ImplicitSelfKind, - InlineAsmOperand, Local, LocalDecl, LocalInfo, LocalKind, Location, MirPhase, MirSource, - NullOp, Operand, Place, PlaceRef, ProjectionElem, ProjectionKind, Promoted, RetagKind, Rvalue, - Safety, SourceInfo, SourceScope, SourceScopeData, SourceScopeLocalData, Statement, - StatementKind, UnOp, UserTypeProjection, UserTypeProjections, VarBindingForm, VarDebugInfo, - VarDebugInfoContents, + CopyNonOverlapping, Coverage, FakeReadCause, Field, GeneratorInfo, InlineAsmOperand, Local, + LocalDecl, LocalInfo, LocalKind, Location, MirPhase, MirSource, NullOp, Operand, Place, + PlaceRef, ProjectionElem, ProjectionKind, Promoted, RetagKind, Rvalue, Safety, SourceInfo, + SourceScope, SourceScopeData, SourceScopeLocalData, Statement, StatementKind, UnOp, + UserTypeProjection, UserTypeProjections, VarBindingForm, VarDebugInfo, VarDebugInfoContents, }; diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index a1533fe46..37b8371a8 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -305,6 +305,12 @@ impl DefId { } } +impl From for DefId { + fn from(local: LocalDefId) -> DefId { + local.to_def_id() + } +} + impl Encodable for DefId { default fn encode(&self, s: &mut E) { self.krate.encode(s); @@ -331,7 +337,7 @@ impl fmt::Debug for DefId { } } -rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId); +rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefIdMapEntry, DefId); /// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since /// we encode this information in the type, we can ensure at compile time that @@ -393,7 +399,12 @@ impl Decodable for LocalDefId { } } -rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId); +rustc_data_structures::define_id_collections!( + LocalDefIdMap, + LocalDefIdSet, + LocalDefIdMapEntry, + LocalDefId +); impl HashStable for DefId { #[inline] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e169d3c7c..191186af6 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -41,7 +41,6 @@ use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::hash::Hash; -use tracing::*; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -945,12 +944,6 @@ pub struct ExpnData { /// internally without forcing the whole crate to opt-in /// to them. pub allow_internal_unstable: Option>, - /// Whether the macro is allowed to use `unsafe` internally - /// even if the user crate has `#![forbid(unsafe_code)]`. - pub allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) - /// for a given macro. - pub local_inner_macros: bool, /// Edition of the crate in which the macro is defined. pub edition: Edition, /// The `DefId` of the macro being invoked, @@ -958,6 +951,13 @@ pub struct ExpnData { pub macro_def_id: Option, /// The normal module (`mod`) in which the expanded macro was defined. pub parent_module: Option, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other + /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? + pub collapse_debuginfo: bool, } impl !PartialEq for ExpnData {} @@ -970,11 +970,12 @@ impl ExpnData { call_site: Span, def_site: Span, allow_internal_unstable: Option>, - allow_internal_unsafe: bool, - local_inner_macros: bool, edition: Edition, macro_def_id: Option, parent_module: Option, + allow_internal_unsafe: bool, + local_inner_macros: bool, + collapse_debuginfo: bool, ) -> ExpnData { ExpnData { kind, @@ -982,12 +983,13 @@ impl ExpnData { call_site, def_site, allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe, + local_inner_macros, + collapse_debuginfo, } } @@ -1005,12 +1007,13 @@ impl ExpnData { call_site, def_site: DUMMY_SP, allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe: false, + local_inner_macros: false, + collapse_debuginfo: false, } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index cf3069281..da31b3462 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -15,11 +15,13 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(if_let_guard)] #![feature(negative_impls)] #![feature(min_specialization)] #![feature(rustc_attrs)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; @@ -74,8 +76,6 @@ use md5::Md5; use sha1::Sha1; use sha2::Sha256; -use tracing::debug; - #[cfg(test)] mod tests; @@ -558,12 +558,25 @@ impl Span { self.data_untracked().is_dummy() } - /// Returns `true` if this span comes from a macro or desugaring. + /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { self.ctxt() != SyntaxContext::root() } + /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be + /// collapsed. + pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo + } + + /// Returns `true` if this span comes from MIR inlining. + pub fn is_inlined(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Inlined) + } + /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) @@ -662,6 +675,16 @@ impl Span { Some(self) } + /// Like `find_ancestor_inside`, but specifically for when spans might not + /// overlaps. Take care when using this, and prefer `find_ancestor_inside` + /// when you know that the spans are nested (modulo macro expansion). + pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option { + while !Span::eq_ctxt(self, other) { + self = self.parent_callsite()?; + } + Some(self) + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() @@ -1094,10 +1117,8 @@ pub enum ExternalSource { Unneeded, Foreign { kind: ExternalSourceKind, - /// This SourceFile's byte-offset within the source_map of its original crate. - original_start_pos: BytePos, - /// The end of this SourceFile within the source_map of its original crate. - original_end_pos: BytePos, + /// Index of the file inside metadata. + metadata_index: u32, }, } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 28381157d..4d94c92d3 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,7 +23,6 @@ use std::{convert::TryFrom, unreachable}; use std::fs; use std::io; -use tracing::debug; #[cfg(test)] mod tests; @@ -336,7 +335,7 @@ impl SourceMap { mut file_local_non_narrow_chars: Vec, mut file_local_normalized_pos: Vec, original_start_pos: BytePos, - original_end_pos: BytePos, + metadata_index: u32, ) -> Lrc { let start_pos = self .allocate_address_space(source_len) @@ -381,8 +380,7 @@ impl SourceMap { src_hash, external_src: Lock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, - original_start_pos, - original_end_pos, + metadata_index, }), start_pos, end_pos, @@ -473,7 +471,7 @@ impl SourceMap { let hi = self.lookup_char_pos(sp.hi()); let offset = self.lookup_char_pos(relative_to.lo()); - if lo.file.name != offset.file.name { + if lo.file.name != offset.file.name || !relative_to.contains(sp) { return self.span_to_embeddable_string(sp); } @@ -722,7 +720,7 @@ impl SourceMap { }) } - /// Extends the given `Span` to just after the next occurrence of `c`. + /// Extends the given `Span` to just before the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { let next_source = next_source.split(c).next().unwrap_or(""); @@ -983,93 +981,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| { match source_file.name { @@ -1148,13 +1059,13 @@ impl FilePathMapping { return remap_path_prefix(&self.mapping, path); - #[instrument(level = "debug", skip(mapping))] + #[instrument(level = "debug", skip(mapping), ret)] fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) { // NOTE: We are iterating over the mapping entries from last to first // because entries specified later on the command line should // take precedence. for &(ref from, ref to) in mapping.iter().rev() { - debug!("Trying to apply {:?} => {:?}", from, to); + debug!("Trying to apply {from:?} => {to:?}"); if let Ok(rest) = path.strip_prefix(from) { let remapped = if rest.as_os_str().is_empty() { @@ -1168,15 +1079,15 @@ impl FilePathMapping { } else { to.join(rest) }; - debug!("Match - remapped {:?} => {:?}", path, remapped); + debug!("Match - remapped"); return (remapped, true); } else { - debug!("No match - prefix {:?} does not match {:?}", from, path); + debug!("No match - prefix {from:?} does not match"); } } - debug!("Path {:?} was not remapped", path); + debug!("not remapped"); (path, false) } } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index be827cea8..3058ec45a 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -251,7 +251,7 @@ fn t10() { non_narrow_chars, normalized_pos, start_pos, - end_pos, + 0, ); assert!( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 791160ff6..ae4d1a463 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -157,6 +157,7 @@ symbols! { BTreeSet, BinaryHeap, Borrow, + BorrowMut, Break, C, CStr, @@ -213,6 +214,7 @@ symbols! { IntoIterator, IoRead, IoWrite, + IpAddr, IrTyKind, Is, ItemContext, @@ -222,6 +224,7 @@ symbols! { LinkedList, LintPass, Mutex, + MutexGuard, N, NonZeroI128, NonZeroI16, @@ -270,6 +273,8 @@ symbols! { Rust, RustcDecodable, RustcEncodable, + RwLockReadGuard, + RwLockWriteGuard, Send, SeqCst, SessionDiagnostic, @@ -280,6 +285,7 @@ symbols! { StructuralPartialEq, SubdiagnosticMessage, Sync, + T, Target, ToOwned, ToString, @@ -334,6 +340,7 @@ symbols! { alias, align, align_offset, + alignment, alignstack, all, alloc, @@ -481,6 +488,7 @@ symbols! { cmse_nonsecure_entry, coerce_unsized, cold, + collapse_debuginfo, column, column_macro, compare_and_swap, @@ -504,7 +512,6 @@ symbols! { const_deallocate, const_eval_limit, const_eval_select, - const_eval_select_ct, const_evaluatable_checked, const_extern_fn, const_fn, @@ -644,6 +651,7 @@ symbols! { dropck_parametricity, dylib, dyn_metadata, + dyn_star, dyn_trait, e, edition_macro_pats, @@ -656,7 +664,6 @@ symbols! { emit_struct, emit_struct_field, enable, - enclosing_scope, encode, end, env, @@ -759,7 +766,7 @@ symbols! { gen_future, gen_kill, generator, - generator_return, + generator_clone, generator_state, generators, generic_arg_infer, @@ -802,6 +809,7 @@ symbols! { impl_trait_in_bindings, implied_by, import, + import_name_type, import_shadowing, imported_main, in_band_lifetimes, @@ -817,6 +825,7 @@ symbols! { infer_outlives_requirements, infer_static_outlives_requirements, inherent_associated_types, + inherit, inlateout, inline, inline_const, @@ -859,6 +868,7 @@ symbols! { lib, libc, lifetime, + lifetimes, likely, line, line_macro, @@ -1056,6 +1066,7 @@ symbols! { panic_unwind, panicking, param_attrs, + parent_label, partial_cmp, partial_ord, passes, @@ -1110,14 +1121,15 @@ symbols! { profiler_builtins, profiler_runtime, ptr, - ptr_guaranteed_eq, - ptr_guaranteed_ne, + ptr_guaranteed_cmp, + ptr_mask, ptr_null, ptr_null_mut, ptr_offset_from, ptr_offset_from_unsigned, pub_macro_rules, pub_restricted, + public, pure, pushpop_unsafe, qreg, @@ -1170,8 +1182,10 @@ symbols! { repr_packed, repr_simd, repr_transparent, + require, residual, result, + return_position_impl_trait_in_trait, rhs, rintf32, rintf64, @@ -1200,6 +1214,7 @@ symbols! { rust_eh_unregister_frames, rust_oom, rustc, + rustc_access_level, rustc_allocator, rustc_allocator_nounwind, rustc_allocator_zeroed, @@ -1217,6 +1232,7 @@ symbols! { rustc_conversion_suggestion, rustc_deallocator, rustc_def_path, + rustc_default_body_unstable, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, @@ -1279,9 +1295,11 @@ symbols! { rustc_variance, rustdoc, rustdoc_internals, + rustdoc_missing_doc_code_examples, rustfmt, rvalue_static_promotion, s, + safety, sanitize, sanitizer_runtime, saturating_add, @@ -1295,6 +1313,8 @@ symbols! { should_panic, shr, shr_assign, + sig_dfl, + sig_ign, simd, simd_add, simd_and, @@ -1302,9 +1322,11 @@ symbols! { simd_as, simd_bitmask, simd_cast, + simd_cast_ptr, simd_ceil, simd_div, simd_eq, + simd_expose_addr, simd_extract, simd_fabs, simd_fcos, @@ -1320,6 +1342,7 @@ symbols! { simd_fmin, simd_fpow, simd_fpowi, + simd_from_exposed_addr, simd_fsin, simd_fsqrt, simd_gather, @@ -1464,6 +1487,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_opts, transmute_trait, transparent, transparent_enums, @@ -1480,6 +1504,7 @@ symbols! { tuple, tuple_from_req, tuple_indexing, + tuple_trait, two_phase, ty, type_alias_enum_variants, @@ -1513,6 +1538,7 @@ symbols! { unit, universal_impl_trait, unix, + unix_sigpipe, unlikely, unmarked_api, unpin, @@ -1558,6 +1584,7 @@ symbols! { va_list, va_start, val, + validity, values, var, variant_count, @@ -1801,6 +1828,11 @@ impl Symbol { Symbol(SymbolIndex::from_u32(n)) } + /// for use in Decoder only + pub fn new_from_decoded(n: u32) -> Self { + Self::new(n) + } + /// Maps a string to its interned representation. pub fn intern(string: &str) -> Self { with_session_globals(|session_globals| session_globals.symbol_interner.intern(string)) @@ -1850,14 +1882,14 @@ impl fmt::Display for Symbol { } impl Encodable for Symbol { - fn encode(&self, s: &mut S) { + default fn encode(&self, s: &mut S) { s.emit_str(self.as_str()); } } impl Decodable for Symbol { #[inline] - fn decode(d: &mut D) -> Symbol { + default fn decode(d: &mut D) -> Symbol { Symbol::intern(&d.read_str()) } } @@ -2025,6 +2057,11 @@ impl Symbol { pub fn can_be_raw(self) -> bool { self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() } + + /// Is this symbol was interned in compiler's `symbols!` macro + pub fn is_preinterned(self) -> bool { + self.as_u32() < PREINTERNED_SYMBOLS_COUNT + } } impl Ident { diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index b104a40c2..3db052257 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -18,3 +18,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_session = { path = "../rustc_session" } +rustc_macros = { path = "../rustc_macros" } +rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs new file mode 100644 index 000000000..664d2543f --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -0,0 +1,34 @@ +//! Errors emitted by symbol_mangling. + +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(symbol_mangling::test_output)] +pub struct TestOutput { + #[primary_span] + pub span: Span, + pub kind: Kind, + pub content: String, +} + +pub enum Kind { + SymbolName, + Demangling, + DemanglingAlt, + DefPath, +} + +impl IntoDiagnosticArg for Kind { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + let kind = match self { + Kind::SymbolName => "symbol-name", + Kind::Demangling => "demangling", + Kind::DemanglingAlt => "demangling-alt", + Kind::DefPath => "def-path", + } + .into(); + DiagnosticArgValue::Str(kind) + } +} diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 9241fd82c..46c5fe78f 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -6,8 +6,6 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable}; use rustc_middle::util::common::record_time; -use tracing::debug; - use std::fmt::{self, Write}; use std::mem::{self, discriminant}; diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 5fc992023..62f44a480 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -91,10 +91,15 @@ #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; +#[macro_use] +extern crate tracing; + use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -105,11 +110,10 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; -use tracing::debug; - mod legacy; mod v0; +pub mod errors; pub mod test; pub mod typeid; diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 7249ce04c..9d89c9c52 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -4,6 +4,7 @@ //! def-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. +use crate::errors::{Kind, TestOutput}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt}; @@ -59,16 +60,31 @@ impl SymbolNamesTest<'_> { tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)), ); let mangled = tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); + tcx.sess.emit_err(TestOutput { + span: attr.span, + kind: Kind::SymbolName, + content: format!("{mangled}"), + }); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { - tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); - tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); + tcx.sess.emit_err(TestOutput { + span: attr.span, + kind: Kind::Demangling, + content: format!("{demangling}"), + }); + tcx.sess.emit_err(TestOutput { + span: attr.span, + kind: Kind::DemanglingAlt, + content: format!("{:#}", demangling), + }); } } for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) { - let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())); - tcx.sess.span_err(attr.span, &format!("def-path({})", path)); + tcx.sess.emit_err(TestOutput { + span: attr.span, + kind: Kind::DefPath, + content: with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())), + }); } } } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index a09b52fbf..aa65a72ab 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, - Term, Ty, TyCtxt, UintTy, + TermKind, Ty, TyCtxt, UintTy, }; use rustc_span::def_id::DefId; use rustc_span::symbol::sym; @@ -243,13 +243,9 @@ fn encode_predicate<'tcx>( let name = encode_ty_name(tcx, projection.item_def_id); let _ = write!(s, "u{}{}", name.len(), &name); s.push_str(&encode_substs(tcx, projection.substs, dict, options)); - match projection.term { - Term::Ty(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - Term::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } + match projection.term.unpack() { + TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)), + TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)), } } ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -309,8 +305,7 @@ fn encode_region<'tcx>( | RegionKind::ReFree(..) | RegionKind::ReStatic | RegionKind::ReVar(..) - | RegionKind::RePlaceholder(..) - | RegionKind::ReEmpty(..) => { + | RegionKind::RePlaceholder(..) => { bug!("encode_region: unexpected `{:?}`", region.kind()); } } @@ -632,10 +627,13 @@ fn encode_ty<'tcx>( } // Trait types - ty::Dynamic(predicates, region) => { + ty::Dynamic(predicates, region, kind) => { // u3dynIE, where is , as // vendor extended type. - let mut s = String::from("u3dynI"); + let mut s = String::from(match kind { + ty::Dyn => "u3dynI", + ty::DynStar => "u7dynstarI", + }); s.push_str(&encode_predicates(tcx, predicates, dict, options)); s.push_str(&encode_region(tcx, *region, dict, options)); s.push('E'); @@ -888,7 +886,7 @@ pub fn typeid_for_fnabi<'tcx>( typeid.push('v'); } } else { - for n in 0..fn_abi.fixed_count { + for n in 0..fn_abi.fixed_count as usize { let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 71fa5a448..79d0ef69b 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -479,8 +479,12 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { })?; } - ty::Dynamic(predicates, r) => { - self.push("D"); + ty::Dynamic(predicates, r, kind) => { + self.push(match kind { + ty::Dyn => "D", + // FIXME(dyn-star): need to update v0 mangling docs + ty::DynStar => "D*", + }); self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } @@ -543,9 +547,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let name = cx.tcx.associated_item(projection.item_def_id).name; cx.push("p"); cx.push_ident(name.as_str()); - cx = match projection.term { - ty::Term::Ty(ty) => ty.print(cx), - ty::Term::Const(c) => c.print(cx), + cx = match projection.term.unpack() { + ty::TermKind::Ty(ty) => ty.print(cx), + ty::TermKind::Const(c) => c.print(cx), }?; } ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index 4613a459c..a84988fa7 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -1,6 +1,27 @@ use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{HasDataLayout, TyAbiInterface}; +/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the +/// `ParamExtension` policy specifies how a uM value should be treated when +/// passed via register or stack-slot of width N. See also rust-lang/rust#97463. +#[derive(Copy, Clone, PartialEq)] +pub enum ParamExtension { + /// Indicates that when passing an i8/i16, either as a function argument or + /// as a return value, it must be sign-extended to 32 bits, and likewise a + /// u8/u16 must be zero-extended to 32-bits. (This variant is here to + /// accommodate Apple's deviation from the usual AArch64 ABI as defined by + /// ARM.) + /// + /// See also: + ExtendTo32Bits, + + /// Indicates that no sign- nor zero-extension is performed: if a value of + /// type with bitwidth M is passed as function argument or return value, + /// then M bits are copied into the least significant M bits, and the + /// remaining bits of the register (or word of memory) are untouched. + NoExtension, +} + fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option where Ty: TyAbiInterface<'a, C> + Copy, @@ -24,13 +45,16 @@ where }) } -fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>) +fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !ret.layout.is_aggregate() { - ret.extend_integer_width_to(32); + match param_policy { + ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32), + ParamExtension::NoExtension => {} + } return; } if let Some(uniform) = is_homogeneous_aggregate(cx, ret) { @@ -46,13 +70,16 @@ where ret.make_indirect(); } -fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_aggregate() { - arg.extend_integer_width_to(32); + match param_policy { + ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32), + ParamExtension::NoExtension => {} + } return; } if let Some(uniform) = is_homogeneous_aggregate(cx, arg) { @@ -68,19 +95,19 @@ where arg.make_indirect(); } -pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !fn_abi.ret.is_ignore() { - classify_ret(cx, &mut fn_abi.ret); + classify_ret(cx, &mut fn_abi.ret, param_policy); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } - classify_arg(cx, arg); + classify_arg(cx, arg, param_policy); } } diff --git a/compiler/rustc_target/src/abi/call/amdgpu.rs b/compiler/rustc_target/src/abi/call/amdgpu.rs index 9be97476c..e30dead63 100644 --- a/compiler/rustc_target/src/abi/call/amdgpu.rs +++ b/compiler/rustc_target/src/abi/call/amdgpu.rs @@ -26,7 +26,7 @@ where classify_ret(cx, &mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs index e66c2132b..1923ea588 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/abi/call/arm.rs @@ -88,7 +88,7 @@ where classify_ret(cx, &mut fn_abi.ret, vfp); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/avr.rs b/compiler/rustc_target/src/abi/call/avr.rs index c1f7a1e3a..e20f01355 100644 --- a/compiler/rustc_target/src/abi/call/avr.rs +++ b/compiler/rustc_target/src/abi/call/avr.rs @@ -49,7 +49,7 @@ pub fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { classify_ret_ty(&mut fty.ret); } - for arg in &mut fty.args { + for arg in fty.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/bpf.rs b/compiler/rustc_target/src/abi/call/bpf.rs index 466c52553..780e7df43 100644 --- a/compiler/rustc_target/src/abi/call/bpf.rs +++ b/compiler/rustc_target/src/abi/call/bpf.rs @@ -22,7 +22,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/hexagon.rs b/compiler/rustc_target/src/abi/call/hexagon.rs index 8028443b8..80a442048 100644 --- a/compiler/rustc_target/src/abi/call/hexagon.rs +++ b/compiler/rustc_target/src/abi/call/hexagon.rs @@ -21,7 +21,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/abi/call/m68k.rs index 58fdc00b6..c1e0f54af 100644 --- a/compiler/rustc_target/src/abi/call/m68k.rs +++ b/compiler/rustc_target/src/abi/call/m68k.rs @@ -21,7 +21,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs index cc4431976..edcd1bab8 100644 --- a/compiler/rustc_target/src/abi/call/mips.rs +++ b/compiler/rustc_target/src/abi/call/mips.rs @@ -22,10 +22,8 @@ where let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; if arg.layout.is_aggregate() { - arg.cast_to(Uniform { unit: Reg::i32(), total: size }); - if !offset.is_aligned(align) { - arg.pad_with(Reg::i32()); - } + let pad_i32 = !offset.is_aligned(align); + arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); } else { arg.extend_integer_width_to(32); } @@ -42,7 +40,7 @@ where classify_ret(cx, &mut fn_abi.ret, &mut offset); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs index cd54167aa..2700f67b2 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/abi/call/mips64.rs @@ -158,7 +158,7 @@ where classify_ret(cx, &mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 577126a95..d2fb8c32f 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -14,7 +14,6 @@ mod m68k; mod mips; mod mips64; mod msp430; -mod nvptx; mod nvptx64; mod powerpc; mod powerpc64; @@ -27,7 +26,7 @@ mod x86; mod x86_64; mod x86_win64; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum PassMode { /// Ignore the argument. /// @@ -41,9 +40,10 @@ pub enum PassMode { /// /// The argument has a layout abi of `ScalarPair`. Pair(ArgAttributes, ArgAttributes), - /// Pass the argument after casting it, to either - /// a single uniform or a pair of registers. - Cast(CastTarget), + /// Pass the argument after casting it, to either a single uniform or a + /// pair of registers. The bool indicates if a `Reg::i32()` dummy argument + /// is emitted before the real argument. + Cast(Box, bool), /// Pass the argument indirectly via a hidden pointer. /// The `extra_attrs` value, if any, is for the extra data (vtable or length) /// which indicates that it refers to an unsized rvalue. @@ -464,10 +464,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct ArgAbi<'a, Ty> { pub layout: TyAndLayout<'a, Ty>, - - /// Dummy argument, which is emitted before the real argument. - pub pad: Option, - pub mode: PassMode, } @@ -487,7 +483,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()), }; - ArgAbi { layout, pad: None, mode } + ArgAbi { layout, mode } } fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode { @@ -549,11 +545,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn cast_to>(&mut self, target: T) { - self.mode = PassMode::Cast(target.into()); + self.mode = PassMode::Cast(Box::new(target.into()), false); } - pub fn pad_with(&mut self, reg: Reg) { - self.pad = Some(reg); + pub fn cast_to_and_pad_i32>(&mut self, target: T, pad_i32: bool) { + self.mode = PassMode::Cast(Box::new(target.into()), pad_i32); } pub fn is_indirect(&self) -> bool { @@ -615,7 +611,7 @@ pub enum Conv { #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct FnAbi<'a, Ty> { /// The LLVM types of each argument. - pub args: Vec>, + pub args: Box<[ArgAbi<'a, Ty>]>, /// LLVM return type. pub ret: ArgAbi<'a, Ty>, @@ -626,7 +622,7 @@ pub struct FnAbi<'a, Ty> { /// /// Should only be different from args.len() when c_variadic is true. /// This can be used to know whether an argument is variadic or not. - pub fixed_count: usize, + pub fixed_count: u32, pub conv: Conv, @@ -689,7 +685,14 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } }, - "aarch64" => aarch64::compute_abi_info(cx, self), + "aarch64" => { + let param_policy = if cx.target_spec().is_like_osx { + aarch64::ParamExtension::ExtendTo32Bits + } else { + aarch64::ParamExtension::NoExtension + }; + aarch64::compute_abi_info(cx, self, param_policy) + } "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), "avr" => avr::compute_abi_info(self), @@ -702,7 +705,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { "msp430" => msp430::compute_abi_info(self), "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), - "nvptx" => nvptx::compute_abi_info(self), "nvptx64" => { if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) @@ -732,3 +734,13 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } } + +// 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; + // These are in alphabetical order, which is easy to maintain. + static_assert_size!(ArgAbi<'_, usize>, 56); + static_assert_size!(FnAbi<'_, usize>, 80); +} diff --git a/compiler/rustc_target/src/abi/call/msp430.rs b/compiler/rustc_target/src/abi/call/msp430.rs index 0ba73657b..33ef47be0 100644 --- a/compiler/rustc_target/src/abi/call/msp430.rs +++ b/compiler/rustc_target/src/abi/call/msp430.rs @@ -30,7 +30,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs deleted file mode 100644 index 428dd95bb..000000000 --- a/compiler/rustc_target/src/abi/call/nvptx.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Reference: PTX Writer's Guide to Interoperability -// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability - -use crate::abi::call::{ArgAbi, FnAbi}; - -fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { - if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 { - ret.make_indirect(); - } else { - ret.extend_integer_width_to(32); - } -} - -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { - if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { - arg.make_indirect(); - } else { - arg.extend_integer_width_to(32); - } -} - -pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { - if !fn_abi.ret.is_ignore() { - classify_ret(&mut fn_abi.ret); - } - - for arg in &mut fn_abi.args { - if arg.is_ignore() { - continue; - } - classify_arg(arg); - } -} diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs index fc16f1c97..4abe51cd6 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/abi/call/nvptx64.rs @@ -38,7 +38,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } @@ -55,7 +55,7 @@ where panic!("Kernels should not return anything other than () or !"); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/powerpc.rs b/compiler/rustc_target/src/abi/call/powerpc.rs index 27a5c6d2f..70c32db0a 100644 --- a/compiler/rustc_target/src/abi/call/powerpc.rs +++ b/compiler/rustc_target/src/abi/call/powerpc.rs @@ -21,7 +21,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs index c22ef9c8f..359bb8fc0 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/abi/call/powerpc64.rs @@ -132,7 +132,7 @@ where classify_ret(cx, &mut fn_abi.ret, abi); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 752b44f64..1cb360f83 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -340,7 +340,7 @@ where arg, xlen, flen, - i >= fn_abi.fixed_count, + i >= fn_abi.fixed_count as usize, &mut avail_gprs, &mut avail_fprs, ); diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs index 13706e8c2..ea2369281 100644 --- a/compiler/rustc_target/src/abi/call/s390x.rs +++ b/compiler/rustc_target/src/abi/call/s390x.rs @@ -48,7 +48,7 @@ where classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs index cc4431976..edcd1bab8 100644 --- a/compiler/rustc_target/src/abi/call/sparc.rs +++ b/compiler/rustc_target/src/abi/call/sparc.rs @@ -22,10 +22,8 @@ where let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; if arg.layout.is_aggregate() { - arg.cast_to(Uniform { unit: Reg::i32(), total: size }); - if !offset.is_aligned(align) { - arg.pad_with(Reg::i32()); - } + let pad_i32 = !offset.is_aligned(align); + arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); } else { arg.extend_integer_width_to(32); } @@ -42,7 +40,7 @@ where classify_ret(cx, &mut fn_abi.ret, &mut offset); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index cc3a0a699..1b74959ad 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -217,7 +217,7 @@ where classify_arg(cx, &mut fn_abi.ret, Size { raw: 32 }); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs index 3237cde10..44427ee53 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/abi/call/wasm.rs @@ -50,7 +50,7 @@ where classify_ret(cx, &mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } @@ -66,7 +66,7 @@ pub fn compute_wasm_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_ret(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index c7d59baf9..7c26335dc 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -49,7 +49,7 @@ where } } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } @@ -72,7 +72,7 @@ where let mut free_regs = 2; - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { let attrs = match arg.mode { PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { @@ -81,7 +81,7 @@ where PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } - | PassMode::Cast(_) => { + | PassMode::Cast(..) => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } }; diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index a52e01a49..c0c071a61 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -239,7 +239,7 @@ where x86_64_arg_or_ret(&mut fn_abi.ret, false); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs index 2aad641b1..1aaf0e511 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/abi/call/x86_win64.rs @@ -31,7 +31,7 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if !fn_abi.ret.is_ignore() { fixup(&mut fn_abi.ret); } - for arg in &mut fn_abi.args { + for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 92ce4d91d..ec334e588 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -7,7 +7,7 @@ use crate::spec::Target; use std::convert::{TryFrom, TryInto}; use std::fmt; use std::iter::Step; -use std::num::NonZeroUsize; +use std::num::{NonZeroUsize, ParseIntError}; use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; use std::str::FromStr; @@ -69,34 +69,46 @@ impl Default for TargetDataLayout { } } +pub enum TargetDataLayoutErrors<'a> { + InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError }, + InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError }, + MissingAlignment { cause: &'a str }, + InvalidAlignment { cause: &'a str, err: String }, + InconsistentTargetArchitecture { dl: &'a str, target: &'a str }, + InconsistentTargetPointerWidth { pointer_size: u64, target: u32 }, + InvalidBitsSize { err: String }, +} + impl TargetDataLayout { - pub fn parse(target: &Target) -> Result { + pub fn parse<'a>(target: &'a Target) -> Result> { // Parse an address space index from a string. - let parse_address_space = |s: &str, cause: &str| { + let parse_address_space = |s: &'a str, cause: &'a str| { s.parse::().map(AddressSpace).map_err(|err| { - format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err) + TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err } }) }; // Parse a bit count from a string. - let parse_bits = |s: &str, kind: &str, cause: &str| { - s.parse::().map_err(|err| { - format!("invalid {} `{}` for `{}` in \"data-layout\": {}", kind, s, cause, err) + let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| { + s.parse::().map_err(|err| TargetDataLayoutErrors::InvalidBits { + kind, + bit: s, + cause, + err, }) }; // Parse a size string. - let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits); + let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits); // Parse an alignment string. - let align = |s: &[&str], cause: &str| { + let align = |s: &[&'a str], cause: &'a str| { if s.is_empty() { - return Err(format!("missing alignment for `{}` in \"data-layout\"", cause)); + return Err(TargetDataLayoutErrors::MissingAlignment { cause }); } let align_from_bits = |bits| { - Align::from_bits(bits).map_err(|err| { - format!("invalid alignment for `{}` in \"data-layout\": {}", cause, err) - }) + Align::from_bits(bits) + .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err }) }; let abi = parse_bits(s[0], "alignment", cause)?; let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?; @@ -158,25 +170,24 @@ impl TargetDataLayout { // Perform consistency checks against the Target information. if dl.endian != target.endian { - return Err(format!( - "inconsistent target specification: \"data-layout\" claims \ - architecture is {}-endian, while \"target-endian\" is `{}`", - dl.endian.as_str(), - target.endian.as_str(), - )); + return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture { + dl: dl.endian.as_str(), + target: target.endian.as_str(), + }); } let target_pointer_width: u64 = target.pointer_width.into(); if dl.pointer_size.bits() != target_pointer_width { - return Err(format!( - "inconsistent target specification: \"data-layout\" claims \ - pointers are {}-bit, while \"target-pointer-width\" is `{}`", - dl.pointer_size.bits(), - target.pointer_width - )); + return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth { + pointer_size: dl.pointer_size.bits(), + target: target.pointer_width, + }); } - dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?; + dl.c_enum_min_size = match Integer::from_size(Size::from_bits(target.c_enum_min_bits)) { + Ok(bits) => bits, + Err(err) => return Err(TargetDataLayoutErrors::InvalidBitsSize { err }), + }; Ok(dl) } @@ -1130,7 +1141,7 @@ pub enum TagEncoding { /// Niche (values invalid for a type) encoding the discriminant: /// Discriminant and variant index coincide. - /// The variant `dataful_variant` contains a niche at an arbitrary + /// The variant `untagged_variant` contains a niche at an arbitrary /// offset (field `tag_field` of the enum), which for a variant with /// discriminant `d` is set to /// `(d - niche_variants.start).wrapping_add(niche_start)`. @@ -1139,7 +1150,7 @@ pub enum TagEncoding { /// `None` has a null pointer for the second tuple field, and /// `Some` is the identity function (with a non-null reference). Niche { - dataful_variant: VariantIdx, + untagged_variant: VariantIdx, niche_variants: RangeInclusive, niche_start: u128, }, diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 59dbea705..a7deab9d2 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -11,11 +11,13 @@ #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(step_trait)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use std::iter::FromIterator; use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 9d36e37d7..6d919a4c2 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -1,20 +1,20 @@ -use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + let arch = "arm64"; + let mut base = super::apple_base::opts("macos", arch, ""); base.cpu = "apple-a14".into(); base.max_atomic_width = Some(128); // FIXME: The leak sanitizer currently fails the tests, see #88132. base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work // correctly, we do too. - let llvm_target = super::apple_base::macos_llvm_target("arm64"); + let llvm_target = super::apple_base::macos_llvm_target(arch); Target { llvm_target: llvm_target.into(), diff --git a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs index 1b7161fbb..b301ce68a 100644 --- a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs @@ -18,7 +18,6 @@ pub fn target() -> Target { panic_strategy: PanicStrategy::Abort, position_independent_executables: true, dynamic_linking: true, - executables: true, relro_level: RelroLevel::Off, ..Default::default() }, diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs index 59c6a95c2..98d3e79c8 100644 --- a/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs @@ -2,7 +2,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_gnullvm_base::opts(); - base.max_atomic_width = Some(64); + base.max_atomic_width = Some(128); base.features = "+neon,+fp-armv8".into(); base.linker = Some("aarch64-w64-mingw32-clang".into()); diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs index 856ec4fb0..7c4544b3f 100644 --- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs @@ -2,7 +2,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); - base.max_atomic_width = Some(64); + base.max_atomic_width = Some(128); base.features = "+neon,+fp-armv8".into(); Target { diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs index 162b091b2..3ef04c676 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs @@ -7,7 +7,7 @@ use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = uefi_msvc_base::opts(); - base.max_atomic_width = Some(64); + base.max_atomic_width = Some(128); base.add_pre_link_args(LinkerFlavor::Msvc, &["/machine:arm64"]); Target { diff --git a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs index 54247fd93..db4dbf817 100644 --- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs @@ -2,7 +2,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_uwp_msvc_base::opts(); - base.max_atomic_width = Some(64); + base.max_atomic_width = Some(128); Target { llvm_target: "aarch64-pc-windows-msvc".into(), diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index dc06597db..9f3e0bd5e 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -4,12 +4,11 @@ pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); base.os = "android".into(); base.default_dwarf_version = 2; - base.position_independent_executables = true; base.has_thread_local = false; // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867 // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution // was to always emit `uwtable`). base.default_uwtable = true; - base.crt_static_respected = false; + base.crt_static_respected = true; base } diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 15e4fb9be..2c72bf88a 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -1,8 +1,42 @@ use std::{borrow::Cow, env}; -use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, StaticCow, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor}; + +fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs { + let platform_name: StaticCow = match abi { + "sim" => format!("{}-simulator", os).into(), + "macabi" => "mac-catalyst".into(), + _ => os.into(), + }; + + let platform_version: StaticCow = match os.as_ref() { + "ios" => ios_lld_platform_version(), + "tvos" => tvos_lld_platform_version(), + "watchos" => watchos_lld_platform_version(), + "macos" => macos_lld_platform_version(arch), + _ => unreachable!(), + } + .into(); + + let mut args = TargetOptions::link_args( + LinkerFlavor::Lld(LldFlavor::Ld64), + &["-arch", arch, "-platform_version"], + ); + // Manually add owned args unsupported by link arg building helpers. + args.entry(LinkerFlavor::Lld(LldFlavor::Ld64)).or_default().extend([ + platform_name, + platform_version.clone(), + platform_version, + ]); + if abi != "macabi" { + super::add_link_args(&mut args, LinkerFlavor::Gcc, &["-arch", arch]); + } + + args +} -pub fn opts(os: &'static str) -> TargetOptions { +pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 // either the linker will complain if it is used or the binary will end up // segfaulting at runtime when run on 10.6. Rust by default supports macOS @@ -24,6 +58,7 @@ pub fn opts(os: &'static str) -> TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, + pre_link_args: pre_link_args(os, arch, abi), linker_is_gnu: false, families: cvs!["unix"], is_like_osx: true, @@ -38,9 +73,15 @@ pub fn opts(os: &'static str) -> TargetOptions { eh_frame_header: false, lld_flavor: LldFlavor::Ld64, + debuginfo_kind: DebuginfoKind::DwarfDsym, // The historical default for macOS targets is to run `dsymutil` which // generates a packed version of debuginfo split from the main file. split_debuginfo: SplitDebuginfo::Packed, + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), // This environment variable is pretty magical but is intended for // producing deterministic builds. This was first discovered to be used @@ -73,12 +114,17 @@ fn macos_deployment_target(arch: &str) -> (u32, u32) { .unwrap_or_else(|| macos_default_deployment_target(arch)) } +fn macos_lld_platform_version(arch: &str) -> String { + let (major, minor) = macos_deployment_target(arch); + format!("{}.{}", major, minor) +} + pub fn macos_llvm_target(arch: &str) -> String { let (major, minor) = macos_deployment_target(arch); format!("{}-apple-macosx{}.{}.0", arch, major, minor) } -pub fn macos_link_env_remove() -> Vec> { +pub fn macos_link_env_remove() -> Vec> { let mut env_remove = Vec::with_capacity(2); // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which // may occur when we're linking a custom build script while targeting iOS for example. @@ -109,7 +155,7 @@ pub fn ios_llvm_target(arch: &str) -> String { format!("{}-apple-ios{}.{}.0", arch, major, minor) } -pub fn ios_lld_platform_version() -> String { +fn ios_lld_platform_version() -> String { let (major, minor) = ios_deployment_target(); format!("{}.{}", major, minor) } @@ -123,7 +169,7 @@ fn tvos_deployment_target() -> (u32, u32) { deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0)) } -pub fn tvos_lld_platform_version() -> String { +fn tvos_lld_platform_version() -> String { let (major, minor) = tvos_deployment_target(); format!("{}.{}", major, minor) } @@ -132,7 +178,7 @@ fn watchos_deployment_target() -> (u32, u32) { deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) } -pub fn watchos_lld_platform_version() -> String { +fn watchos_lld_platform_version() -> String { let (major, minor) = watchos_deployment_target(); format!("{}.{}", major, minor) } diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index d77558f0f..49e302676 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{cvs, TargetOptions}; use std::borrow::Cow; use Arch::*; @@ -61,53 +61,12 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> { } } -fn pre_link_args(os: &'static str, arch: Arch) -> LinkArgs { - let mut args = LinkArgs::new(); - - let target_abi = target_abi(arch); - - let platform_name = match target_abi { - "sim" => format!("{}-simulator", os), - "macabi" => "mac-catalyst".to_string(), - _ => os.to_string(), - }; - - let platform_version = match os.as_ref() { - "ios" => super::apple_base::ios_lld_platform_version(), - "tvos" => super::apple_base::tvos_lld_platform_version(), - "watchos" => super::apple_base::watchos_lld_platform_version(), - _ => unreachable!(), - }; - - let arch_str = target_arch_name(arch); - - if target_abi != "macabi" { - args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch_str.into()]); - } - - args.insert( - LinkerFlavor::Lld(LldFlavor::Ld64), - vec![ - "-arch".into(), - arch_str.into(), - "-platform_version".into(), - platform_name.into(), - platform_version.clone().into(), - platform_version.into(), - ], - ); - - args -} - pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { TargetOptions { abi: target_abi(arch).into(), cpu: target_cpu(arch).into(), - dynamic_linking: false, - pre_link_args: pre_link_args(os, arch), link_env_remove: link_env_remove(arch), has_thread_local: false, - ..super::apple_base::opts(os) + ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch)) } } diff --git a/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs index 7b23fe1c4..cb7f5f2a5 100644 --- a/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { arch: "aarch64".into(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), - max_atomic_width: Some(64), + max_atomic_width: Some(128), forces_embed_bitcode: true, // These arguments are not actually invoked - they just have // to look right to pass App Store validation. diff --git a/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs new file mode 100644 index 000000000..4836f3cf7 --- /dev/null +++ b/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs @@ -0,0 +1,19 @@ +use crate::abi::Endian; +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "armeb-unknown-linux-gnueabi".into(), + pointer_width: 32, + data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: TargetOptions { + abi: "eabi".into(), + features: "+strict-align,+v8,+crc".into(), + endian: Endian::Big, + max_atomic_width: Some(64), + mcount: "\u{1}__gnu_mcount_nc".into(), + ..super::linux_gnu_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs new file mode 100644 index 000000000..797dfe52b --- /dev/null +++ b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs @@ -0,0 +1,56 @@ +//! Targets the ARMv4T, with code as `a32` code by default. +//! +//! Primarily of use for the GBA, but usable with other devices too. +//! +//! Please ping @Lokathor if changes are needed. +//! +//! This target profile assumes that you have the ARM binutils in your path +//! (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free +//! for all major OSes from the ARM developer's website, and they may also be +//! available in your system's package manager. Unfortunately, the standard +//! linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we +//! must use the GNU `ld` linker. +//! +//! **Important:** This target profile **does not** specify a linker script. You +//! just get the default link script when you build a binary for this target. +//! The default link script is very likely wrong, so you should use +//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script. + +use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "armv4t-none-eabi".into(), + pointer_width: 32, + arch: "arm".into(), + /* Data layout args are '-' separated: + * little endian + * stack is 64-bit aligned (EABI) + * pointers are 32-bit + * i64 must be 64-bit aligned (EABI) + * mangle names with ELF style + * native integers are 32-bit + * All other elements are default + */ + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + options: TargetOptions { + abi: "eabi".into(), + linker_flavor: LinkerFlavor::Ld, + linker: Some("arm-none-eabi-ld".into()), + asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], + // Force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+soft-float,+strict-align,+atomics-32".into(), + main_needs_argc_argv: false, + atomic_cas: false, + has_thumb_interworking: true, + relocation_model: RelocModel::Static, + panic_strategy: PanicStrategy::Abort, + // from thumb_base, rust-lang/rust#44993. + emit_debug_gdb_scripts: false, + // from thumb_base, apparently gcc/clang give enums a minimum of 8 bits on no-os targets + c_enum_min_bits: 8, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs index b4cf2c5ee..f492c3451 100644 --- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs @@ -2,6 +2,6 @@ use super::{wasm32_unknown_emscripten, LinkerFlavor, Target}; pub fn target() -> Target { let mut target = wasm32_unknown_emscripten::target(); - target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]); + target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]); target } diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 1d441e558..8cca33cc4 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions}; /// A base target for AVR devices using the GNU toolchain. /// @@ -21,6 +21,7 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { late_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &["-lgcc"]), max_atomic_width: Some(0), atomic_cas: false, + relocation_model: RelocModel::Static, ..TargetOptions::default() }, } diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index 3c4da6f88..baf365871 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -5,7 +5,7 @@ pub fn opts(endian: Endian) -> TargetOptions { TargetOptions { allow_asm: true, endian, - linker_flavor: LinkerFlavor::BpfLinker, + linker_flavor: LinkerFlavor::Bpf, atomic_cas: false, dynamic_linking: true, no_builtins: true, diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs index 52ac3622e..c126390f5 100644 --- a/compiler/rustc_target/src/spec/crt_objects.rs +++ b/compiler/rustc_target/src/spec/crt_objects.rs @@ -63,7 +63,7 @@ pub(super) fn all(obj: &'static str) -> CrtObjects { ]) } -pub(super) fn pre_musl_fallback() -> CrtObjects { +pub(super) fn pre_musl_self_contained() -> CrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]), (LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]), @@ -74,7 +74,7 @@ pub(super) fn pre_musl_fallback() -> CrtObjects { ]) } -pub(super) fn post_musl_fallback() -> CrtObjects { +pub(super) fn post_musl_self_contained() -> CrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]), (LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]), @@ -85,7 +85,7 @@ pub(super) fn post_musl_fallback() -> CrtObjects { ]) } -pub(super) fn pre_mingw_fallback() -> CrtObjects { +pub(super) fn pre_mingw_self_contained() -> CrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]), (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]), @@ -96,7 +96,7 @@ pub(super) fn pre_mingw_fallback() -> CrtObjects { ]) } -pub(super) fn post_mingw_fallback() -> CrtObjects { +pub(super) fn post_mingw_self_contained() -> CrtObjects { all("rsend.o") } @@ -108,7 +108,7 @@ pub(super) fn post_mingw() -> CrtObjects { all("rsend.o") } -pub(super) fn pre_wasi_fallback() -> CrtObjects { +pub(super) fn pre_wasi_self_contained() -> CrtObjects { // Use crt1-command.o instead of crt1.o to enable support for new-style // commands. See https://reviews.llvm.org/D81689 for more info. new(&[ @@ -120,37 +120,41 @@ pub(super) fn pre_wasi_fallback() -> CrtObjects { ]) } -pub(super) fn post_wasi_fallback() -> CrtObjects { +pub(super) fn post_wasi_self_contained() -> CrtObjects { new(&[]) } -/// Which logic to use to determine whether to fall back to the "self-contained" mode or not. +/// Which logic to use to determine whether to use self-contained linking mode +/// if `-Clink-self-contained` is not specified explicitly. #[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum CrtObjectsFallback { +pub enum LinkSelfContainedDefault { + False, + True, Musl, Mingw, - Wasm, } -impl FromStr for CrtObjectsFallback { +impl FromStr for LinkSelfContainedDefault { type Err = (); - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { - "musl" => CrtObjectsFallback::Musl, - "mingw" => CrtObjectsFallback::Mingw, - "wasm" => CrtObjectsFallback::Wasm, + "false" => LinkSelfContainedDefault::False, + "true" | "wasm" => LinkSelfContainedDefault::True, + "musl" => LinkSelfContainedDefault::Musl, + "mingw" => LinkSelfContainedDefault::Mingw, _ => return Err(()), }) } } -impl ToJson for CrtObjectsFallback { +impl ToJson for LinkSelfContainedDefault { fn to_json(&self) -> Json { match *self { - CrtObjectsFallback::Musl => "musl", - CrtObjectsFallback::Mingw => "mingw", - CrtObjectsFallback::Wasm => "wasm", + LinkSelfContainedDefault::False => "false", + LinkSelfContainedDefault::True => "true", + LinkSelfContainedDefault::Musl => "musl", + LinkSelfContainedDefault::Mingw => "mingw", } .to_json() } diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index df1e3275f..962ad0c66 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -1,6 +1,11 @@ use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions}; pub fn opts() -> TargetOptions { + // This mirrors the linker options provided by clang. We presume lld for + // now. When using clang as the linker it will supply these options for us, + // so we only list them for ld/lld. + // + // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31 let pre_link_args = TargetOptions::link_args( LinkerFlavor::Ld, &[ diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs index cc2c78c69..2a24e4459 100644 --- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { base.crt_static_default = false; base.has_rpath = true; base.linker_is_gnu = false; - base.dynamic_linking = true; base.c_enum_min_bits = 8; diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 1718bd77b..5e9ceb844 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -1,7 +1,8 @@ use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + // ld64 only understand i386 and not i686 + let mut base = super::apple_base::opts("macos", "i386", ""); base.cpu = "yonah".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index a08756861..b7bc1072b 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -1,14 +1,15 @@ -use crate::spec::{cvs, LinkerFlavor, PanicStrategy, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions}; pub fn opts() -> TargetOptions { TargetOptions { os: "l4re".into(), env: "uclibc".into(), - linker_flavor: LinkerFlavor::L4Bender, + linker_flavor: LinkerFlavor::Ld, panic_strategy: PanicStrategy::Abort, linker: Some("l4-bender".into()), linker_is_gnu: false, families: cvs!["unix"], + relocation_model: RelocModel::Static, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index f4fce3b40..df8e84812 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -1,4 +1,5 @@ -use crate::spec::{cvs, RelroLevel, TargetOptions}; +use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { TargetOptions { @@ -10,6 +11,11 @@ pub fn opts() -> TargetOptions { relro_level: RelroLevel::Full, has_thread_local: true, crt_static_respected: true, + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs index 207a87ab0..61553e71b 100644 --- a/compiler/rustc_target/src/spec/linux_musl_base.rs +++ b/compiler/rustc_target/src/spec/linux_musl_base.rs @@ -1,13 +1,13 @@ -use crate::spec::crt_objects::{self, CrtObjectsFallback}; +use crate::spec::crt_objects::{self, LinkSelfContainedDefault}; use crate::spec::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); base.env = "musl".into(); - base.pre_link_objects_fallback = crt_objects::pre_musl_fallback(); - base.post_link_objects_fallback = crt_objects::post_musl_fallback(); - base.crt_objects_fallback = Some(CrtObjectsFallback::Musl); + base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained(); + base.post_link_objects_self_contained = crt_objects::post_musl_self_contained(); + base.link_self_contained = LinkSelfContainedDefault::Musl; // These targets statically link libc by default base.crt_static_default = true; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f7abeafd3..dc16739bd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -37,7 +37,7 @@ use crate::abi::Endian; use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; -use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; +use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{sym, Symbol}; @@ -92,14 +92,24 @@ mod windows_uwp_msvc_base; #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavor { - Em, Gcc, - L4Bender, Ld, + Lld(LldFlavor), Msvc, + EmCc, + Bpf, + Ptx, +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum LinkerFlavorCli { + Gcc, + Ld, Lld(LldFlavor), - PtxLinker, + Msvc, + Em, BpfLinker, + PtxLinker, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -137,19 +147,40 @@ impl ToJson for LldFlavor { } } -impl ToJson for LinkerFlavor { - fn to_json(&self) -> Json { - self.desc().to_json() +impl LinkerFlavor { + pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor { + match cli { + LinkerFlavorCli::Gcc => LinkerFlavor::Gcc, + LinkerFlavorCli::Ld => LinkerFlavor::Ld, + LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor), + LinkerFlavorCli::Msvc => LinkerFlavor::Msvc, + LinkerFlavorCli::Em => LinkerFlavor::EmCc, + LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf, + LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx, + } + } + + fn to_cli(self) -> LinkerFlavorCli { + match self { + LinkerFlavor::Gcc => LinkerFlavorCli::Gcc, + LinkerFlavor::Ld => LinkerFlavorCli::Ld, + LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor), + LinkerFlavor::Msvc => LinkerFlavorCli::Msvc, + LinkerFlavor::EmCc => LinkerFlavorCli::Em, + LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker, + LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker, + } } } -macro_rules! flavor_mappings { - ($((($($flavor:tt)*), $string:expr),)*) => ( - impl LinkerFlavor { + +macro_rules! linker_flavor_cli_impls { + ($(($($flavor:tt)*) $string:literal)*) => ( + impl LinkerFlavorCli { pub const fn one_of() -> &'static str { concat!("one of: ", $($string, " ",)*) } - pub fn from_str(s: &str) -> Option { + pub fn from_str(s: &str) -> Option { Some(match s { $($string => $($flavor)*,)* _ => return None, @@ -165,18 +196,23 @@ macro_rules! flavor_mappings { ) } -flavor_mappings! { - ((LinkerFlavor::Em), "em"), - ((LinkerFlavor::Gcc), "gcc"), - ((LinkerFlavor::L4Bender), "l4-bender"), - ((LinkerFlavor::Ld), "ld"), - ((LinkerFlavor::Msvc), "msvc"), - ((LinkerFlavor::PtxLinker), "ptx-linker"), - ((LinkerFlavor::BpfLinker), "bpf-linker"), - ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), - ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), - ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), - ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"), +linker_flavor_cli_impls! { + (LinkerFlavorCli::Gcc) "gcc" + (LinkerFlavorCli::Ld) "ld" + (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld" + (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld" + (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link" + (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld" + (LinkerFlavorCli::Msvc) "msvc" + (LinkerFlavorCli::Em) "em" + (LinkerFlavorCli::BpfLinker) "bpf-linker" + (LinkerFlavorCli::PtxLinker) "ptx-linker" +} + +impl ToJson for LinkerFlavorCli { + fn to_json(&self) -> Json { + self.desc().to_json() + } } #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] @@ -467,8 +503,59 @@ impl fmt::Display for LinkOutputKind { } pub type LinkArgs = BTreeMap>>; +pub type LinkArgsCli = BTreeMap>>; + +/// Which kind of debuginfo does the target use? +/// +/// Useful in determining whether a target supports Split DWARF (a target with +/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example). +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub enum DebuginfoKind { + /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`). + #[default] + Dwarf, + /// DWARF debuginfo in dSYM files (such as on Apple platforms). + DwarfDsym, + /// Program database files (such as on Windows). + Pdb, +} + +impl DebuginfoKind { + fn as_str(&self) -> &'static str { + match self { + DebuginfoKind::Dwarf => "dwarf", + DebuginfoKind::DwarfDsym => "dwarf-dsym", + DebuginfoKind::Pdb => "pdb", + } + } +} + +impl FromStr for DebuginfoKind { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "dwarf" => DebuginfoKind::Dwarf, + "dwarf-dsym" => DebuginfoKind::DwarfDsym, + "pdb" => DebuginfoKind::Pdb, + _ => return Err(()), + }) + } +} + +impl ToJson for DebuginfoKind { + fn to_json(&self) -> Json { + self.as_str().to_json() + } +} -#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)] +impl fmt::Display for DebuginfoKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub enum SplitDebuginfo { /// Split debug-information is disabled, meaning that on supported platforms /// you can find all debug information in the executable itself. This is @@ -476,7 +563,8 @@ pub enum SplitDebuginfo { /// /// * Windows - not supported /// * macOS - don't run `dsymutil` - /// * ELF - `.dwarf_*` sections + /// * ELF - `.debug_*` sections + #[default] Off, /// Split debug-information can be found in a "packed" location separate @@ -484,7 +572,7 @@ pub enum SplitDebuginfo { /// /// * Windows - `*.pdb` /// * macOS - `*.dSYM` (run `dsymutil`) - /// * ELF - `*.dwp` (run `rust-llvm-dwp`) + /// * ELF - `*.dwp` (run `thorin`) Packed, /// Split debug-information can be found in individual object files on the @@ -509,7 +597,7 @@ impl SplitDebuginfo { impl FromStr for SplitDebuginfo { type Err = (); - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(match s { "off" => SplitDebuginfo::Off, "unpacked" => SplitDebuginfo::Unpacked, @@ -786,15 +874,15 @@ impl fmt::Display for StackProtector { } macro_rules! supported_targets { - ( $(($( $triple:literal, )+ $module:ident ),)+ ) => { + ( $(($triple:literal, $module:ident ),)+ ) => { $(mod $module;)+ /// List of supported targets - pub const TARGETS: &[&str] = &[$($($triple),+),+]; + pub const TARGETS: &[&str] = &[$($triple),+]; fn load_builtin(target: &str) -> Option { let mut t = match target { - $( $($triple)|+ => $module::target(), )+ + $( $triple => $module::target(), )+ _ => return None, }; t.is_builtin = true; @@ -810,7 +898,7 @@ macro_rules! supported_targets { $( #[test] // `#[test]` fn $module() { - tests_impl::test_target(super::$module::target()); + tests_impl::test_target(super::$module::target(), $triple); } )+ } @@ -844,6 +932,7 @@ supported_targets! { ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), + ("armeb-unknown-linux-gnueabi", armeb_unknown_linux_gnueabi), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi), @@ -893,9 +982,11 @@ supported_targets! { ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), ("i686-unknown-openbsd", i686_unknown_openbsd), + ("powerpc-unknown-openbsd", powerpc_unknown_openbsd), + ("powerpc64-unknown-openbsd", powerpc64_unknown_openbsd), + ("riscv64gc-unknown-openbsd", riscv64gc_unknown_openbsd), ("sparc64-unknown-openbsd", sparc64_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), - ("powerpc-unknown-openbsd", powerpc_unknown_openbsd), ("aarch64-unknown-netbsd", aarch64_unknown_netbsd), ("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf), @@ -1028,6 +1119,7 @@ supported_targets! { ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), + ("armv4t-none-eabi", armv4t_none_eabi), ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu), ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32), @@ -1156,48 +1248,54 @@ pub struct TargetOptions { pub abi: StaticCow, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". pub vendor: StaticCow, - /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed - /// on the command line. Defaults to `LinkerFlavor::Gcc`. - pub linker_flavor: LinkerFlavor, /// Linker to invoke pub linker: Option>, - + /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed + /// on the command line. Defaults to `LinkerFlavor::Gcc`. + pub linker_flavor: LinkerFlavor, + linker_flavor_json: LinkerFlavorCli, /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker /// without clarifying its flavor in any way. + /// FIXME: Merge this into `LinkerFlavor`. pub lld_flavor: LldFlavor, + /// Whether the linker support GNU-like arguments such as -O. Defaults to true. + /// FIXME: Merge this into `LinkerFlavor`. + pub linker_is_gnu: bool, - /// Linker arguments that are passed *before* any user-defined libraries. - pub pre_link_args: LinkArgs, /// Objects to link before and after all other object code. pub pre_link_objects: CrtObjects, pub post_link_objects: CrtObjects, - /// Same as `(pre|post)_link_objects`, but when we fail to pull the objects with help of the - /// target's native gcc and fall back to the "self-contained" mode and pull them manually. - /// See `crt_objects.rs` for some more detailed documentation. - pub pre_link_objects_fallback: CrtObjects, - pub post_link_objects_fallback: CrtObjects, - /// Which logic to use to determine whether to fall back to the "self-contained" mode or not. - pub crt_objects_fallback: Option, + /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled. + pub pre_link_objects_self_contained: CrtObjects, + pub post_link_objects_self_contained: CrtObjects, + pub link_self_contained: LinkSelfContainedDefault, + /// Linker arguments that are passed *before* any user-defined libraries. + pub pre_link_args: LinkArgs, + pre_link_args_json: LinkArgsCli, /// Linker arguments that are unconditionally passed after any /// user-defined but before post-link objects. Standard platform /// libraries that should be always be linked to, usually go here. pub late_link_args: LinkArgs, + late_link_args_json: LinkArgsCli, /// Linker arguments used in addition to `late_link_args` if at least one /// Rust dependency is dynamically linked. pub late_link_args_dynamic: LinkArgs, + late_link_args_dynamic_json: LinkArgsCli, /// Linker arguments used in addition to `late_link_args` if all Rust /// dependencies are statically linked. pub late_link_args_static: LinkArgs, + late_link_args_static_json: LinkArgsCli, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. pub post_link_args: LinkArgs, + post_link_args_json: LinkArgsCli, + /// Optional link script applied to `dylib` and `executable` crate types. /// This is a string containing the script, not a path. Can only be applied /// to linkers where `linker_is_gnu` is true. pub link_script: Option>, - /// Environment variables to be set for the linker invocation. pub link_env: StaticCow<[(StaticCow, StaticCow)]>, /// Environment variables to be removed for the linker invocation. @@ -1254,6 +1352,8 @@ pub struct TargetOptions { pub abi_return_struct_as_int: bool, /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. + /// Also indiates whether to use Apple-specific ABI changes, such as extending function + /// parameters to 32-bits. pub is_like_osx: bool, /// Whether the target toolchain is like Solaris's. /// Only useful for compiling against Illumos/Solaris, @@ -1282,8 +1382,6 @@ pub struct TargetOptions { /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub default_dwarf_version: u32, - /// Whether the linker support GNU-like arguments such as -O. Defaults to true. - pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly /// handling COFF object files with more than 215 sections. Since each weak /// symbol needs its own COMDAT section, weak linkage implies a large @@ -1438,9 +1536,13 @@ pub struct TargetOptions { /// thumb and arm interworking. pub has_thumb_interworking: bool, + /// Which kind of debuginfo is used by this target? + pub debuginfo_kind: DebuginfoKind, /// How to handle split debug information, if at all. Specifying `None` has /// target-specific meaning. pub split_debuginfo: SplitDebuginfo, + /// Which kinds of split debuginfo are supported by the target? + pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>, /// The sanitizers supported by this target /// @@ -1473,15 +1575,11 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati match flavor { LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)), LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)), - LinkerFlavor::Lld(LldFlavor::Wasm) => {} + LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Lld(LldFlavor::Wasm) => {} LinkerFlavor::Lld(lld_flavor) => { panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor) } - LinkerFlavor::Gcc - | LinkerFlavor::Em - | LinkerFlavor::L4Bender - | LinkerFlavor::BpfLinker - | LinkerFlavor::PtxLinker => {} + LinkerFlavor::Gcc | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {} } } @@ -1499,6 +1597,36 @@ impl TargetOptions { fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { add_link_args(&mut self.post_link_args, flavor, args); } + + fn update_from_cli(&mut self) { + self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json); + for (args, args_json) in [ + (&mut self.pre_link_args, &self.pre_link_args_json), + (&mut self.late_link_args, &self.late_link_args_json), + (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json), + (&mut self.late_link_args_static, &self.late_link_args_static_json), + (&mut self.post_link_args, &self.post_link_args_json), + ] { + *args = args_json + .iter() + .map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone())) + .collect(); + } + } + + fn update_to_cli(&mut self) { + self.linker_flavor_json = self.linker_flavor.to_cli(); + for (args, args_json) in [ + (&self.pre_link_args, &mut self.pre_link_args_json), + (&self.late_link_args, &mut self.late_link_args_json), + (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json), + (&self.late_link_args_static, &mut self.late_link_args_static_json), + (&self.post_link_args, &mut self.post_link_args_json), + ] { + *args_json = + args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect(); + } + } } impl Default for TargetOptions { @@ -1513,11 +1641,11 @@ impl Default for TargetOptions { env: "".into(), abi: "".into(), vendor: "unknown".into(), - linker_flavor: LinkerFlavor::Gcc, linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), + linker_flavor: LinkerFlavor::Gcc, + linker_flavor_json: LinkerFlavorCli::Gcc, lld_flavor: LldFlavor::Ld, - pre_link_args: LinkArgs::new(), - post_link_args: LinkArgs::new(), + linker_is_gnu: true, link_script: None, asm_args: cvs![], cpu: "generic".into(), @@ -1544,7 +1672,6 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, default_dwarf_version: 4, - linker_is_gnu: true, allows_weak_linkage: true, has_rpath: false, no_default_libraries: true, @@ -1554,12 +1681,19 @@ impl Default for TargetOptions { relro_level: RelroLevel::None, pre_link_objects: Default::default(), post_link_objects: Default::default(), - pre_link_objects_fallback: Default::default(), - post_link_objects_fallback: Default::default(), - crt_objects_fallback: None, + pre_link_objects_self_contained: Default::default(), + post_link_objects_self_contained: Default::default(), + link_self_contained: LinkSelfContainedDefault::False, + pre_link_args: LinkArgs::new(), + pre_link_args_json: LinkArgsCli::new(), late_link_args: LinkArgs::new(), + late_link_args_json: LinkArgsCli::new(), late_link_args_dynamic: LinkArgs::new(), + late_link_args_dynamic_json: LinkArgsCli::new(), late_link_args_static: LinkArgs::new(), + late_link_args_static_json: LinkArgsCli::new(), + post_link_args: LinkArgs::new(), + post_link_args_json: LinkArgsCli::new(), link_env: cvs![], link_env_remove: cvs![], archive_format: "gnu".into(), @@ -1598,7 +1732,10 @@ impl Default for TargetOptions { use_ctors_section: false, eh_frame_header: true, has_thumb_interworking: false, - split_debuginfo: SplitDebuginfo::Off, + debuginfo_kind: Default::default(), + split_debuginfo: Default::default(), + // `Off` is supported by default, but targets can remove this manually, e.g. Windows. + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), supported_sanitizers: SanitizerSet::empty(), default_adjusted_cabi: None, c_enum_min_bits: 32, @@ -1871,6 +2008,19 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, DebuginfoKind) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::() { + Ok(level) => base.$key_name = level, + _ => return Some(Err( + format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \ + 'dwarf-dsym' or 'pdb'.") + )), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, SplitDebuginfo) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -1907,6 +2057,25 @@ impl Target { } } } ); + ($key_name:ident, falliable_list) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|j| { + if let Some(v) = j.as_array() { + match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() { + Ok(l) => { base.$key_name = l }, + // FIXME: `falliable_list` can't re-use the `key!` macro for list + // elements and the error messages from that macro, so it has a bad + // generic message instead + Err(_) => return Some(Err( + format!("`{:?}` is not a valid value for `{}`", j, name) + )), + } + } else { + incorrect_type.push(name) + } + Some(Ok(())) + }).unwrap_or(Ok(())) + } ); ($key_name:ident, optional) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(o) = obj.remove(&name) { @@ -1929,13 +2098,13 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); - ($key_name:ident, LinkerFlavor) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match LinkerFlavor::from_str(s) { + ($key_name:ident = $json_name:expr, LinkerFlavor) => ( { + let name = $json_name; + obj.remove(name).and_then(|o| o.as_str().and_then(|s| { + match LinkerFlavorCli::from_str(s) { Some(linker_flavor) => base.$key_name = linker_flavor, _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \ - Use {}", s, LinkerFlavor::one_of()))), + Use {}", s, LinkerFlavorCli::one_of()))), } Some(Ok(())) })).unwrap_or(Ok(())) @@ -1977,20 +2146,20 @@ impl Target { Ok::<(), String>(()) } ); - ($key_name:ident, crt_objects_fallback) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match s.parse::() { - Ok(fallback) => base.$key_name = Some(fallback), - _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \ - Use 'musl', 'mingw' or 'wasm'", s))), + ($key_name:ident = $json_name:expr, link_self_contained) => ( { + let name = $json_name; + obj.remove(name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::() { + Ok(lsc_default) => base.$key_name = lsc_default, + _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \ + Use 'false', 'true', 'musl' or 'mingw'", s))), } Some(Ok(())) })).unwrap_or(Ok(())) } ); - ($key_name:ident, link_objects) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(val) = obj.remove(&name) { + ($key_name:ident = $json_name:expr, link_objects) => ( { + let name = $json_name; + if let Some(val) = obj.remove(name) { let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ JSON object with fields per CRT object kind.", name))?; let mut args = CrtObjects::new(); @@ -2016,14 +2185,14 @@ impl Target { base.$key_name = args; } } ); - ($key_name:ident, link_args) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(val) = obj.remove(&name) { + ($key_name:ident = $json_name:expr, link_args) => ( { + let name = $json_name; + if let Some(val) = obj.remove(name) { let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ JSON object with fields per linker-flavor.", name))?; - let mut args = LinkArgs::new(); + let mut args = LinkArgsCli::new(); for (k, v) in obj { - let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| { + let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| { format!("{}: '{}' is not a valid value for linker-flavor. \ Use 'em', 'gcc', 'ld' or 'msvc'", name, k) })?; @@ -2109,19 +2278,20 @@ impl Target { key!(env); key!(abi); key!(vendor); - key!(linker_flavor, LinkerFlavor)?; key!(linker, optional); + key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?; key!(lld_flavor, LldFlavor)?; - key!(pre_link_objects, link_objects); - key!(post_link_objects, link_objects); - key!(pre_link_objects_fallback, link_objects); - key!(post_link_objects_fallback, link_objects); - key!(crt_objects_fallback, crt_objects_fallback)?; - key!(pre_link_args, link_args); - key!(late_link_args, link_args); - key!(late_link_args_dynamic, link_args); - key!(late_link_args_static, link_args); - key!(post_link_args, link_args); + key!(linker_is_gnu, bool); + key!(pre_link_objects = "pre-link-objects", link_objects); + key!(post_link_objects = "post-link-objects", link_objects); + key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects); + key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects); + key!(link_self_contained = "crt-objects-fallback", link_self_contained)?; + key!(pre_link_args_json = "pre-link-args", link_args); + key!(late_link_args_json = "late-link-args", link_args); + key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args); + key!(late_link_args_static_json = "late-link-args-static", link_args); + key!(post_link_args_json = "post-link-args", link_args); key!(link_script, optional); key!(link_env, env); key!(link_env_remove, list); @@ -2149,7 +2319,6 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_wasm, bool); key!(default_dwarf_version, u32); - key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); key!(no_default_libraries, bool); @@ -2193,7 +2362,9 @@ impl Target { key!(use_ctors_section, bool); key!(eh_frame_header, bool); key!(has_thumb_interworking, bool); + key!(debuginfo_kind, DebuginfoKind)?; key!(split_debuginfo, SplitDebuginfo)?; + key!(supported_split_debuginfo, falliable_list)?; key!(supported_sanitizers, SanitizerSet)?; key!(default_adjusted_cabi, Option)?; key!(c_enum_min_bits, u64); @@ -2204,6 +2375,8 @@ impl Target { // This can cause unfortunate ICEs later down the line. return Err("may not set is_builtin for targets not built-in".into()); } + base.update_from_cli(); + // Each field should have been read using `Json::remove` so any keys remaining are unused. let remaining_keys = obj.keys(); Ok(( @@ -2219,7 +2392,7 @@ impl Target { load_builtin(target_triple).expect("built-in target") } TargetTriple::TargetJson { .. } => { - panic!("built-in targets doens't support target-paths") + panic!("built-in targets doesn't support target-paths") } } } @@ -2295,42 +2468,44 @@ impl ToJson for Target { fn to_json(&self) -> Json { let mut d = serde_json::Map::new(); let default: TargetOptions = Default::default(); + let mut target = self.clone(); + target.update_to_cli(); macro_rules! target_val { ($attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - d.insert(name, self.$attr.to_json()); + d.insert(name, target.$attr.to_json()); }}; } macro_rules! target_option_val { ($attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - d.insert(name, self.$attr.to_json()); + if default.$attr != target.$attr { + d.insert(name, target.$attr.to_json()); } }}; - ($attr:ident, $key_name:expr) => {{ - let name = $key_name; - if default.$attr != self.$attr { - d.insert(name.into(), self.$attr.to_json()); + ($attr:ident, $json_name:expr) => {{ + let name = $json_name; + if default.$attr != target.$attr { + d.insert(name.into(), target.$attr.to_json()); } }}; - (link_args - $attr:ident) => {{ - let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - let obj = self + (link_args - $attr:ident, $json_name:expr) => {{ + let name = $json_name; + if default.$attr != target.$attr { + let obj = target .$attr .iter() .map(|(k, v)| (k.desc().to_string(), v.clone())) .collect::>(); - d.insert(name, obj.to_json()); + d.insert(name.to_string(), obj.to_json()); } }}; (env - $attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - let obj = self + if default.$attr != target.$attr { + let obj = target .$attr .iter() .map(|&(ref k, ref v)| format!("{k}={v}")) @@ -2352,19 +2527,20 @@ impl ToJson for Target { target_option_val!(env); target_option_val!(abi); target_option_val!(vendor); - target_option_val!(linker_flavor); target_option_val!(linker); + target_option_val!(linker_flavor_json, "linker-flavor"); target_option_val!(lld_flavor); + target_option_val!(linker_is_gnu); target_option_val!(pre_link_objects); target_option_val!(post_link_objects); - target_option_val!(pre_link_objects_fallback); - target_option_val!(post_link_objects_fallback); - target_option_val!(crt_objects_fallback); - target_option_val!(link_args - pre_link_args); - target_option_val!(link_args - late_link_args); - target_option_val!(link_args - late_link_args_dynamic); - target_option_val!(link_args - late_link_args_static); - target_option_val!(link_args - post_link_args); + target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback"); + target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback"); + target_option_val!(link_self_contained, "crt-objects-fallback"); + target_option_val!(link_args - pre_link_args_json, "pre-link-args"); + target_option_val!(link_args - late_link_args_json, "late-link-args"); + target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic"); + target_option_val!(link_args - late_link_args_static_json, "late-link-args-static"); + target_option_val!(link_args - post_link_args_json, "post-link-args"); target_option_val!(link_script); target_option_val!(env - link_env); target_option_val!(link_env_remove); @@ -2393,7 +2569,6 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(default_dwarf_version); - target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); target_option_val!(no_default_libraries); @@ -2437,7 +2612,9 @@ impl ToJson for Target { target_option_val!(use_ctors_section); target_option_val!(eh_frame_header); target_option_val!(has_thumb_interworking); + target_option_val!(debuginfo_kind); target_option_val!(split_debuginfo); + target_option_val!(supported_split_debuginfo); target_option_val!(supported_sanitizers); target_option_val!(c_enum_min_bits); target_option_val!(generate_arange_section); diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index edb30b72b..b3cd38a6e 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -1,4 +1,5 @@ -use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{DebuginfoKind, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly @@ -18,6 +19,8 @@ pub fn opts() -> TargetOptions { // Currently this is the only supported method of debuginfo on MSVC // where `*.pdb` files show up next to the final artifact. split_debuginfo: SplitDebuginfo::Packed, + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]), + debuginfo_kind: DebuginfoKind::Pdb, ..Default::default() } diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 1c5b68001..6ab3a8b7e 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { options: TargetOptions { os: "cuda".into(), vendor: "nvidia".into(), - linker_flavor: LinkerFlavor::PtxLinker, + linker_flavor: LinkerFlavor::Ptx, // The linker can be installed from `crates.io`. linker: Some("rust-ptx-linker".into()), linker_is_gnu: false, diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs new file mode 100644 index 000000000..9cb3a67dc --- /dev/null +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs @@ -0,0 +1,17 @@ +use crate::abi::Endian; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; + +pub fn target() -> Target { + let mut base = super::openbsd_base::opts(); + base.cpu = "ppc64".into(); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); + base.max_atomic_width = Some(64); + + Target { + llvm_target: "powerpc64-unknown-openbsd".into(), + pointer_width: 64, + data_layout: "E-m:e-i64:64-n32:64".into(), + arch: "powerpc64".into(), + options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, + } +} diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs index 516b2de37..75ac66c27 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs @@ -1,5 +1,5 @@ use crate::abi::Endian; -use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); @@ -15,7 +15,6 @@ pub fn target() -> Target { options: TargetOptions { endian: Endian::Big, features: "+secure-plt".into(), - relocation_model: RelocModel::Pic, mcount: "_mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs new file mode 100644 index 000000000..cd10f3afa --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs @@ -0,0 +1,18 @@ +use crate::spec::{CodeModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "riscv64-unknown-openbsd".into(), + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), + arch: "riscv64".into(), + options: TargetOptions { + code_model: Some(CodeModel::Medium), + cpu: "generic-rv64".into(), + features: "+m,+a,+f,+d,+c".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + ..super::openbsd_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 1db6db78b..0af599916 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -2,28 +2,31 @@ use super::super::*; use std::assert_matches::assert_matches; // Test target self-consistency and JSON encoding/decoding roundtrip. -pub(super) fn test_target(target: Target) { - target.check_consistency(); - assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target)); +pub(super) fn test_target(mut target: Target, triple: &str) { + let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j); + target.update_to_cli(); + target.check_consistency(triple); + assert_eq!(recycled_target, Ok(target)); } impl Target { - fn check_consistency(&self) { + fn check_consistency(&self, triple: &str) { assert_eq!(self.is_like_osx, self.vendor == "apple"); assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos"); assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi"); assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64"); - assert!(self.is_like_windows || !self.is_like_msvc); + if self.is_like_msvc { + assert!(self.is_like_windows); + } // Check that default linker flavor and lld flavor are compatible // with some other key properties. assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64)); assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link)); assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm)); - assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender)); - assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em)); - assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker)); - assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker)); + assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc)); + assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf)); + assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx)); for args in [ &self.pre_link_args, @@ -63,17 +66,14 @@ impl Target { LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc ) } - (LinkerFlavor::L4Bender, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::L4Bender) - } - (LinkerFlavor::Em, LldFlavor::Wasm) => { - assert_matches!(flavor, LinkerFlavor::Em) + (LinkerFlavor::EmCc, LldFlavor::Wasm) => { + assert_matches!(flavor, LinkerFlavor::EmCc) } - (LinkerFlavor::BpfLinker, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::BpfLinker) + (LinkerFlavor::Bpf, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::Bpf) } - (LinkerFlavor::PtxLinker, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::PtxLinker) + (LinkerFlavor::Ptx, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::Ptx) } flavors => unreachable!("unexpected flavor combination: {:?}", flavors), } @@ -94,8 +94,9 @@ impl Target { check_noncc(LinkerFlavor::Ld); check_noncc(LinkerFlavor::Lld(LldFlavor::Ld)); } + LldFlavor::Ld64 => check_noncc(LinkerFlavor::Lld(LldFlavor::Ld64)), LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)), - LldFlavor::Ld64 | LldFlavor::Link => {} + LldFlavor::Link => {} }, _ => {} } @@ -109,20 +110,57 @@ impl Target { ); } - assert!( - (self.pre_link_objects_fallback.is_empty() - && self.post_link_objects_fallback.is_empty()) - || self.crt_objects_fallback.is_some() - ); + if self.link_self_contained == LinkSelfContainedDefault::False { + assert!( + self.pre_link_objects_self_contained.is_empty() + && self.post_link_objects_self_contained.is_empty() + ); + } // If your target really needs to deviate from the rules below, // except it and document the reasons. // Keep the default "unknown" vendor instead. assert_ne!(self.vendor, ""); + assert_ne!(self.os, ""); if !self.can_use_os_unknown() { // Keep the default "none" for bare metal targets instead. assert_ne!(self.os, "unknown"); } + + // Check dynamic linking stuff + // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries. + if self.os == "none" && self.arch != "bpf" { + assert!(!self.dynamic_linking); + } + if self.only_cdylib + || self.crt_static_allows_dylibs + || !self.late_link_args_dynamic.is_empty() + { + assert!(self.dynamic_linking); + } + // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs + if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") { + assert_eq!(self.relocation_model, RelocModel::Pic); + } + // PIEs are supported but not enabled by default with linuxkernel target. + if self.position_independent_executables && !triple.ends_with("-linuxkernel") { + assert_eq!(self.relocation_model, RelocModel::Pic); + } + // The UEFI targets do not support dynamic linking but still require PIC (#101377). + if self.relocation_model == RelocModel::Pic && self.os != "uefi" { + assert!(self.dynamic_linking || self.position_independent_executables); + } + if self.static_position_independent_executables { + assert!(self.position_independent_executables); + } + if self.position_independent_executables { + assert!(self.executables); + } + + // Check crt static stuff + if self.crt_static_default || self.crt_static_allows_dylibs { + assert!(self.crt_static_respected); + } } // Add your target to the whitelist if it has `std` library diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index 7125d141a..bdaaed8b5 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -47,7 +47,9 @@ pub fn target() -> Target { asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",], // minimum extra features, these cannot be disabled via -C - features: "+soft-float,+strict-align".into(), + // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+soft-float,+strict-align,+atomics-32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs index 2546ab9b7..c9bb0112f 100644 --- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs @@ -13,7 +13,9 @@ pub fn target() -> Target { abi: "eabi".into(), // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them // with +strict-align. - features: "+strict-align".into(), + // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+strict-align,+atomics-32".into(), // There are no atomic CAS instructions available in the instruction set of the ARMv6-M // architecture atomic_cas: false, diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index aee8eb2e3..99af7d85e 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -9,7 +9,8 @@ // the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all // code runs in the same environment, no process separation is supported. -use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, TargetOptions}; +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy}; +use crate::spec::{StackProbeType, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::msvc_base::opts(); diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index c7e7d2210..6f77ef98c 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -5,13 +5,13 @@ pub fn target() -> Target { // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. let pre_link_args = LinkArgs::new(); let post_link_args = TargetOptions::link_args( - LinkerFlavor::Em, + LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], ); let opts = TargetOptions { os: "emscripten".into(), - linker_flavor: LinkerFlavor::Em, + linker_flavor: LinkerFlavor::EmCc, // emcc emits two files - a .js file to instantiate the wasm and supply platform // functionality, and a .wasm file. exe_suffix: ".js".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 280457d68..9c30487f4 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -82,8 +82,8 @@ pub fn target() -> Target { options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]); - options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback(); - options.post_link_objects_fallback = crt_objects::post_wasi_fallback(); + options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained(); + options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained(); // Right now this is a bit of a workaround but we're currently saying that // the target by default has a static crt which we're taking as a signal diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index 9216d3e7b..28a07701e 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -1,4 +1,4 @@ -use super::crt_objects::CrtObjectsFallback; +use super::crt_objects::LinkSelfContainedDefault; use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; pub fn options() -> TargetOptions { @@ -96,7 +96,8 @@ pub fn options() -> TargetOptions { pre_link_args, - crt_objects_fallback: Some(CrtObjectsFallback::Wasm), + // FIXME: Figure out cases in which WASM needs to link with a native toolchain. + link_self_contained: LinkSelfContainedDefault::True, // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when // PIC code is implemented this has quite a drastic effect if it stays diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 90e0af3e3..81d44a963 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -1,5 +1,6 @@ -use crate::spec::crt_objects::{self, CrtObjectsFallback}; -use crate::spec::{cvs, LinkerFlavor, TargetOptions}; +use crate::spec::crt_objects::{self, LinkSelfContainedDefault}; +use crate::spec::{cvs, DebuginfoKind, LinkerFlavor, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { let mut pre_link_args = TargetOptions::link_args( @@ -76,9 +77,9 @@ pub fn opts() -> TargetOptions { pre_link_args, pre_link_objects: crt_objects::pre_mingw(), post_link_objects: crt_objects::post_mingw(), - pre_link_objects_fallback: crt_objects::pre_mingw_fallback(), - post_link_objects_fallback: crt_objects::post_mingw_fallback(), - crt_objects_fallback: Some(CrtObjectsFallback::Mingw), + pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(), + post_link_objects_self_contained: crt_objects::post_mingw_self_contained(), + link_self_contained: LinkSelfContainedDefault::Mingw, late_link_args, late_link_args_dynamic, late_link_args_static, @@ -86,6 +87,10 @@ pub fn opts() -> TargetOptions { emit_debug_gdb_scripts: false, requires_uwtable: true, eh_frame_header: false, + // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to + // output DWO, despite using DWARF, doesn't use ELF.. + debuginfo_kind: DebuginfoKind::Pdb, + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs index bae007dc9..f30be2549 100644 --- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -3,7 +3,7 @@ use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { // We cannot use `-nodefaultlibs` because compiler-rt has to be passed // as a path since it's not added to linker search path by the default. - // There were attemts to make it behave like libgcc (so one can just use -l) + // There were attempts to make it behave like libgcc (so one can just use -l) // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]); diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index dbd26899c..176c9dd6b 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -2,11 +2,12 @@ use crate::spec::TargetOptions; use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + let arch = "x86_64"; + let mut base = super::apple_base::opts("macos", arch, ""); base.cpu = "core2".into(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.frame_pointer = FramePointer::Always; - base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; @@ -16,7 +17,6 @@ pub fn target() -> Target { // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work // correctly, we do too. - let arch = "x86_64"; let llvm_target = super::apple_base::macos_llvm_target(&arch); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 78189a0c0..26da7e800 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -4,8 +4,6 @@ pub fn target() -> Target { let mut base = super::l4re_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.crt_static_allows_dylibs = false; - base.dynamic_linking = false; base.panic_strategy = PanicStrategy::Abort; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index 809fd642d..b9a345127 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -4,10 +4,8 @@ // `target-cpu` compiler flags to opt-in more hardware-specific // features. -use super::{ - CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType, - Target, TargetOptions, -}; +use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy}; +use super::{RelroLevel, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let opts = TargetOptions { @@ -18,7 +16,6 @@ pub fn target() -> Target { position_independent_executables: true, static_position_independent_executables: true, relro_level: RelroLevel::Full, - relocation_model: RelocModel::Pic, linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), features: diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 8b7e8984a..36ab8f3bd 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -1,6 +1,6 @@ +use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, TraitEngine}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; @@ -222,19 +222,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa Limit(0) => Limit(2), limit => limit * 2, }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(AutoDerefReachedRecursionLimit { span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - ty - ) - .span_label(span, "deref recursion limit reached") - .help(&format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + ty, suggested_limit, - tcx.crate_name(LOCAL_CRATE), - )) - .emit(); + crate_name: tcx.crate_name(LOCAL_CRATE), + }); } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs new file mode 100644 index 000000000..ab0afc545 --- /dev/null +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -0,0 +1,102 @@ +use rustc_errors::{fluent, ErrorGuaranteed, Handler}; +use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated}; +use rustc_session::{Limit, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::dump_vtable_entries)] +pub struct DumpVTableEntries<'a> { + #[primary_span] + pub span: Span, + pub trait_ref: PolyTraitRef<'a>, + pub entries: String, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::unable_to_construct_constant_value)] +pub struct UnableToConstructConstantValue<'a> { + #[primary_span] + pub span: Span, + pub unevaluated: Unevaluated<'a>, +} + +#[derive(SessionDiagnostic)] +#[help] +#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")] +pub struct AutoDerefReachedRecursionLimit<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'a>, + pub suggested_limit: Limit, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct EmptyOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct InvalidOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")] +#[note] +pub struct NoValueInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +pub struct NegativePositiveConflict<'a> { + pub impl_span: Span, + pub trait_desc: &'a str, + pub self_desc: &'a Option, + pub negative_impl_span: Result, + pub positive_impl_span: Result, +} + +impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> { + fn into_diagnostic( + self, + handler: &Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict); + diag.set_arg("trait_desc", self.trait_desc); + diag.set_arg( + "self_desc", + self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty), + ); + diag.set_span(self.impl_span); + diag.code(rustc_errors::error_code!(E0751)); + match self.negative_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::negative_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::negative_implementation_in_crate); + diag.set_arg("negative_impl_cname", cname.to_string()); + } + } + match self.positive_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::positive_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::positive_implementation_in_crate); + diag.set_arg("positive_impl_cname", cname.to_string()); + } + } + diag + } +} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9d30374f8..ba403ab2d 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -24,6 +24,13 @@ pub trait InferCtxtExt<'tcx> { span: Span, ) -> bool; + fn type_is_sized_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool; + fn partially_normalize_associated_types_in( &self, cause: ObligationCause<'tcx>, @@ -74,6 +81,16 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) } + fn type_is_sized_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool { + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) + } + /// Normalizes associated types in `value`, potentially returning /// new obligations that must further be processed. fn partially_normalize_associated_types_in( diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 282ee632c..d35f74974 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -16,11 +16,12 @@ #![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(hash_drain_filter)] -#![feature(label_break_value)] +#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(if_let_guard)] #![feature(never_type)] +#![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc #[macro_use] @@ -36,5 +37,6 @@ extern crate rustc_middle; extern crate smallvec; pub mod autoderef; +pub mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 294c81d0b..bcdfa4f12 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -3,13 +3,14 @@ use super::*; +use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{Region, RegionVid, Term}; +use rustc_middle::ty::{Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -205,10 +206,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. - let mut fulfill = >::new(tcx); - fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); - let errors = fulfill.select_all_or_error(&infcx); - + let errors = + super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); if !errors.is_empty() { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } @@ -343,7 +342,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } - let obligations = impl_source.clone().nested_obligations().into_iter(); + let obligations = impl_source.borrow_nested_obligations().iter().cloned(); if !self.evaluate_nested_obligations( ty, @@ -613,7 +612,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - if let Term::Ty(ty) = p.term().skip_binder() { + if let Some(ty) = p.term().skip_binder().ty() { matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty) } else { false @@ -832,8 +831,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def.did; - let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit(); - + let reported = + tcx.sess.emit_err(UnableToConstructConstantValue { + span: tcx.def_span(def_id), + unevaluated: unevaluated.expand(), + }); Err(ErrorHandled::Reported(reported)) } Err(err) => Err(err), diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index c0700748c..08adbcbd4 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -18,8 +18,7 @@ use rustc_middle::ty::{self, TyCtxt}; /// obligations *could be* resolved if we wanted to. /// /// This also expects that `trait_ref` is fully normalized. -#[instrument(level = "debug", skip(tcx))] -pub fn codegen_fulfill_obligation<'tcx>( +pub fn codegen_select_candidate<'tcx>( tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { @@ -74,7 +73,6 @@ pub fn codegen_fulfill_obligation<'tcx>( // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); Ok(&*tcx.arena.alloc(impl_source)) }) } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 1c8cdf4ca..292787d4d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,18 +6,20 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{CombinedSnapshot, InferOk}; +use crate::traits::outlives_bounds::InferCtxtExt as _; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_subject_and_oblig; use crate::traits::SkipLeakCheck; use crate::traits::{ - self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, - PredicateObligations, SelectionContext, TraitEngineExt, + self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, + PredicateObligations, SelectionContext, }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, TraitEngine}; +use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::subst::Subst; @@ -302,13 +304,18 @@ fn negative_impl<'cx, 'tcx>( let impl_env = tcx.param_env(impl1_def_id); let subject1 = match traits::fully_normalize( &infcx, - FulfillmentContext::new(), ObligationCause::dummy(), impl_env, tcx.impl_subject(impl1_def_id), ) { Ok(s) => s, - Err(err) => bug!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), + Err(err) => { + tcx.sess.delay_span_bug( + tcx.def_span(impl1_def_id), + format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), + ); + return false; + } }; // Attempt to prove that impl2 applies, given all of the above. @@ -317,7 +324,7 @@ fn negative_impl<'cx, 'tcx>( let (subject2, obligations) = impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); - !equate(&infcx, impl_env, subject1, subject2, obligations) + !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) }) } @@ -327,6 +334,7 @@ fn equate<'cx, 'tcx>( subject1: ImplSubject<'tcx>, subject2: ImplSubject<'tcx>, obligations: impl Iterator>, + body_def_id: DefId, ) -> bool { // do the impls unify? If not, not disjoint. let Ok(InferOk { obligations: more_obligations, .. }) = @@ -340,7 +348,7 @@ fn equate<'cx, 'tcx>( let opt_failing_obligation = obligations .into_iter() .chain(more_obligations) - .find(|o| negative_impl_exists(selcx, impl_env, o)); + .find(|o| negative_impl_exists(selcx, o, body_def_id)); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); @@ -354,18 +362,16 @@ fn equate<'cx, 'tcx>( #[instrument(level = "debug", skip(selcx))] fn negative_impl_exists<'cx, 'tcx>( selcx: &SelectionContext<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, o: &PredicateObligation<'tcx>, + body_def_id: DefId, ) -> bool { - let infcx = &selcx.infcx().fork(); - - if resolve_negative_obligation(infcx, param_env, o) { + if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) { return true; } // Try to prove a negative obligation exists for super predicates - for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { - if resolve_negative_obligation(infcx, param_env, &o) { + for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) { + if resolve_negative_obligation(selcx.infcx().fork(), &o, body_def_id) { return true; } } @@ -375,9 +381,9 @@ fn negative_impl_exists<'cx, 'tcx>( #[instrument(level = "debug", skip(infcx))] fn resolve_negative_obligation<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + infcx: InferCtxt<'cx, 'tcx>, o: &PredicateObligation<'tcx>, + body_def_id: DefId, ) -> bool { let tcx = infcx.tcx; @@ -385,17 +391,25 @@ fn resolve_negative_obligation<'cx, 'tcx>( return false; }; - let mut fulfillment_cx = >::new(infcx.tcx); - fulfillment_cx.register_predicate_obligation(infcx, o); - - let errors = fulfillment_cx.select_all_or_error(infcx); - - if !errors.is_empty() { + let param_env = o.param_env; + if !super::fully_solve_obligation(&infcx, o).is_empty() { return false; } - // FIXME -- also add "assumed to be well formed" types into the `outlives_env` - let outlives_env = OutlivesEnvironment::new(param_env); + let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() { + (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id) + } else { + (CRATE_HIR_ID, CRATE_DEF_ID) + }; + + let ocx = ObligationCtxt::new(&infcx); + let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys(param_env, body_id, wf_tys), + ); + infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); infcx.resolve_regions(&outlives_env).is_empty() @@ -404,12 +418,12 @@ fn resolve_negative_obligation<'cx, 'tcx>( pub fn trait_ref_is_knowable<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, -) -> Option { +) -> Result<(), Conflict> { debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { // A downstream or cousin crate is allowed to implement some // substitution of this trait-ref. - return Some(Conflict::Downstream); + return Err(Conflict::Downstream); } if trait_ref_is_local_or_fundamental(tcx, trait_ref) { @@ -418,7 +432,7 @@ pub fn trait_ref_is_knowable<'tcx>( // allowed to implement a substitution of this trait ref, which // means impls could only come from dependencies of this crate, // which we already know about. - return None; + return Ok(()); } // This is a remote non-fundamental trait, so if another crate @@ -431,10 +445,10 @@ pub fn trait_ref_is_knowable<'tcx>( // we are an owner. if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() { debug!("trait_ref_is_knowable: orphan check passed"); - None + Ok(()) } else { debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned"); - Some(Conflict::Upstream) + Err(Conflict::Upstream) } } @@ -740,7 +754,21 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { result } - // FIXME: Constants should participate in orphan checking. + /// All possible values for a constant parameter already exist + /// in the crate defining the trait, so they are always non-local[^1]. + /// + /// Because there's no way to have an impl where the first local + /// generic argument is a constant, we also don't have to fail + /// the orphan check when encountering a parameter or a generic constant. + /// + /// This means that we can completely ignore constants during the orphan check. + /// + /// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples. + /// + /// [^1]: This might not hold for function pointers or trait objects in the future. + /// As these should be quite rare as const arguments and especially rare as impl + /// parameters, allowing uncovered const parameters in impls seems more useful + /// than allowing `impl Trait for i32` to compile. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { ControlFlow::CONTINUE } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 254bc4ab6..5a213987e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -183,7 +183,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( FailureKind::Concrete => {} } } - let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { Err(ErrorHandled::TooGeneric) => { Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( @@ -210,7 +210,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // and hopefully soon change this to an error. // // See #74595 for more details about this. - let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { // If we're evaluating a foreign constant, under a nightly compiler without generic diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 6c177f638..dba4d4f69 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -3,7 +3,8 @@ use std::cell::RefCell; use super::TraitEngine; use super::{ChalkFulfillmentContext, FulfillmentContext}; use crate::infer::InferCtxtExt; -use rustc_hir::def_id::DefId; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, @@ -12,9 +13,11 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; pub trait TraitEngineExt<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box; + fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { @@ -25,6 +28,14 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { Box::new(FulfillmentContext::new()) } } + + fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box { + if tcx.sess.opts.unstable_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new_in_snapshot()) + } + } } /// Used if you want to have pleasant experience when dealing @@ -39,6 +50,10 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } } + pub fn new_in_snapshot(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx.tcx)) } + } + pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); } @@ -109,4 +124,34 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { pub fn select_all_or_error(&self) -> Vec> { self.engine.borrow_mut().select_all_or_error(self.infcx) } + + pub fn assumed_wf_types( + &self, + param_env: ty::ParamEnv<'tcx>, + span: Span, + def_id: LocalDefId, + ) -> FxHashSet> { + let tcx = self.infcx.tcx; + let assumed_wf_types = tcx.assumed_wf_types(def_id); + let mut implied_bounds = FxHashSet::default(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let cause = ObligationCause::misc(span, hir_id); + for ty in assumed_wf_types { + // FIXME(@lcnr): rustc currently does not check wf for types + // pre-normalization, meaning that implied bounds are sometimes + // incorrect. See #100910 for more details. + // + // Not adding the unnormalized types here mostly fixes that, except + // that there are projections which are still ambiguous in the item definition + // but do normalize successfully when using the item, see #98543. + // + // Anyways, I will hopefully soon change implied bounds to make all of this + // sound and then uncomment this line again. + + // implied_bounds.insert(ty); + let normalized = self.normalize(cause.clone(), param_env, ty); + implied_bounds.insert(normalized); + } + implied_bounds + } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e442c5c91..efdb1ace1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; +use rustc_infer::infer::TypeTrace; use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -348,7 +349,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { message, label, note, - enclosing_scope, + parent_label, append_const_msg, } = self.on_unimplemented_note(trait_ref, &obligation); let have_alt_message = message.is_some() || label.is_some(); @@ -449,12 +450,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { { "consider using `()`, or a `Result`".to_owned() } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), - ) + let ty_desc = match trait_ref.skip_binder().self_ty().kind() { + ty::FnDef(_, _) => Some("fn item"), + ty::Closure(_, _) => Some("closure"), + _ => None, + }; + + match ty_desc { + Some(desc) => format!( + "{}the trait `{}` is not implemented for {} `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + desc, + trait_ref.skip_binder().self_ty(), + ), + None => format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + } }; if self.suggest_add_reference_to_arg( @@ -514,7 +530,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); } - if let Some(ref s) = enclosing_scope { + if let Some(ref s) = parent_label { let body = tcx .hir() .opt_local_def_id(obligation.cause.body_id) @@ -523,11 +539,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { hir_id: obligation.cause.body_id, }) }); - - let enclosing_scope_span = - tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); - - err.span_label(enclosing_scope_span, s); + err.span_label(tcx.def_span(body), s); } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); @@ -859,8 +871,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - err.emit(); - return; + err } ty::PredicateKind::WellFormed(ty) => { @@ -941,9 +952,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + let mut not_tupled = false; + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => vec![ArgKind::empty()], + _ => { + not_tupled = true; + vec![ArgKind::empty()] + } }; let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); @@ -951,10 +967,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Tuple(ref tys) => { tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() } - _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], + _ => { + not_tupled = true; + vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())] + } }; - if found.len() == expected.len() { + // If this is a `Fn` family trait and either the expected or found + // is not tupled, then fall back to just a regular mismatch error. + // This shouldn't be common unless manually implementing one of the + // traits manually, but don't make it more confusing when it does + // happen. + if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled { + self.report_and_explain_type_error( + TypeTrace::poly_trait_refs( + &obligation.cause, + true, + expected_trait_ref, + found_trait_ref, + ), + ty::error::TypeError::Mismatch, + ) + } else if found.len() == expected.len() { self.report_closure_arg_mismatch( span, found_span, @@ -1315,6 +1349,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> { error: &MismatchedProjectionTypes<'tcx>, ); + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option; + fn fuzzy_match_tys( &self, a: Ty<'tcx>, @@ -1476,13 +1517,28 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { .emit(); } FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => { - self.report_mismatched_consts( + let mut diag = self.report_mismatched_consts( &error.obligation.cause, expected_found.expected, expected_found.found, err.clone(), - ) - .emit(); + ); + let code = error.obligation.cause.code().peel_derives().peel_match_impls(); + if let ObligationCauseCode::BindingObligation(..) + | ObligationCauseCode::ItemObligation(..) + | ObligationCauseCode::ExprBindingObligation(..) + | ObligationCauseCode::ExprItemObligation(..) = code + { + self.note_obligation_cause_code( + &mut diag, + &error.obligation.predicate, + error.obligation.param_env, + code, + &mut vec![], + &mut Default::default(), + ); + } + diag.emit(); } } } @@ -1500,8 +1556,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } self.probe(|_| { - let err_buf; - let mut err = &error.err; + let mut err = error.err; let mut values = None; // try to find the mismatched types to report the error with. @@ -1534,31 +1589,28 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { obligation.cause.code().peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ExprItemObligation(..) + | ObligationCauseCode::ExprBindingObligation(..) | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( + if let Err(new_err) = self.at(&obligation.cause, obligation.param_env).eq_exp( is_normalized_ty_expected, normalized_ty, data.term, ) { - values = Some(infer::ValuePairs::Terms(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.term, - ))); - err_buf = error; - err = &err_buf; + values = Some((data, is_normalized_ty_expected, normalized_ty, data.term)); + err = new_err; } } - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); + let msg = values + .and_then(|(predicate, _, normalized_ty, expected_ty)| { + self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty) + }) + .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); + let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); + let secondary_span = match predicate.kind().skip_binder() { ty::PredicateKind::Projection(proj) => self .tcx @@ -1596,7 +1648,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &mut diag, &obligation.cause, secondary_span, - values, + values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| { + infer::ValuePairs::Terms(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + term, + )) + }), err, true, false, @@ -1606,6 +1664,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }); } + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option { + let trait_def_id = pred.projection_ty.trait_def_id(self.tcx); + let self_ty = pred.projection_ty.self_ty(); + + if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() { + Some(format!( + "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`", + fn_kind = self_ty.prefix_string(self.tcx) + )) + } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + Some(format!( + "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`" + )) + } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + Some(format!( + "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`" + )) + } else { + None + } + } + fn fuzzy_match_tys( &self, mut a: Ty<'tcx>, @@ -1731,13 +1816,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { return false; } if candidates.len() == 1 { + let ty_desc = match candidates[0].self_ty().kind() { + ty::FnPtr(_) => Some("fn pointer"), + _ => None, + }; + let the_desc = match ty_desc { + Some(desc) => format!(" implemented for {} `", desc), + None => " implemented for `".to_string(), + }; err.highlighted_help(vec![ ( format!("the trait `{}` ", candidates[0].print_only_trait_path()), Style::NoStyle, ), ("is".to_string(), Style::Highlight), - (" implemented for `".to_string(), Style::NoStyle), + (the_desc, Style::NoStyle), (candidates[0].self_ty().to_string(), Style::Highlight), ("`".to_string(), Style::NoStyle), ]); @@ -1802,9 +1895,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be generalized, both to // be more granular, and probably look past other `#[fundamental]` // types, too. - self.tcx - .visibility(def.did()) - .is_accessible_from(body_id.owner.to_def_id(), self.tcx) + self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx) } else { true } @@ -1940,7 +2031,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; - debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code())); + debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); // Ambiguity errors are often caused as fallout from earlier errors. // We ignore them if this `infcx` is tainted in some cases below. @@ -2033,13 +2124,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() { + if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let ( - Ok(ref snippet), - &ObligationCauseCode::BindingObligation(def_id, _), - ) = - (self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code()) + } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span) + && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..) + = *obligation.cause.code() { let generics = self.tcx.generics_of(def_id); if generics.params.iter().any(|p| p.name != kw::SelfUpper) @@ -2119,12 +2208,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { && let [ .., trait_path_segment @ hir::PathSegment { - res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)), + res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id), .. }, hir::PathSegment { ident: assoc_item_name, - res: Some(rustc_hir::def::Res::Def(_, item_id)), + res: rustc_hir::def::Res::Def(_, item_id), .. } ] = path.segments @@ -2462,15 +2551,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { - let ( - ty::PredicateKind::Trait(pred), - &ObligationCauseCode::BindingObligation(item_def_id, span), - ) = ( - obligation.predicate.kind().skip_binder(), - obligation.cause.code().peel_derives(), - ) else { - return; - }; + let ty::PredicateKind::Trait(pred) = obligation.predicate.kind().skip_binder() else { return; }; + let (ObligationCauseCode::BindingObligation(item_def_id, span) + | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) + = *obligation.cause.code().peel_derives() else { return; }; debug!(?pred, ?item_def_id, ?span); let (Some(node), true) = ( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index e6907637c..e11a42201 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -143,7 +143,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } if let ObligationCauseCode::ItemObligation(item) - | ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code() + | ObligationCauseCode::BindingObligation(item, _) + | ObligationCauseCode::ExprItemObligation(item, ..) + | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code() { // FIXME: maybe also have some way of handling methods // from other traits? That would require name resolution, @@ -254,7 +256,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - if let ty::Dynamic(traits, _) = self_ty.kind() { + if let ty::Dynamic(traits, _, _) = self_ty.kind() { for t in traits.iter() { if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 219413121..13d9c1600 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -20,13 +20,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::hir::map; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, - ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitable, + ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; @@ -174,7 +173,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - proj_pred: Option>, + associated_item: Option<(&'static str, Ty<'tcx>)>, body_id: hir::HirId, ); @@ -467,7 +466,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - proj_pred: Option>, + associated_ty: Option<(&'static str, Ty<'tcx>)>, body_id: hir::HirId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -604,21 +603,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_pred.print_modifiers_and_trait_path().to_string() ); - if let Some(proj_pred) = proj_pred { - let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder(); - let item = self.tcx.associated_item(projection_ty.item_def_id); - + if let Some((name, term)) = associated_ty { // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. // That should be extracted into a helper function. if constraint.ends_with('>') { constraint = format!( - "{}, {}={}>", + "{}, {} = {}>", &constraint[..constraint.len() - 1], - item.name, + name, term ); } else { - constraint.push_str(&format!("<{}={}>", item.name, term)); + constraint.push_str(&format!("<{} = {}>", name, term)); } } @@ -648,7 +644,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .. }) if !param_ty => { // Missing generic type parameter bound. - if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) { + if suggest_arbitrary_trait_bound( + self.tcx, + generics, + &mut err, + trait_pred, + associated_ty, + ) { return; } } @@ -671,11 +673,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It only make sense when suggesting dereferences for arguments - let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else { - return false; - }; - let param_env = obligation.param_env; - let body_id = obligation.cause.body_id; + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() + else { return false; }; + let Some(typeck_results) = self.in_progress_typeck_results + else { return false; }; + let typeck_results = typeck_results.borrow(); + let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) + else { return false; }; + let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) + else { return false; }; + let span = obligation.cause.span; let mut real_trait_pred = trait_pred; let mut code = obligation.cause.code(); @@ -685,11 +692,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { real_trait_pred = parent_trait_pred; } - // Skipping binder here, remapping below - let real_ty = real_trait_pred.self_ty().skip_binder(); + let real_ty = real_trait_pred.self_ty(); + // We `erase_late_bound_regions` here because `make_subregion` does not handle + // `ReLateBound`, and we don't particularly care about the regions. + if self + .can_eq(obligation.param_env, self.tcx.erase_late_bound_regions(real_ty), arg_ty) + .is_err() + { + continue; + } - if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); + if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() { + let mut autoderef = Autoderef::new( + self, + obligation.param_env, + obligation.cause.body_id, + span, + base_ty, + span, + ); if let Some(steps) = autoderef.find_map(|(ty, steps)| { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); @@ -697,24 +718,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Remapping bound vars here let real_trait_pred_and_ty = real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); - let obligation = self - .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty); + let obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + real_trait_pred_and_ty, + ); Some(steps).filter(|_| self.predicate_may_hold(&obligation)) }) { if steps > 0 { - if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { - // Don't care about `&mut` because `DerefMut` is used less - // often and user will not expect autoderef happens. - if src.starts_with('&') && !src.starts_with("&mut ") { - let derefs = "*".repeat(steps); - err.span_suggestion( - span, - "consider dereferencing here", - format!("&{}{}", derefs, &src[1..]), - Applicability::MachineApplicable, - ); - return true; - } + // Don't care about `&mut` because `DerefMut` is used less + // often and user will not expect autoderef happens. + if let Some(hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr), + .. + })) = self.tcx.hir().find(*arg_hir_id) + { + let derefs = "*".repeat(steps); + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "consider dereferencing here", + derefs, + Applicability::MachineApplicable, + ); + return true; } } } else if real_trait_pred != trait_pred { @@ -724,7 +750,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let real_trait_pred_and_base_ty = real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty)); let obligation = self.mk_trait_obligation_with_new_self_ty( - param_env, + obligation.param_env, real_trait_pred_and_base_ty, ); if self.predicate_may_hold(&obligation) { @@ -750,7 +776,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Get the local name of this closure. This can be inaccurate because // of the possibility of reassignment, but this should be good enough. match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => { + hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => { Some(ident.name) } _ => { @@ -852,6 +878,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => return false, }; if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) + && obligation.cause.span.can_be_used_for_suggestions() { // When the obligation error has been ensured to have been caused by // an argument, the `obligation.cause.span` points at the expression @@ -882,6 +909,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.cause.code() { &parent_code + } else if let ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() + { + obligation.cause.code() } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = span.ctxt().outer_expn_data().kind { @@ -906,102 +937,121 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let param_env = obligation.param_env; // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = - |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&old_pred.def_id()) { - return false; - } - // We map bounds to `&T` and `&mut T` - let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| { - ( - trait_pred, - self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), - ) - }); - let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| { + let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>, + blacklist: &[DefId]| + -> bool { + if blacklist.contains(&old_pred.def_id()) { + return false; + } + // We map bounds to `&T` and `&mut T` + let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| { + ( + trait_pred, + self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + ) + }); + let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| { + ( + trait_pred, + self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + ) + }); + + let mk_result = |trait_pred_and_new_ty| { + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); + self.predicate_must_hold_modulo_regions(&obligation) + }; + let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref); + let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); + + let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = + if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() + && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() + { ( - trait_pred, - self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), + matches!(mutability, hir::Mutability::Mut), ) - }); - - let mk_result = |trait_pred_and_new_ty| { - let obligation = - self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); - self.predicate_must_hold_modulo_regions(&obligation) + } else { + (false, false) }; - let imm_result = mk_result(trait_pred_and_imm_ref); - let mut_result = mk_result(trait_pred_and_mut_ref); - - if imm_result || mut_result { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - // We have a very specific type of error, where just borrowing this argument - // might solve the problem. In cases like this, the important part is the - // original type obligation, not the last one that failed, which is arbitrary. - // Because of this, we modify the error to refer to the original obligation and - // return early in the caller. - - let msg = format!("the trait bound `{}` is not satisfied", old_pred); - if has_custom_message { - err.note(&msg); - } else { - err.message = - vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)]; - } - if snippet.starts_with('&') { - // This is already a literal borrow and the obligation is failing - // somewhere else in the obligation chain. Do not suggest non-sense. - return false; - } - err.span_label( - span, + + if imm_ref_self_ty_satisfies_pred + || mut_ref_self_ty_satisfies_pred + || ref_inner_ty_satisfies_pred + { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + // We don't want a borrowing suggestion on the fields in structs, + // ``` + // struct Foo { + // the_foos: Vec + // } + // ``` + if !matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) + ) { + return false; + } + if snippet.starts_with('&') { + // This is already a literal borrow and the obligation is failing + // somewhere else in the obligation chain. Do not suggest non-sense. + return false; + } + // We have a very specific type of error, where just borrowing this argument + // might solve the problem. In cases like this, the important part is the + // original type obligation, not the last one that failed, which is arbitrary. + // Because of this, we modify the error to refer to the original obligation and + // return early in the caller. + + let msg = format!("the trait bound `{}` is not satisfied", old_pred); + if has_custom_message { + err.note(&msg); + } else { + err.message = + vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)]; + } + err.span_label( + span, + format!( + "the trait `{}` is not implemented for `{}`", + old_pred.print_modifiers_and_trait_path(), + old_pred.self_ty().skip_binder(), + ), + ); + + if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; + err.span_suggestion_verbose( + span.shrink_to_lo(), &format!( - "expected an implementor of trait `{}`", - old_pred.print_modifiers_and_trait_path(), + "consider{} borrowing here", + if is_mut { " mutably" } else { "" } ), + format!("&{}", if is_mut { "mut " } else { "" }), + Applicability::MaybeIncorrect, ); - - // This if is to prevent a special edge-case - if matches!( - span.ctxt().outer_expn_data().kind, - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) - ) { - // We don't want a borrowing suggestion on the fields in structs, - // ``` - // struct Foo { - // the_foos: Vec - // } - // ``` - - if imm_result && mut_result { - err.span_suggestions( - span.shrink_to_lo(), - "consider borrowing here", - ["&".to_string(), "&mut ".to_string()].into_iter(), - Applicability::MaybeIncorrect, - ); - } else { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "consider{} borrowing here", - if mut_result { " mutably" } else { "" } - ), - format!("&{}", if mut_result { "mut " } else { "" }), - Applicability::MaybeIncorrect, - ); - } - } - return true; } + return true; } - return false; - }; + } + return false; + }; if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code { try_borrowing(cause.derived.parent_trait_pred, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ItemObligation(_) = code + | ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::ExprItemObligation(..) + | ObligationCauseCode::ExprBindingObligation(..) = code { try_borrowing(poly_trait_pred, &never_suggest_borrow) } else { @@ -1017,7 +1067,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, object_ty: Ty<'tcx>, ) { - let ty::Dynamic(predicates, _) = object_ty.kind() else { return; }; + let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { @@ -1110,8 +1160,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // and if not maybe suggest doing something else? If we kept the expression around we // could also check if it is an fn call (very likely) and suggest changing *that*, if // it is from the local crate. - err.span_suggestion_verbose( - expr.span.shrink_to_hi().with_hi(span.hi()), + err.span_suggestion( + span, "remove the `.await`", "", Applicability::MachineApplicable, @@ -1315,7 +1365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let trait_pred = self.resolve_vars_if_possible(trait_pred); let ty = trait_pred.skip_binder().self_ty(); let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, ty::Dyn) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() @@ -1375,7 +1425,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut spans_and_needs_box = vec![]; match liberated_sig.output().kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, _) => { let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); let param_env = ty::ParamEnv::empty(); @@ -1541,32 +1591,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { expected: ty::PolyTraitRef<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( - tcx: TyCtxt<'tcx>, + infcx: &InferCtxt<'_, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { let inputs = trait_ref.skip_binder().substs.type_at(1); let sig = match inputs.kind() { ty::Tuple(inputs) - if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() => + if infcx.tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() => { - tcx.mk_fn_sig( + infcx.tcx.mk_fn_sig( inputs.iter(), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), + infcx.next_ty_var(TypeVariableOrigin { + span: DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }), false, hir::Unsafety::Normal, abi::Abi::Rust, ) } - _ => tcx.mk_fn_sig( + _ => infcx.tcx.mk_fn_sig( std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), + infcx.next_ty_var(TypeVariableOrigin { + span: DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }), false, hir::Unsafety::Normal, abi::Abi::Rust, ), }; - tcx.mk_fn_ptr(trait_ref.rebind(sig)) + infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig)) } let argument_kind = match expected.skip_binder().self_ty().kind() { @@ -1586,11 +1642,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let found_span = found_span.unwrap_or(span); err.span_label(found_span, "found signature defined here"); - let expected = build_fn_sig_ty(self.tcx, expected); - let found = build_fn_sig_ty(self.tcx, found); + let expected = build_fn_sig_ty(self, expected); + let found = build_fn_sig_ty(self, found); - let (expected_str, found_str) = - self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found)); + let (expected_str, found_str) = self.cmp(expected, found); let signature_kind = format!("{argument_kind} signature"); err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); @@ -2201,7 +2256,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::QuestionMark | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse - | ObligationCauseCode::BinOp { .. } => {} + | ObligationCauseCode::BinOp { .. } + | ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } @@ -2223,11 +2279,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { region, object_ty, )); } - ObligationCauseCode::ItemObligation(_item_def_id) => { + ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::ExprItemObligation(..) => { // We hold the `DefId` of the item introducing the obligation, but displaying it // doesn't add user usable information. It always point at an associated item. } - ObligationCauseCode::BindingObligation(item_def_id, span) => { + ObligationCauseCode::BindingObligation(item_def_id, span) + | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { let item_name = tcx.def_path_str(item_def_id); let mut multispan = MultiSpan::from(span); if let Some(ident) = tcx.opt_item_ident(item_def_id) { @@ -2537,9 +2595,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { parent_trait_pred.remap_constness_diag(param_env); let parent_def_id = parent_trait_pred.def_id(); let msg = format!( - "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_pred.print_modifiers_and_trait_path(), - parent_trait_pred.skip_binder().self_ty() + "required for `{}` to implement `{}`", + parent_trait_pred.skip_binder().self_ty(), + parent_trait_pred.print_modifiers_and_trait_path() ); let mut is_auto_trait = false; match self.tcx.hir().get_if_local(data.impl_def_id) { @@ -2608,9 +2666,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { pluralize!(count) )); err.note(&format!( - "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_pred.print_modifiers_and_trait_path(), - parent_trait_pred.skip_binder().self_ty() + "required for `{}` to implement `{}`", + parent_trait_pred.skip_binder().self_ty(), + parent_trait_pred.print_modifiers_and_trait_path() )); } // #74711: avoid a stack overflow diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 556ef466c..a81fef60a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -135,7 +135,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// `SomeTrait` or a where-clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. - #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))] + #[instrument(level = "debug", skip(self, infcx, param_env, cause))] fn normalize_projection_type( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -427,16 +427,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.param_env, Binder::dummy(subtype), ) { - None => { + Err((a, b)) => { // None means that both are unresolved. - pending_obligation.stalled_on = vec![ - TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(), - TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(), - ]; + pending_obligation.stalled_on = + vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), - Some(Err(err)) => { + Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Ok(Err(err)) => { let expected_found = ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( @@ -453,16 +451,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.param_env, Binder::dummy(coerce), ) { - None => { + Err((a, b)) => { // None means that both are unresolved. - pending_obligation.stalled_on = vec![ - TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(), - TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(), - ]; + pending_obligation.stalled_on = + vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), - Some(Err(err)) => { + Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Ok(Err(err)) => { let expected_found = ExpectedFound::new(false, coerce.a, coerce.b); ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( expected_found, @@ -509,11 +505,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.kind(), c2.kind()) { - if infcx.try_unify_abstract_consts( - a.shrink(), - b.shrink(), - obligation.param_env, - ) { + if infcx.try_unify_abstract_consts(a, b, obligation.param_env) { return ProcessResult::Changed(vec![]); } } @@ -597,6 +589,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } + #[inline(never)] fn process_backedge<'c, I>( &mut self, cycle: I, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index dd2769c71..e1bd48ba8 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -63,8 +63,7 @@ pub fn can_type_implement_copy<'tcx>( } else { ObligationCause::dummy_with_span(span) }; - let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { + match traits::fully_normalize(&infcx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push((field, ty)); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9c6bb0731..40596078f 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -13,6 +13,7 @@ mod fulfill; pub mod misc; mod object_safety; mod on_unimplemented; +pub mod outlives_bounds; mod project; pub mod query; pub(crate) mod relationships; @@ -22,6 +23,7 @@ mod structural_match; mod util; pub mod wf; +use crate::errors::DumpVTableEntries; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::InferCtxtExt as _; @@ -30,10 +32,14 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; +use rustc_middle::ty::{ + self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, + VtblEntry, +}; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -113,11 +119,21 @@ pub enum TraitQueryMode { /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, + cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_bounds: ty::InstantiatedPredicates<'tcx>, ) -> impl Iterator> { - util::predicates_for_generics(cause, 0, param_env, generic_bounds) + let generic_bounds = generic_bounds; + debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); + + std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map( + move |(idx, (predicate, span))| Obligation { + cause: cause(idx, span), + recursion_depth: 0, + param_env: param_env, + predicate, + }, + ) } /// Determines whether the type `ty` is known to meet `bound` and @@ -161,22 +177,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let mut fulfill_cx = >::new(infcx.tcx); - // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any // anyhow). let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID); - fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); + // The handling of regions in this area of the code is terrible, + // see issue #29149. We should be able to improve on this with + // NLL. + let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id); // Note: we only assume something is `Copy` if we can // *definitively* show that it implements `Copy`. Otherwise, // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx).as_slice() { + match &errors[..] { [] => { debug!( "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", @@ -222,15 +236,13 @@ fn do_normalize_predicates<'tcx>( // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let fulfill_cx = FulfillmentContext::new(); - let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { - Ok(predicates) => predicates, - Err(errors) => { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); - } - }; + let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { + Ok(predicates) => predicates, + Err(errors) => { + let reported = infcx.report_fulfillment_errors(&errors, None, false); + return Err(reported); + } + }; debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); @@ -381,9 +393,9 @@ pub fn normalize_param_env_or_error<'tcx>( ) } +/// Normalize a type and process all resulting obligations, returning any errors pub fn fully_normalize<'a, 'tcx, T>( infcx: &InferCtxt<'a, 'tcx>, - mut fulfill_cx: FulfillmentContext<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: T, @@ -399,8 +411,10 @@ where "fully_normalize: normalized_value={:?} obligations={:?}", normalized_value, obligations ); + + let mut fulfill_cx = FulfillmentContext::new(); for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); + fulfill_cx.register_predicate_obligation(infcx, obligation); } debug!("fully_normalize: select_all_or_error start"); @@ -414,6 +428,43 @@ where Ok(resolved_value) } +/// Process an obligation (and any nested obligations that come from it) to +/// completion, returning any errors +pub fn fully_solve_obligation<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + obligation: PredicateObligation<'tcx>, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_predicate_obligation(infcx, obligation); + engine.select_all_or_error(infcx) +} + +/// Process a set of obligations (and any nested obligations that come from them) +/// to completion +pub fn fully_solve_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + obligations: impl IntoIterator>, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_predicate_obligations(infcx, obligations); + engine.select_all_or_error(infcx) +} + +/// Process a bound (and any nested obligations that come from it) to completion. +/// This is a convenience function for traits that have no generic arguments, such +/// as auto traits, and builtin traits like Copy or Sized. +pub fn fully_solve_bound<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + bound: DefId, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_bound(infcx, param_env, ty, bound, cause); + engine.select_all_or_error(infcx) +} + /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. @@ -424,24 +475,14 @@ pub fn impossible_predicates<'tcx>( debug!("impossible_predicates(predicates={:?})", predicates); let result = tcx.infer_ctxt().enter(|infcx| { - // HACK: Set tainted by errors to gracefully exit in case of overflow. - infcx.set_tainted_by_errors(); - let param_env = ty::ParamEnv::reveal_all(); - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = FulfillmentContext::new(); - let cause = ObligationCause::dummy(); - let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), predicates); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } + let ocx = ObligationCtxt::new(&infcx); + let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates); for predicate in predicates { - let obligation = Obligation::new(cause.clone(), param_env, predicate); - fulfill_cx.register_predicate_obligation(&infcx, obligation); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + ocx.register_obligation(obligation); } - - let errors = fulfill_cx.select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); // Clean up after ourselves let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); @@ -474,6 +515,84 @@ fn subst_and_check_impossible_predicates<'tcx>( result } +/// Checks whether a trait's method is impossible to call on a given impl. +/// +/// This only considers predicates that reference the impl's generics, and not +/// those that reference the method's generics. +fn is_impossible_method<'tcx>( + tcx: TyCtxt<'tcx>, + (impl_def_id, trait_item_def_id): (DefId, DefId), +) -> bool { + struct ReferencesOnlyParentGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + trait_item_def_id: DefId, + } + impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + // If this is a parameter from the trait item's own generics, then bail + if let ty::Param(param) = t.kind() + && let param_def_id = self.generics.type_param(param, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + t.super_visit_with(self) + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::ReEarlyBound(param) = r.kind() + && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + r.super_visit_with(self) + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + if let ty::ConstKind::Param(param) = ct.kind() + && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + ct.super_visit_with(self) + } + } + + let generics = tcx.generics_of(trait_item_def_id); + let predicates = tcx.predicates_of(trait_item_def_id); + let impl_trait_ref = + tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait"); + let param_env = tcx.param_env(impl_def_id); + + let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; + let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { + if pred.visit_with(&mut visitor).is_continue() { + Some(Obligation::new( + ObligationCause::dummy_with_span(*span), + param_env, + ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), + )) + } else { + None + } + }); + + tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| { + for obligation in predicates_for_trait { + // Ignore overflow error, to be conservative. + if let Ok(result) = infcx.evaluate_obligation(&obligation) + && !result.may_apply() + { + return true; + } + } + + false + }) +} + #[derive(Clone, Debug)] enum VtblSegment<'tcx> { MetadataDSA, @@ -645,8 +764,11 @@ fn dump_vtable_entries<'tcx>( trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); - tcx.sess.struct_span_err(sp, &msg).emit(); + tcx.sess.emit_err(DumpVTableEntries { + span: sp, + trait_ref, + entries: format!("{:#?}", entries), + }); } fn own_existential_vtable_entries<'tcx>( @@ -849,11 +971,12 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, - codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, + codegen_select_candidate: codegen::codegen_select_candidate, own_existential_vtable_entries, vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, + is_impossible_method, try_unify_abstract_consts: |tcx, param_env_and| { let (param_env, (a, b)) = param_env_and.into_parts(); const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 612f51309..f2779ce2d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -13,6 +13,7 @@ use super::elaborate_predicates; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; +use hir::def::DefKind; use rustc_errors::{FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -431,6 +432,9 @@ fn virtual_call_violation_for_method<'tcx>( if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { return Some(MethodViolationCode::ReferencesSelfOutput); } + if contains_illegal_impl_trait_in_trait(tcx, sig.output()) { + return Some(MethodViolationCode::ReferencesImplTraitInTrait); + } // We can't monomorphize things like `fn foo(...)`. let own_counts = tcx.generics_of(method.def_id).own_counts(); @@ -596,7 +600,7 @@ fn object_ty_for_trait<'tcx>( let existential_predicates = tcx .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); @@ -793,6 +797,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( ControlFlow::CONTINUE } } + ty::Projection(ref data) + if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => + { + // We'll deny these later in their own pass + ControlFlow::CONTINUE + } ty::Projection(ref data) => { // This is a projected type `::X`. @@ -861,6 +871,22 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( .is_break() } +pub fn contains_illegal_impl_trait_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, +) -> bool { + // FIXME(RPITIT): Perhaps we should use a visitor here? + ty.skip_binder().walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Projection(proj) = ty.kind() + { + tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder + } else { + false + } + }) +} + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { object_safety_violations, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 9227bbf01..4a4f34b76 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -8,6 +8,10 @@ use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use crate::errors::{ + EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, +}; + #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString(Symbol); @@ -18,7 +22,7 @@ pub struct OnUnimplementedDirective { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, pub append_const_msg: Option>, } @@ -27,7 +31,7 @@ pub struct OnUnimplementedNote { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, /// Append a message for `~const Trait` errors. `None` means not requested and /// should fallback to a generic message, `Some(None)` suggests using the default /// appended message, `Some(Some(s))` suggests use the `s` message instead of the @@ -35,21 +39,6 @@ pub struct OnUnimplementedNote { pub append_const_msg: Option>, } -fn parse_error( - tcx: TyCtxt<'_>, - span: Span, - message: &str, - label: &str, - note: Option<&str>, -) -> ErrorGuaranteed { - let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); - diag.span_label(span, label); - if let Some(note) = note { - diag.note(note); - } - diag.emit() -} - impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -70,25 +59,9 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| { - parse_error( - tcx, - span, - "empty `on`-clause in `#[rustc_on_unimplemented]`", - "empty on-clause here", - None, - ) - })? + .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))? .meta_item() - .ok_or_else(|| { - parse_error( - tcx, - span, - "invalid `on`-clause in `#[rustc_on_unimplemented]`", - "invalid on-clause here", - None, - ) - })?; + .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { errored = Some(guar); @@ -101,7 +74,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut subcommands = vec![]; let mut append_const_msg = None; @@ -121,9 +94,9 @@ impl<'tcx> OnUnimplementedDirective { note = parse_value(note_)?; continue; } - } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() { - if let Some(enclosing_scope_) = item.value_str() { - enclosing_scope = parse_value(enclosing_scope_)?; + } else if item.has_name(sym::parent_label) && parent_label.is_none() { + if let Some(parent_label_) = item.value_str() { + parent_label = parse_value(parent_label_)?; continue; } } else if item.has_name(sym::on) @@ -150,13 +123,7 @@ impl<'tcx> OnUnimplementedDirective { } // nothing found - parse_error( - tcx, - item.span(), - "this attribute must have a valid value", - "expected value here", - Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), - ); + tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() }); } if let Some(reported) = errored { @@ -168,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective { message, label, note, - enclosing_scope, + parent_label, append_const_msg, }) } @@ -193,7 +160,7 @@ impl<'tcx> OnUnimplementedDirective { attr.span, )?), note: None, - enclosing_scope: None, + parent_label: None, append_const_msg: None, })) } else { @@ -214,7 +181,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut append_const_msg = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); @@ -250,8 +217,8 @@ impl<'tcx> OnUnimplementedDirective { note = Some(note_.clone()); } - if let Some(ref enclosing_scope_) = command.enclosing_scope { - enclosing_scope = Some(enclosing_scope_.clone()); + if let Some(ref parent_label_) = command.parent_label { + parent_label = Some(parent_label_.clone()); } append_const_msg = command.append_const_msg; @@ -261,7 +228,7 @@ impl<'tcx> OnUnimplementedDirective { label: label.map(|l| l.format(tcx, trait_ref, &options_map)), message: message.map(|m| m.format(tcx, trait_ref, &options_map)), note: note.map(|n| n.format(tcx, trait_ref, &options_map)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), + parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), append_const_msg, } } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs new file mode 100644 index 000000000..3008dfcad --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -0,0 +1,115 @@ +use crate::infer::InferCtxt; +use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; +use crate::traits::query::NoSolution; +use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_hir::HirId; +use rustc_middle::ty::{self, ParamEnv, Ty}; + +pub use rustc_middle::traits::query::OutlivesBound; + +type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; +pub trait InferCtxtExt<'a, 'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + ) -> Vec>; + + fn implied_bounds_tys( + &'a self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + tys: FxHashSet>, + ) -> Bounds<'a, 'tcx>; +} + +impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// ``` + /// fn foo<'a,T>(x: &'a T) {} + /// ``` + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `ty`, the type that we are supposed to assume is WF. + #[instrument(level = "debug", skip(self, param_env, body_id), ret)] + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + ) -> Vec> { + let span = self.tcx.hir().span(body_id); + let result = param_env + .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) + .fully_perform(self); + let result = match result { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations", + ); + return vec![]; + } + }; + + let TypeOpOutput { output, constraints, .. } = result; + + if let Some(constraints) = constraints { + debug!(?constraints); + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = >::new(self.tcx); + let cause = ObligationCause::misc(span, body_id); + for &constraint in &constraints.outlives { + let obligation = self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + ); + fulfill_cx.register_predicate_obligation(self, obligation); + } + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } + let errors = fulfill_cx.select_all_or_error(self); + if !errors.is_empty() { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + }; + + output + } + + fn implied_bounds_tys( + &'a self, + param_env: ParamEnv<'tcx>, + body_id: HirId, + tys: FxHashSet>, + ) -> Bounds<'a, 'tcx> { + tys.into_iter() + .map(move |ty| { + let ty = self.resolve_vars_if_possible(ty); + self.implied_outlives_bounds(param_env, body_id, ty) + }) + .flatten() + } +} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c4e80e1ba..a25fb8543 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -32,6 +32,7 @@ use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; +use rustc_middle::ty::DefIdTree; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -70,6 +71,8 @@ enum ProjectionCandidate<'tcx> { /// From an "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), + + ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>), } enum ProjectionCandidateSet<'tcx> { @@ -231,7 +234,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_type] for an explanation of the return value. -#[tracing::instrument(level = "debug", skip(selcx))] +#[instrument(level = "debug", skip(selcx))] fn project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionObligation<'tcx>, @@ -552,8 +555,23 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { ) .ok() .flatten() - .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self))) + .unwrap_or_else(|| ty.super_fold_with(self).into()) }; + // For cases like #95134 we would like to catch overflows early + // otherwise they slip away away and cause ICE. + let recursion_limit = self.tcx().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) + // HACK: Don't overflow when running cargo doc see #100991 + && !self.tcx().sess.opts.actually_rustdoc + { + let obligation = Obligation::with_depth( + self.cause.clone(), + recursion_limit.0, + self.param_env, + ty, + ); + self.selcx.infcx().report_overflow_error(&obligation, true); + } debug!( ?self.depth, ?ty, @@ -620,13 +638,27 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { - if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement { + let tcx = self.selcx.tcx(); + if tcx.lazy_normalization() { constant } else { let constant = constant.super_fold_with(self); - debug!(?constant); - debug!("self.param_env: {:?}", self.param_env); - constant.eval(self.selcx.tcx(), self.param_env) + debug!(?constant, ?self.param_env); + with_replaced_escaping_bound_vars( + self.selcx.infcx(), + &mut self.universes, + constant, + |constant| constant.eval(tcx, self.param_env), + ) + } + } + + #[inline] + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.super_fold_with(self) + } else { + p } } } @@ -647,6 +679,41 @@ pub struct BoundVarReplacer<'me, 'tcx> { universe_indices: &'me mut Vec>, } +/// Executes `f` on `value` after replacing all escaping bound variables with placeholders +/// and then replaces these placeholders with the original bound variables in the result. +/// +/// In most places, bound variables should be replaced right when entering a binder, making +/// this function unnecessary. However, normalization currently does not do that, so we have +/// to do this lazily. +/// +/// You should not add any additional uses of this function, at least not without first +/// discussing it with t-types. +/// +/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during +/// normalization as well, at which point this function will be unnecessary and can be removed. +pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>( + infcx: &'a InferCtxt<'a, 'tcx>, + universe_indices: &'a mut Vec>, + value: T, + f: impl FnOnce(T) -> R, +) -> R { + if value.has_escaping_bound_vars() { + let (value, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); + let result = f(value); + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + result, + ) + } else { + f(value) + } +} + impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. @@ -1182,7 +1249,7 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized -#[tracing::instrument(level = "info", skip(selcx))] +#[instrument(level = "info", skip(selcx))] fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, @@ -1201,6 +1268,8 @@ fn project<'cx, 'tcx>( let mut candidates = ProjectionCandidateSet::None; + assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates); + // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. @@ -1239,6 +1308,48 @@ fn project<'cx, 'tcx>( } } +/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the +/// corresponding trait ref. If this yields an `impl`, then we're able to project +/// to a concrete type, since we have an `impl`'s method to provide the RPITIT. +fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, +) { + let tcx = selcx.tcx(); + if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder { + let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id); + let trait_def_id = tcx.parent(trait_fn_def_id); + let trait_substs = + obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id)); + // FIXME(named-returns): Binders + let trait_predicate = + ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs }) + .to_poly_trait_predicate(); + + let _ = + selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) { + Ok(Some(super::ImplSource::UserDefined(data))) => { + candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); + Ok(()) + } + Ok(None) => { + candidate_set.mark_ambiguous(); + return Err(()); + } + Ok(Some(_)) => { + // Don't know enough about the impl to provide a useful signature + return Err(()); + } + Err(e) => { + debug!(error = ?e, "selection error"); + candidate_set.mark_error(e); + return Err(()); + } + }); + } +} + /// The first thing we have to do is scan through the parameter /// environment to see whether there are any projection predicates /// there that can answer this question. @@ -1344,7 +1455,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( ); } -#[tracing::instrument( +#[instrument( level = "debug", skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates) )] @@ -1395,12 +1506,17 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( } } -#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))] +#[instrument(level = "debug", skip(selcx, obligation, candidate_set))] fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { + // Can't assemble candidate from impl for RPITIT + if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder { + return; + } + // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); @@ -1635,7 +1751,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) - | super::ImplSource::ConstDestruct(_) => { + | super::ImplSource::ConstDestruct(_) + | super::ImplSource::Tuple => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1676,6 +1793,9 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } + ProjectionCandidate::ImplTraitInTrait(data) => { + confirm_impl_trait_in_trait_candidate(selcx, obligation, data) + } }; // When checking for cycle during evaluation, we compare predicates with @@ -1710,7 +1830,8 @@ fn confirm_select_candidate<'cx, 'tcx>( | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) | super::ImplSource::TraitAlias(..) - | super::ImplSource::ConstDestruct(_) => { + | super::ImplSource::ConstDestruct(_) + | super::ImplSource::Tuple => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, @@ -2038,10 +2159,74 @@ fn confirm_impl_candidate<'cx, 'tcx>( } } +fn confirm_impl_trait_in_trait_candidate<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + let mut obligations = data.nested; + + let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id); + let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else { + return Progress { term: tcx.ty_error().into(), obligations }; + }; + if !leaf_def.item.defaultness(tcx).has_value() { + return Progress { term: tcx.ty_error().into(), obligations }; + } + + let impl_fn_def_id = leaf_def.item.def_id; + let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs); + + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + super::ItemObligation(impl_fn_def_id), + ); + let predicates = normalize_with_depth_to( + selcx, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs), + &mut obligations, + ); + obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map( + |(pred, span)| { + Obligation::with_depth( + ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + if span.is_dummy() { + super::ItemObligation(impl_fn_def_id) + } else { + super::BindingObligation(impl_fn_def_id, span) + }, + ), + obligation.recursion_depth + 1, + obligation.param_env, + pred, + ) + }, + )); + + let ty = super::normalize_to( + selcx, + obligation.param_env, + cause.clone(), + tcx.bound_trait_impl_trait_tys(impl_fn_def_id) + .map_bound(|tys| { + tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id]) + }) + .subst(tcx, impl_fn_substs), + &mut obligations, + ); + + Progress { term: ty.into(), obligations } +} + // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. -// Note: `feature(generic_associated_types)` is required to write such -// predicates, even for non-generic associated types. fn assoc_ty_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 449d7a7b4..40acabf62 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,7 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; -use crate::traits::project::needs_normalization; +use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -48,10 +48,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { T: TypeFoldable<'tcx>, { debug!( - "normalize::<{}>(value={:?}, param_env={:?})", + "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})", std::any::type_name::(), value, self.param_env, + self.cause, ); if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); @@ -266,7 +267,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(result.normalized_ty) + + let res = result.normalized_ty; + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } ty::Projection(data) => { @@ -275,11 +284,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let tcx = self.infcx.tcx; let infcx = self.infcx; let (data, mapped_regions, mapped_types, mapped_consts) = - crate::traits::project::BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - data, - ); + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); @@ -305,18 +310,26 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders( + let res = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, result.normalized_ty, - )) + ); + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } _ => ty.try_super_fold_with(self), })()?; + self.cache.insert(ty, res); Ok(res) } @@ -326,7 +339,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { constant: ty::Const<'tcx>, ) -> Result, Self::Error> { let constant = constant.try_super_fold_with(self)?; - Ok(constant.eval(self.infcx.tcx, self.param_env)) + debug!(?constant, ?self.param_env); + Ok(crate::traits::project::with_replaced_escaping_bound_vars( + self.infcx, + &mut self.universes, + constant, + |constant| constant.eval(self.infcx.tcx, self.param_env), + )) } fn try_fold_mir_const( @@ -348,7 +367,21 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { _ => mir::ConstantKind::Ty(const_folded), } } - mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?, + mir::ConstantKind::Val(_, _) | mir::ConstantKind::Unevaluated(..) => { + constant.try_super_fold_with(self)? + } }) } + + #[inline] + fn try_fold_predicate( + &mut self, + p: ty::Predicate<'tcx>, + ) -> Result, Self::Error> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.try_super_fold_with(self) + } else { + Ok(p) + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c99564936..18988861a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,11 +1,9 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::engine::TraitEngineExt as _; +use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; -use crate::traits::TraitEngine; use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::fmt; @@ -25,7 +23,7 @@ impl CustomTypeOp { } } -impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp +impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp where F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible>, G: Fn() -> String, @@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'_, 'tcx>, op: impl FnOnce() -> Fallible>, ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { - let mut fulfill_cx = >::new(infcx.tcx); - // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the // end of each custom type op, we scrape out the region @@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - fulfill_cx.register_predicate_obligations(infcx, obligations); - let errors = fulfill_cx.select_all_or_error(infcx); + let errors = traits::fully_solve_obligations(infcx, obligations); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, @@ -94,8 +89,8 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx.tcx, region_obligations .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())) + .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 578e1d00c..8a7916570 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -26,7 +26,7 @@ pub use rustc_middle::traits::query::type_op::*; /// extract out the resulting region constraints (or an error if it /// cannot be completed). pub trait TypeOp<'tcx>: Sized + fmt::Debug { - type Output; + type Output: fmt::Debug; type ErrorInfo; /// Processes the operation and all resulting obligations, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a60ce0f34..a80527f63 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -8,7 +8,7 @@ use hir::LangItem; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -28,7 +28,7 @@ use super::SelectionCandidate::{self, *}; use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(super) fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -48,7 +48,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) { - debug!(candidate = ?c, "CACHE HIT"); + debug!("CACHE HIT"); return c; } @@ -61,7 +61,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let (candidate, dep_node) = self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - debug!(?candidate, "CACHE MISS"); + debug!("CACHE MISS"); self.insert_candidate_cache( stack.obligation.param_env, cache_fresh_trait_pred, @@ -75,7 +75,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let Some(conflict) = self.is_knowable(stack) { + if let Err(conflict) = self.is_knowable(stack) { debug!("coherence stage: not knowable"); if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); @@ -309,6 +309,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // User-defined transmutability impls are permitted. self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_for_transmutability(obligation, &mut candidates); + } else if lang_items.tuple_trait() == Some(def_id) { + self.assemble_candidate_for_tuple(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -337,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(candidates) } - #[tracing::instrument(level = "debug", skip(self, candidates))] + #[instrument(level = "debug", skip(self, candidates))] fn assemble_candidates_from_projected_tys( &mut self, obligation: &TraitObligation<'tcx>, @@ -367,7 +369,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// supplied to find out whether it is listed among them. /// /// Never affects the inference environment. - #[tracing::instrument(level = "debug", skip(self, stack, candidates))] + #[instrument(level = "debug", skip(self, stack, candidates))] fn assemble_candidates_from_caller_bounds<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -706,8 +708,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn need_migrate_deref_output_trait_object( &mut self, ty: Ty<'tcx>, - cause: &traits::ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, + cause: &ObligationCause<'tcx>, ) -> Option<(Ty<'tcx>, DefId)> { let tcx = self.tcx(); if tcx.features().trait_upcasting { @@ -729,24 +731,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } - let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); - let normalized_ty = fulfillcx.normalize_projection_type( - &self.infcx, + let ty = traits::normalize_projection_type( + self, param_env, ty::ProjectionTy { item_def_id: tcx.lang_items().deref_target()?, substs: trait_ref.substs, }, cause.clone(), - ); - - let ty::Dynamic(data, ..) = normalized_ty.kind() else { - return None; - }; - - let def_id = data.principal_def_id()?; - - return Some((normalized_ty, def_id)); + 0, + // We're *intentionally* throwing these away, + // since we don't actually use them. + &mut vec![], + ) + .ty() + .unwrap(); + + if let ty::Dynamic(data, ..) = ty.kind() { + Some((ty, data.principal_def_id()?)) + } else { + None + } } /// Searches for unsizing that might apply to `obligation`. @@ -809,8 +814,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some((deref_output_ty, deref_output_trait_did)) = self .need_migrate_deref_output_trait_object( source, - &obligation.cause, obligation.param_env, + &obligation.cause, ) { if deref_output_trait_did == target_trait_did { @@ -877,7 +882,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } - #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + #[instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_transmutability( &mut self, obligation: &TraitObligation<'tcx>, @@ -895,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(TransmutabilityCandidate); } - #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + #[instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, @@ -914,7 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Assembles the trait which are built-in to the language itself: /// `Copy`, `Clone` and `Sized`. - #[tracing::instrument(level = "debug", skip(self, candidates))] + #[instrument(level = "debug", skip(self, candidates))] fn assemble_builtin_bound_candidates( &mut self, conditions: BuiltinImplConditions<'tcx>, @@ -1006,4 +1011,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidate_for_tuple( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder()); + match self_ty.kind() { + ty::Tuple(_) => { + candidates.vec.push(TupleCandidate); + } + ty::Infer(ty::TyVar(_)) => { + candidates.ambiguous = true; + } + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Projection(_) + | ty::Opaque(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Error(_) + | ty::Infer(_) + | ty::Placeholder(_) => {} + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2a1099fc8..d1deef784 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -126,6 +126,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = self.confirm_const_destruct_candidate(obligation, def_id)?; ImplSource::ConstDestruct(data) } + + TupleCandidate => ImplSource::Tuple, }; if !obligation.predicate.is_const_if_const() { @@ -279,29 +281,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = obligation.predicate; let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); - let bool_at = |i| { - predicate - .skip_binder() - .trait_ref - .substs - .const_at(i) - .try_eval_bool(self.tcx(), obligation.param_env) - .unwrap_or(true) - }; + let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i); let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { - src: p.trait_ref.substs.type_at(1), dst: p.trait_ref.substs.type_at(0), + src: p.trait_ref.substs.type_at(1), }); let scope = type_at(2).skip_binder(); - let assume = rustc_transmute::Assume { - alignment: bool_at(3), - lifetimes: bool_at(4), - validity: bool_at(5), - visibility: bool_at(6), - }; + let assume = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)); let cause = obligation.cause.clone(); @@ -794,7 +784,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let upcast_trait_ref; match (source.kind(), target.kind()) { // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b)) + if repr_a == repr_b => + { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let principal_a = data_a.principal().unwrap(); @@ -820,7 +812,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -898,7 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = vec![]; match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, ty::Dyn), &ty::Dynamic(ref data_b, r_b, ty::Dyn)) => { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let iter = data_a @@ -917,7 +909,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, ty::Dyn); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -944,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { + (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); @@ -1047,9 +1039,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(Unimplemented); } - // Extract `TailField` and `TailField` from `Struct` and `Struct`. - let source_tail = tail_field_ty.subst(tcx, substs_a); - let target_tail = tail_field_ty.subst(tcx, substs_b); + // Extract `TailField` and `TailField` from `Struct` and `Struct`, + // normalizing in the process, since `type_of` returns something directly from + // astconv (which means it's un-normalized). + let source_tail = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + tail_field_ty.subst(tcx, substs_a), + &mut nested, + ); + let target_tail = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + tail_field_ty.subst(tcx, substs_b), + &mut nested, + ); // Check that the source struct with the target's // unsizing parameters is equal to the target. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c01ac1979..75bd2c89f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -295,7 +295,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Attempts to satisfy the obligation. If successful, this will affect the surrounding /// type environment by performing unification. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn select( &mut self, obligation: &TraitObligation<'tcx>, @@ -325,10 +325,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(SelectionError::Overflow(OverflowError::Canonical)) } Err(e) => Err(e), - Ok(candidate) => { - debug!(?candidate, "confirmed"); - Ok(Some(candidate)) - } + Ok(candidate) => Ok(Some(candidate)), } } @@ -435,6 +432,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { level = "debug", skip(self, previous_stack), fields(previous_stack = ?previous_stack.head()) + ret, )] fn evaluate_predicate_recursively<'o>( &mut self, @@ -450,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - let result = ensure_sufficient_stack(|| { + ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Trait(t) => { @@ -464,15 +462,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { + Ok(Ok(InferOk { mut obligations, .. })) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively( previous_stack, obligations.into_iter(), ) } - Some(Err(_)) => Ok(EvaluatedToErr), - None => Ok(EvaluatedToAmbig), + Ok(Err(_)) => Ok(EvaluatedToErr), + Err(..) => Ok(EvaluatedToAmbig), } } @@ -480,15 +478,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { + Ok(Ok(InferOk { mut obligations, .. })) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively( previous_stack, obligations.into_iter(), ) } - Some(Err(_)) => Ok(EvaluatedToErr), - None => Ok(EvaluatedToAmbig), + Ok(Err(_)) => Ok(EvaluatedToErr), + Err(..) => Ok(EvaluatedToAmbig), } } @@ -701,11 +699,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = (c1.kind(), c2.kind()) { - if self.infcx.try_unify_abstract_consts( - a.shrink(), - b.shrink(), - obligation.param_env, - ) { + if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) { return Ok(EvaluatedToOk); } } @@ -760,14 +754,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("TypeWellFormedFromEnv is only used for chalk") } } - }); - - debug!("finished: {:?} from {:?}", result, obligation); - - result + }) } - #[instrument(skip(self, previous_stack), level = "debug")] + #[instrument(skip(self, previous_stack), level = "debug", ret)] fn evaluate_trait_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, @@ -798,12 +788,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a trait predicate is in the (local or global) evaluation cache, // then we know it holds without cycles. if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { - debug!(?result, "CACHE HIT"); + debug!("CACHE HIT"); return Ok(result); } if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { - debug!(?result, "PROVISIONAL CACHE HIT"); + debug!("PROVISIONAL CACHE HIT"); stack.update_reached_depth(result.reached_depth); return Ok(result.result); } @@ -826,11 +816,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { - debug!(?result, "CACHE MISS"); + debug!("CACHE MISS"); self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); stack.cache().on_completion(stack.dfn); } else { - debug!(?result, "PROVISIONAL"); + debug!("PROVISIONAL"); debug!( "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", @@ -1023,7 +1013,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument( level = "debug", skip(self, stack), - fields(depth = stack.obligation.recursion_depth) + fields(depth = stack.obligation.recursion_depth), + ret )] fn evaluate_candidate<'o>( &mut self, @@ -1056,7 +1047,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result = result.max(EvaluatedToOkModuloRegions); } - debug!(?result); Ok(result) } @@ -1265,11 +1255,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { + fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { debug!("is_knowable(intercrate={:?})", self.intercrate); if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative { - return None; + return Ok(()); } let obligation = &stack.obligation; @@ -1405,7 +1395,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// a projection, look at the bounds of `T::Bar`, see if we can find a /// `Baz` bound. We return indexes into the list returned by /// `tcx.item_bounds` for any applicable bounds. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, @@ -1435,7 +1425,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // unnecessary ambiguity. let mut distinct_normalized_bounds = FxHashSet::default(); - let matching_bounds = bounds + bounds .iter() .enumerate() .filter_map(|(idx, bound)| { @@ -1462,10 +1452,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } None }) - .collect(); - - debug!(?matching_bounds); - matching_bounds + .collect() } /// Equates the trait in `obligation` with trait bound. If the two traits @@ -1618,7 +1605,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else. + // `DiscriminantKindCandidate`, `ConstDestructCandidate`, and `TupleCandidate` + // to anything else. // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. @@ -1638,7 +1626,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDestructCandidate(_), + | ConstDestructCandidate(_) + | TupleCandidate, _, ) => true, ( @@ -1646,7 +1635,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDestructCandidate(_), + | ConstDestructCandidate(_) + | TupleCandidate, ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { @@ -1871,6 +1861,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) @@ -1937,8 +1928,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Dynamic(..) | ty::Str | ty::Slice(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Generator(_, _, hir::Movability::Static) | ty::Foreign(..) | ty::Ref(_, _, hir::Mutability::Mut) => None, @@ -1947,6 +1937,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Where(obligation.predicate.rebind(tys.iter().collect())) } + ty::Generator(_, substs, hir::Movability::Movable) => { + if self.tcx().features().generator_clone { + let resolved_upvars = + self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let resolved_witness = + self.infcx.shallow_resolve(substs.as_generator().witness()); + if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { + // Not yet resolved. + Ambiguous + } else { + let all = substs + .as_generator() + .upvar_tys() + .chain(iter::once(substs.as_generator().witness())) + .collect::>(); + Where(obligation.predicate.rebind(all)) + } + } else { + None + } + } + + ty::GeneratorWitness(binder) => { + let witness_tys = binder.skip_binder(); + for witness_ty in witness_tys.iter() { + let resolved = self.infcx.shallow_resolve(witness_ty); + if resolved.is_ty_var() { + return Ambiguous; + } + } + // (*) binder moved here + let all_vars = self.tcx().mk_bound_variable_kinds( + obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()), + ); + Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) + } + ty::Closure(_, substs) => { // (*) binder moved here let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); @@ -2153,7 +2180,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn match_impl( &mut self, impl_def_id: DefId, @@ -2194,17 +2221,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&cause, obligation.param_env) .define_opaque_types(false) .eq(placeholder_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; + .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?; nested_obligations.extend(obligations); if !self.intercrate && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { - debug!("match_impl: reservation impls only apply in intercrate mode"); + debug!("reservation impls only apply in intercrate mode"); return Err(()); } - debug!(?impl_substs, ?nested_obligations, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } @@ -2335,7 +2361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default /// impl. - #[tracing::instrument(level = "debug", skip(self, cause, param_env))] + #[instrument(level = "debug", skip(self, cause, param_env))] fn impl_or_trait_obligations( &mut self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 6223c5ea3..7d299e30a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -12,11 +12,10 @@ pub mod specialization_graph; use specialization_graph::GraphExt; +use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{ - self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt, -}; +use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -26,8 +25,8 @@ use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::{Span, DUMMY_SP}; +use super::util; use super::SelectionContext; -use super::{util, FulfillmentContext}; /// Information pertinent to an overlapping impl error. #[derive(Debug)] @@ -153,7 +152,6 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, tcx.infer_ctxt().enter(|infcx| { let impl1_trait_ref = match traits::fully_normalize( &infcx, - FulfillmentContext::new(), ObligationCause::dummy(), penv, impl1_trait_ref, @@ -211,11 +209,8 @@ fn fulfill_implication<'a, 'tcx>( // (which are packed up in penv) infcx.save_and_restore_in_snapshot_flag(|infcx| { - let mut fulfill_cx = >::new(infcx.tcx); - for oblig in obligations.chain(more_obligations) { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx).as_slice() { + let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations)); + match &errors[..] { [] => { debug!( "fulfill_implication: an impl for {:?} specializes {:?}", @@ -333,35 +328,13 @@ fn report_negative_positive_conflict( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let impl_span = tcx.def_span(local_impl_def_id); - - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0751, - "found both positive and negative implementation of trait `{}`{}:", - overlap.trait_desc, - overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty)) - ); - - match tcx.span_of_impl(negative_impl_def_id) { - Ok(span) => { - err.span_label(span, "negative implementation here"); - } - Err(cname) => { - err.note(&format!("negative implementation in crate `{}`", cname)); - } - } - - match tcx.span_of_impl(positive_impl_def_id) { - Ok(span) => { - err.span_label(span, "positive implementation here"); - } - Err(cname) => { - err.note(&format!("positive implementation in crate `{}`", cname)); - } - } - + let mut err = tcx.sess.create_err(NegativePositiveConflict { + impl_span: tcx.def_span(local_impl_def_id), + trait_desc: &overlap.trait_desc, + self_desc: &overlap.self_desc, + negative_impl_span: tcx.span_of_impl(negative_impl_def_id), + positive_impl_span: tcx.span_of_impl(positive_impl_def_id), + }); sg.has_errored = Some(err.emit()); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index d25006016..0f5dff01c 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -11,8 +11,6 @@ use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::{self, util::*}; -use std::iter; - /////////////////////////////////////////////////////////////////////////// // `TraitAliasExpander` iterator /////////////////////////////////////////////////////////////////////////// @@ -210,7 +208,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, param_env, ObligationCause::dummy(), predicates); let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates); + super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates); let impl_obligations = impl_obligations .chain(normalization_obligations1.into_iter()) @@ -219,27 +217,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( (subject, impl_obligations) } -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: ty::InstantiatedPredicates<'tcx>, -) -> impl Iterator> { - debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); - - iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| { - let cause = match *cause.code() { - traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new( - cause.span, - cause.body_id, - traits::BindingObligation(def_id, span), - ), - _ => cause.clone(), - }; - Obligation { cause, recursion_depth, param_env, predicate } - }) -} - pub fn predicate_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 414857f0a..5ea28fb47 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -31,9 +31,9 @@ pub fn obligations<'a, 'tcx>( if resolved_ty == ty { // No progress, bail out to prevent "livelock". return None; + } else { + resolved_ty } - - resolved_ty } _ => ty, } @@ -41,16 +41,14 @@ pub fn obligations<'a, 'tcx>( } GenericArgKind::Const(ct) => { match ct.kind() { - ty::ConstKind::Infer(infer) => { - let resolved = infcx.shallow_resolve(infer); - if resolved == infer { + ty::ConstKind::Infer(_) => { + let resolved = infcx.shallow_resolve(ct); + if resolved == ct { // No progress. return None; + } else { + resolved } - - infcx - .tcx - .mk_const(ty::ConstS { kind: ty::ConstKind::Infer(resolved), ty: ct.ty() }) } _ => ct, } @@ -103,6 +101,7 @@ pub fn trait_obligations<'a, 'tcx>( wf.normalize(infcx) } +#[instrument(skip(infcx), ret)] pub fn predicate_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -131,9 +130,9 @@ pub fn predicate_obligations<'a, 'tcx>( } ty::PredicateKind::Projection(t) => { wf.compute_projection(t.projection_ty); - wf.compute(match t.term { - ty::Term::Ty(ty) => ty.into(), - ty::Term::Const(c) => c.into(), + wf.compute(match t.term.unpack() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(c) => c.into(), }) } ty::PredicateKind::WellFormed(arg) => { @@ -436,11 +435,13 @@ impl<'tcx> WfPredicates<'tcx> { } /// Pushes all the predicates needed to validate that `ty` is WF into `out`. + #[instrument(level = "debug", skip(self))] fn compute(&mut self, arg: GenericArg<'tcx>) { let mut walker = arg.walk(); let param_env = self.param_env; let depth = self.recursion_depth; while let Some(arg) = walker.next() { + debug!(?arg, ?self.out); let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -455,7 +456,7 @@ impl<'tcx> WfPredicates<'tcx> { self.out.extend(obligations); let predicate = - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) .to_predicate(self.tcx()); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -490,6 +491,8 @@ impl<'tcx> WfPredicates<'tcx> { } }; + debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind()); + match *ty.kind() { ty::Bool | ty::Char @@ -636,7 +639,7 @@ impl<'tcx> WfPredicates<'tcx> { } } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // WfObject // // Here, we defer WF checking due to higher-ranked @@ -688,6 +691,8 @@ impl<'tcx> WfPredicates<'tcx> { )); } } + + debug!(?self.out); } } @@ -713,7 +718,7 @@ impl<'tcx> WfPredicates<'tcx> { iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) .map(|((mut pred, span), origin_def_id)| { let code = if span.is_dummy() { - traits::MiscObligation + traits::ItemObligation(origin_def_id) } else { traits::BindingObligation(origin_def_id, span) }; @@ -843,7 +848,7 @@ pub fn object_region_bounds<'tcx>( /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. -#[instrument(skip(tcx, predicates), level = "debug")] +#[instrument(skip(tcx, predicates), level = "debug", ret)] pub(crate) fn required_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, erased_self_ty: Ty<'tcx>, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index c7c604e14..45d5ea93d 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -191,7 +191,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi GenericArgKind::Const(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), + GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt), }, ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal( @@ -326,7 +326,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { )), }) } - ty::Dynamic(predicates, region) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { + // FIXME(dyn-star): handle the dynamic kind (dyn or dyn*) + ty::Dynamic(predicates, region, _kind) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner), lifetime: region.lower_into(interner), }), @@ -485,10 +486,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t }) .intern(interner) } - ty::ReEmpty(ui) => { - chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() }) - .intern(interner) - } ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner), } } @@ -510,8 +507,8 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime return interner.tcx.lifetimes.re_static, - chalk_ir::LifetimeData::Empty(ui) => { - ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter)) + chalk_ir::LifetimeData::Empty(_) => { + bug!("Chalk should not have been passed an empty lifetime.") } chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased, chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index e3e78f70b..691b79f10 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>( let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); let mut wf_args = vec![ty.into()]; - let mut implied_bounds = vec![]; + let mut outlives_bounds: Vec, ty::Region<'tcx>>> = + vec![]; let mut fulfill_cx = >::new(tcx); @@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>( // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) + // + // FIXME(@lcnr): It's not really "always fine", having fewer implied + // bounds can be backward incompatible, e.g. #101951 was caused by + // us not dealing with inference vars in `TypeOutlives` predicates. let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) .unwrap_or_default(); - // N.B., all of these predicates *ought* to be easily proven - // true. In fact, their correctness is (mostly) implied by - // other parts of the program. However, in #42552, we had - // an annoying scenario where: - // - // - Some `T::Foo` gets normalized, resulting in a - // variable `_1` and a `T: Trait` constraint - // (not sure why it couldn't immediately get - // solved). This result of `_1` got cached. - // - These obligations were dropped on the floor here, - // rather than being registered. - // - Then later we would get a request to normalize - // `T::Foo` which would result in `_1` being used from - // the cache, but hence without the `T: Trait` - // constraint. As a result, `_1` never gets resolved, - // and we get an ICE (in dropck). - // - // Therefore, we register any predicates involving - // inference variables. We restrict ourselves to those - // involving inference variables both for efficiency and - // to avoids duplicate errors that otherwise show up. + // While these predicates should all be implied by other parts of + // the program, they are still relevant as they may constrain + // inference variables, which is necessary to add the correct + // implied bounds in some cases, mostly when dealing with projections. fulfill_cx.register_predicate_obligations( infcx, obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(), @@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>( // From the full set of obligations, just filter down to the // region relationships. - implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { + outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| { assert!(!obligation.has_escaping_bound_vars()); match obligation.predicate.kind().no_bound_vars() { - None => vec![], + None => None, Some(pred) => match pred { ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) @@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![], + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); - vec![] + None } ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - vec![OutlivesBound::RegionSubRegion(r_b, r_a)] + Some(ty::OutlivesPredicate(r_a.into(), r_b)) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) + Some(ty::OutlivesPredicate(ty_a.into(), r_b)) } }, } @@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>( // Ensure that those obligations that we had to solve // get solved *here*. match fulfill_cx.select_all_or_error(infcx).as_slice() { - [] => Ok(implied_bounds), - _ => Err(NoSolution), + [] => (), + _ => return Err(NoSolution), } + + // We lazily compute the outlives components as + // `select_all_or_error` constrains inference variables. + let implied_bounds = outlives_bounds + .into_iter() + .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + ty::GenericArgKind::Type(ty_a) => { + let ty_a = infcx.resolve_vars_if_possible(ty_a); + let mut components = smallvec![]; + push_outlives_components(tcx, ty_a, &mut components); + implied_bounds_from_components(r_b, components) + } + ty::GenericArgKind::Const(_) => unreachable!(), + }) + .collect(); + + Ok(implied_bounds) } /// When we have an implied bound that `T: 'a`, we can further break diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 2bea164c0..2d39e973e 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -1,7 +1,9 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![feature(let_else)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index d895b647d..1bb6506b3 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngineExt as _; +use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ @@ -22,6 +22,7 @@ use rustc_trait_selection::traits::query::type_op::subtype::Subtype; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; use std::fmt; +use std::iter::zip; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -61,28 +62,32 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( mir_ty, def_id, user_substs ); - let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx }; - cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?; + let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx }; + cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?; Ok(()) } struct AscribeUserTypeCx<'me, 'tcx> { infcx: &'me InferCtxt<'me, 'tcx>, param_env: ParamEnv<'tcx>, + span: Span, fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { fn normalize(&mut self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID)) + } + + fn normalize_with_cause(&mut self, value: T, cause: ObligationCause<'tcx>) -> T where T: TypeFoldable<'tcx>, { self.infcx - .partially_normalize_associated_types_in( - ObligationCause::misc(DUMMY_SP, hir::CRATE_HIR_ID), - self.param_env, - value, - ) + .partially_normalize_associated_types_in(cause, self.param_env, value) .into_value_registering_obligations(self.infcx, self.fulfill_cx) } @@ -91,18 +96,13 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { T: ToTrace<'tcx>, { self.infcx - .at(&ObligationCause::dummy(), self.param_env) + .at(&ObligationCause::dummy_with_span(self.span), self.param_env) .relate(a, variance, b)? .into_value_registering_obligations(self.infcx, self.fulfill_cx); Ok(()) } - fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; + fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) { self.fulfill_cx.register_predicate_obligation( self.infcx, Obligation::new(cause, self.param_env, predicate), @@ -120,20 +120,20 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { EarlyBinder(value).subst(self.tcx(), substs) } + #[instrument(level = "debug", skip(self))] fn relate_mir_and_user_ty( &mut self, mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>, - span: Option, ) -> Result<(), NoSolution> { let UserSubsts { user_self_ty, substs } = user_substs; let tcx = self.tcx(); let ty = tcx.type_of(def_id); let ty = self.subst(ty, substs); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); let ty = self.normalize(ty); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); self.relate(mir_ty, Variance::Invariant, ty)?; @@ -144,10 +144,22 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // outlives" error messages. let instantiated_predicates = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); - debug!(?instantiated_predicates.predicates); - for instantiated_predicate in instantiated_predicates.predicates { - let instantiated_predicate = self.normalize(instantiated_predicate); - self.prove_predicate(instantiated_predicate, span); + + let cause = ObligationCause::dummy_with_span(self.span); + + debug!(?instantiated_predicates); + for (instantiated_predicate, predicate_span) in + zip(instantiated_predicates.predicates, instantiated_predicates.spans) + { + let span = if self.span == DUMMY_SP { predicate_span } else { self.span }; + let cause = ObligationCause::new( + span, + hir::CRATE_HIR_ID, + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), + ); + let instantiated_predicate = + self.normalize_with_cause(instantiated_predicate, cause.clone()); + self.prove_predicate(instantiated_predicate, cause); } if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { @@ -160,7 +172,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) .to_predicate(self.tcx()), - span, + cause.clone(), ); } @@ -177,7 +189,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // which...could happen with normalization... self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), - span, + cause, ); Ok(()) } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 9dc96e08a..aa6fe7d24 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" [dependencies] tracing = "0.1" -rustc_data_structures = { path = "../rustc_data_structures", optional = true} +rustc_data_structures = { path = "../rustc_data_structures"} +rustc_hir = { path = "../rustc_hir", optional = true} rustc_infer = { path = "../rustc_infer", optional = true} rustc_macros = { path = "../rustc_macros", optional = true} rustc_middle = { path = "../rustc_middle", optional = true} @@ -17,7 +18,7 @@ rustc_target = { path = "../rustc_target", optional = true} [features] rustc = [ "rustc_middle", - "rustc_data_structures", + "rustc_hir", "rustc_infer", "rustc_macros", "rustc_span", diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index b60ea6e7a..b8922696e 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -104,7 +104,6 @@ where } #[instrument(level = "debug")] - #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] pub(crate) fn from_nfa(nfa: Nfa) -> Self { let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index f25e3c1fd..c2bc47bc0 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -119,8 +119,6 @@ where let mut transitions: Map, Set>> = self.transitions; - // the iteration order doesn't matter - #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] for (source, transition) in other.transitions { let fix_state = |state| if state == other.start { self.accepting } else { state }; let entry = transitions.entry(fix_state(source)).or_default(); @@ -142,8 +140,6 @@ where let mut transitions: Map, Set>> = self.transitions.clone(); - // the iteration order doesn't matter - #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] for (&(mut source), transition) in other.transitions.iter() { // if source is starting state of `other`, replace with starting state of `self` if source == other.start { @@ -152,8 +148,6 @@ where let entry = transitions.entry(source).or_default(); for (edge, destinations) in transition { let entry = entry.entry(edge.clone()).or_default(); - // the iteration order doesn't matter - #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] for &(mut destination) in destinations { // if dest is accepting state of `other`, replace with accepting state of `self` if destination == other.accepting { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 70b3ba02b..211c813b8 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -1,4 +1,5 @@ use super::{Byte, Def, Ref}; +use std::ops::ControlFlow; #[cfg(test)] mod tests; @@ -86,17 +87,18 @@ where F: Fn(D) -> bool, { match self { - Self::Seq(elts) => elts - .into_iter() - .map(|elt| elt.prune(f)) - .try_fold(Tree::unit(), |elts, elt| { + Self::Seq(elts) => match elts.into_iter().map(|elt| elt.prune(f)).try_fold( + Tree::unit(), + |elts, elt| { if elt == Tree::uninhabited() { - Err(Tree::uninhabited()) + ControlFlow::Break(Tree::uninhabited()) } else { - Ok(elts.then(elt)) + ControlFlow::Continue(elts.then(elt)) } - }) - .into_ok_or_err(), + }, + ) { + ControlFlow::Break(node) | ControlFlow::Continue(node) => node, + }, Self::Alt(alts) => alts .into_iter() .map(|alt| alt.prune(f)) @@ -315,7 +317,7 @@ pub(crate) mod rustc { tcx, )?, AdtKind::Enum => { - tracing::trace!(?adt_def, "treeifying enum"); + trace!(?adt_def, "treeifying enum"); let mut tree = Tree::uninhabited(); for (idx, discr) in adt_def.discriminants(tcx) { @@ -379,7 +381,7 @@ pub(crate) mod rustc { let clamp = |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap(); - let variant_span = tracing::trace_span!( + let variant_span = trace_span!( "treeifying variant", min_align = ?min_align, max_align = ?max_align, @@ -394,27 +396,27 @@ pub(crate) mod rustc { // The layout of the variant is prefixed by the discriminant, if any. if let Some(discr) = discr { - tracing::trace!(?discr, "treeifying discriminant"); + trace!(?discr, "treeifying discriminant"); let discr_layout = alloc::Layout::from_size_align( layout_summary.discriminant_size, clamp(layout_summary.discriminant_align), ) .unwrap(); - tracing::trace!(?discr_layout, "computed discriminant layout"); + trace!(?discr_layout, "computed discriminant layout"); variant_layout = variant_layout.extend(discr_layout).unwrap().0; tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); } // Next come fields. - let fields_span = tracing::trace_span!("treeifying fields").entered(); + let fields_span = trace_span!("treeifying fields").entered(); for field_def in variant_def.fields.iter() { let field_ty = field_def.ty(tcx, substs_ref); - let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered(); + let _span = trace_span!("treeifying field", field = ?field_ty).entered(); // begin with the field's visibility tree = tree.then(Self::def(Def::Field(field_def))); - // compute the field's layout charactaristics + // compute the field's layout characteristics let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); // next comes the field's padding @@ -432,7 +434,7 @@ pub(crate) mod rustc { drop(fields_span); // finally: padding - let padding_span = tracing::trace_span!("adding trailing padding").entered(); + let padding_span = trace_span!("adding trailing padding").entered(); let padding_needed = layout_summary.total_size - variant_layout.size(); if padding_needed > 0 { tree = tree.then(Self::padding(padding_needed)); @@ -465,7 +467,7 @@ pub(crate) mod rustc { layout.align().abi.bytes().try_into().unwrap(), ) .unwrap(); - tracing::trace!(?ty, ?layout, "computed layout for type"); + trace!(?ty, ?layout, "computed layout for type"); Ok(layout) } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index cfc7c752a..64cd70d36 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,21 +1,12 @@ -#![feature( - alloc_layout_extra, - control_flow_enum, - decl_macro, - iterator_try_reduce, - never_type, - result_into_ok_or_err -)] +#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; -#[cfg(feature = "rustc")] -pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set}; - -#[cfg(not(feature = "rustc"))] -pub(crate) use std::collections::{HashMap as Map, HashSet as Set}; +pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; pub(crate) mod layout; pub(crate) mod maybe_transmutable; @@ -24,8 +15,8 @@ pub(crate) mod maybe_transmutable; pub struct Assume { pub alignment: bool, pub lifetimes: bool, + pub safety: bool, pub validity: bool, - pub visibility: bool, } /// The type encodes answers to the question: "Are these types transmutable?" @@ -67,11 +58,17 @@ pub enum Reason { #[cfg(feature = "rustc")] mod rustc { + use super::*; + + use rustc_hir::lang_items::LangItem; use rustc_infer::infer::InferCtxt; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::Binder; + use rustc_middle::ty::Const; + use rustc_middle::ty::ParamEnv; use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; /// The source and destination types of a transmutation. #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)] @@ -111,6 +108,54 @@ mod rustc { .answer() } } + + impl Assume { + /// Constructs an `Assume` from a given const-`Assume`. + pub fn from_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + c: Const<'tcx>, + ) -> Self { + use rustc_middle::ty::ScalarInt; + use rustc_middle::ty::TypeVisitable; + use rustc_span::symbol::sym; + + let c = c.eval(tcx, param_env); + + if let Some(err) = c.error_reported() { + return Self { alignment: true, lifetimes: true, safety: true, validity: true }; + } + + let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT."); + + assert_eq!( + tcx.require_lang_item(LangItem::TransmuteOpts, None), + adt_def.did(), + "The given `Const` was not marked with the `{}` lang item.", + LangItem::TransmuteOpts.name(), + ); + + let variant = adt_def.non_enum_variant(); + let fields = c.to_valtree().unwrap_branch(); + + let get_field = |name| { + let (field_idx, _) = variant + .fields + .iter() + .enumerate() + .find(|(_, field_def)| name == field_def.name) + .expect(&format!("There were no fields named `{name}`.")); + fields[field_idx].unwrap_leaf() == ScalarInt::TRUE + }; + + Self { + alignment: get_field(sym::alignment), + lifetimes: get_field(sym::lifetimes), + safety: get_field(sym::safety), + validity: get_field(sym::validity), + } + } + } } #[cfg(feature = "rustc")] diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 076d922d1..1186eac37 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -105,12 +105,12 @@ where #[inline(always)] #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { - let assume_visibility = self.assume.visibility; + let assume_visibility = self.assume.safety; let query_or_answer = self.map_layouts(|src, dst, scope, context| { // Remove all `Def` nodes from `src`, without checking their visibility. let src = src.prune(&|def| true); - tracing::trace!(?src, "pruned src"); + trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... let dst = if assume_visibility { @@ -121,7 +121,7 @@ where dst.prune(&|def| context.is_accessible_from(def, scope)) }; - tracing::trace!(?dst, "pruned dst"); + trace!(?dst, "pruned dst"); // Convert `src` from a tree-based representation to an NFA-based representation. // If the conversion fails because `src` is uninhabited, conclude that the transmutation diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 9c2cf4c9a..adab343ac 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -82,7 +82,7 @@ mod rustc { false }; - tracing::trace!(?ret, "ret"); + trace!(?ret, "ret"); ret } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index d9d125687..4d5772a4f 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -13,7 +13,7 @@ mod bool { layout::Tree::::bool(), layout::Tree::::bool(), (), - crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, UltraMinimal, ) .answer(); @@ -26,7 +26,7 @@ mod bool { layout::Dfa::::bool(), layout::Dfa::::bool(), (), - crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, UltraMinimal, ) .answer(); diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index caad2ed42..52fbd3ae0 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -10,6 +10,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 7c2f4db94..44c4fc48d 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -11,6 +11,8 @@ use rustc_target::abi::VariantIdx; use std::iter; +use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub}; + /// Destructures array, ADT or tuple constants into the constants /// of their fields. pub(crate) fn destructure_const<'tcx>( @@ -93,26 +95,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.body.exprs[self.body_id].span } - fn error(&mut self, span: Span, msg: &str) -> Result { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .emit(); + fn error(&mut self, sub: GenericConstantTooComplexSub) -> Result { + let reported = self.tcx.sess.emit_err(GenericConstantTooComplex { + span: self.root_span(), + maybe_supported: None, + sub, + }); Err(reported) } - fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .note("this operation may be supported in the future") - .emit(); + + fn maybe_supported_error( + &mut self, + sub: GenericConstantTooComplexSub, + ) -> Result { + let reported = self.tcx.sess.emit_err(GenericConstantTooComplex { + span: self.root_span(), + maybe_supported: Some(()), + sub, + }); Err(reported) } @@ -154,9 +155,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { return true; } - match pat.kind.as_ref() { + match pat.kind { thir::PatKind::Constant { value } => value.has_param_types_or_consts(), - thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => { + thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { lo.has_param_types_or_consts() || hi.has_param_types_or_consts() } _ => false, @@ -221,17 +222,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { debug!("AbstractConstBuilder::build: body={:?}", &*self.body); self.recurse_build(self.body_id)?; - for n in self.nodes.iter() { - if let Node::Leaf(ct) = n { - if let ty::ConstKind::Unevaluated(ct) = ct.kind() { - // `AbstractConst`s should not contain any promoteds as they require references which - // are not allowed. - assert_eq!(ct.promoted, None); - assert_eq!(ct, self.tcx.erase_regions(ct)); - } - } - } - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) } @@ -243,22 +233,23 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Scope { value, .. } => self.recurse_build(value)?, &ExprKind::PlaceTypeAscription { source, .. } | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, - &ExprKind::Literal { lit, neg} => { + &ExprKind::Literal { lit, neg } => { let sp = node.span; - let constant = - match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported) => { - self.tcx.const_error(node.ty) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in lit_to_const") - } - }; + let constant = match self.tcx.at(sp).lit_to_const(LitToConstInput { + lit: &lit.node, + ty: node.ty, + neg, + }) { + Ok(c) => c, + Err(LitToConstError::Reported) => self.tcx.const_error(node.ty), + Err(LitToConstError::TypeError) => { + bug!("encountered type error in lit_to_const") + } + }; self.nodes.push(Node::Leaf(constant)) } - &ExprKind::NonHirLiteral { lit , user_ty: _} => { + &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(lit); self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) } @@ -269,19 +260,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); - let constant = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(uneval), - ty: node.ty, - }); + let constant = self + .tcx + .mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(uneval), ty: node.ty }); self.nodes.push(Node::Leaf(constant)) } - ExprKind::ConstParam {param, ..} => { - let const_param = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Param(*param), - ty: node.ty, - }); + ExprKind::ConstParam { param, .. } => { + let const_param = self + .tcx + .mk_const(ty::ConstS { kind: ty::ConstKind::Param(*param), ty: node.ty }); self.nodes.push(Node::Leaf(const_param)) } @@ -311,8 +300,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // bar::<{ N + 1 }>(); // } // ``` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { - self.recurse_build(*e)? + ExprKind::Block { block } => { + if let thir::Block { stmts: box [], expr: Some(e), .. } = &self.body.blocks[*block] + { + self.recurse_build(*e)? + } else { + self.maybe_supported_error(GenericConstantTooComplexSub::BlockNotSupported( + node.span, + ))? + } } // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. @@ -325,7 +321,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(CastKind::As, arg, node.ty)) } - ExprKind::Borrow{ arg, ..} => { + ExprKind::Borrow { arg, .. } => { let arg_node = &self.body.exprs[*arg]; // Skip reborrows for now until we allow Deref/Borrow/AddressOf @@ -334,80 +330,69 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { if let ExprKind::Deref { arg } = arg_node.kind { self.recurse_build(arg)? } else { - self.maybe_supported_error( + self.maybe_supported_error(GenericConstantTooComplexSub::BorrowNotSupported( node.span, - "borrowing is not supported in generic constants", - )? + ))? } } // FIXME(generic_const_exprs): We may want to support these. - ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error( - node.span, - "dereferencing or taking the address is not supported in generic constants", - )?, - ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( - node.span, - "array construction is not supported in generic constants", + ExprKind::AddressOf { .. } | ExprKind::Deref { .. } => self.maybe_supported_error( + GenericConstantTooComplexSub::AddressAndDerefNotSupported(node.span), )?, - ExprKind::Block { .. } => self.maybe_supported_error( - node.span, - "blocks are not supported in generic constant", + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + GenericConstantTooComplexSub::ArrayNotSupported(node.span), )?, ExprKind::NeverToAny { .. } => self.maybe_supported_error( - node.span, - "converting nevers to any is not supported in generic constant", + GenericConstantTooComplexSub::NeverToAnyNotSupported(node.span), )?, ExprKind::Tuple { .. } => self.maybe_supported_error( - node.span, - "tuple construction is not supported in generic constants", + GenericConstantTooComplexSub::TupleNotSupported(node.span), )?, ExprKind::Index { .. } => self.maybe_supported_error( - node.span, - "indexing is not supported in generic constant", + GenericConstantTooComplexSub::IndexNotSupported(node.span), )?, ExprKind::Field { .. } => self.maybe_supported_error( - node.span, - "field access is not supported in generic constant", + GenericConstantTooComplexSub::FieldNotSupported(node.span), )?, ExprKind::ConstBlock { .. } => self.maybe_supported_error( - node.span, - "const blocks are not supported in generic constant", - )?, - ExprKind::Adt(_) => self.maybe_supported_error( - node.span, - "struct/enum construction is not supported in generic constants", + GenericConstantTooComplexSub::ConstBlockNotSupported(node.span), )?, + ExprKind::Adt(_) => self + .maybe_supported_error(GenericConstantTooComplexSub::AdtNotSupported(node.span))?, // dont know if this is correct - ExprKind::Pointer { .. } => - self.error(node.span, "pointer casts are not allowed in generic constants")?, - ExprKind::Yield { .. } => - self.error(node.span, "generator control flow is not allowed in generic constants")?, - ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self - .error( - node.span, - "loops and loop control flow are not supported in generic constants", - )?, - ExprKind::Box { .. } => - self.error(node.span, "allocations are not allowed in generic constants")?, + ExprKind::Pointer { .. } => { + self.error(GenericConstantTooComplexSub::PointerNotSupported(node.span))? + } + ExprKind::Yield { .. } => { + self.error(GenericConstantTooComplexSub::YieldNotSupported(node.span))? + } + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => { + self.error(GenericConstantTooComplexSub::LoopNotSupported(node.span))? + } + ExprKind::Box { .. } => { + self.error(GenericConstantTooComplexSub::BoxNotSupported(node.span))? + } ExprKind::Unary { .. } => unreachable!(), // we handle valid unary/binary ops above - ExprKind::Binary { .. } => - self.error(node.span, "unsupported binary operation in generic constants")?, - ExprKind::LogicalOp { .. } => - self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Binary { .. } => { + self.error(GenericConstantTooComplexSub::BinaryNotSupported(node.span))? + } + ExprKind::LogicalOp { .. } => { + self.error(GenericConstantTooComplexSub::LogicalOpNotSupported(node.span))? + } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - self.error(node.span, "assignment is not supported in generic constants")? + self.error(GenericConstantTooComplexSub::AssignNotSupported(node.span))? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => { + self.error(GenericConstantTooComplexSub::ClosureAndReturnNotSupported(node.span))? } - ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( - node.span, - "closures and function keywords are not supported in generic constants", - )?, // let expressions imply control flow - ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => - self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => { + self.error(GenericConstantTooComplexSub::ControlFlowNotSupported(node.span))? + } ExprKind::InlineAsm { .. } => { - self.error(node.span, "assembly is not supported in generic constants")? + self.error(GenericConstantTooComplexSub::InlineAsmNotSupported(node.span))? } // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen @@ -415,7 +400,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::UpvarRef { .. } | ExprKind::StaticRef { .. } | ExprKind::ThreadLocalRef(_) => { - self.error(node.span, "unsupported operation in generic constant")? + self.error(GenericConstantTooComplexSub::OperationNotSupported(node.span))? } }) } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs new file mode 100644 index 000000000..3a8ef96c9 --- /dev/null +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -0,0 +1,69 @@ +//! Errors emitted by ty_utils + +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::Ty; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(ty_utils::needs_drop_overflow)] +pub struct NeedsDropOverflow<'tcx> { + pub query_ty: Ty<'tcx>, +} + +#[derive(SessionDiagnostic)] +#[diag(ty_utils::generic_constant_too_complex)] +#[help] +pub struct GenericConstantTooComplex { + #[primary_span] + pub span: Span, + #[note(ty_utils::maybe_supported)] + pub maybe_supported: Option<()>, + #[subdiagnostic] + pub sub: GenericConstantTooComplexSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum GenericConstantTooComplexSub { + #[label(ty_utils::borrow_not_supported)] + BorrowNotSupported(#[primary_span] Span), + #[label(ty_utils::address_and_deref_not_supported)] + AddressAndDerefNotSupported(#[primary_span] Span), + #[label(ty_utils::array_not_supported)] + ArrayNotSupported(#[primary_span] Span), + #[label(ty_utils::block_not_supported)] + BlockNotSupported(#[primary_span] Span), + #[label(ty_utils::never_to_any_not_supported)] + NeverToAnyNotSupported(#[primary_span] Span), + #[label(ty_utils::tuple_not_supported)] + TupleNotSupported(#[primary_span] Span), + #[label(ty_utils::index_not_supported)] + IndexNotSupported(#[primary_span] Span), + #[label(ty_utils::field_not_supported)] + FieldNotSupported(#[primary_span] Span), + #[label(ty_utils::const_block_not_supported)] + ConstBlockNotSupported(#[primary_span] Span), + #[label(ty_utils::adt_not_supported)] + AdtNotSupported(#[primary_span] Span), + #[label(ty_utils::pointer_not_supported)] + PointerNotSupported(#[primary_span] Span), + #[label(ty_utils::yield_not_supported)] + YieldNotSupported(#[primary_span] Span), + #[label(ty_utils::loop_not_supported)] + LoopNotSupported(#[primary_span] Span), + #[label(ty_utils::box_not_supported)] + BoxNotSupported(#[primary_span] Span), + #[label(ty_utils::binary_not_supported)] + BinaryNotSupported(#[primary_span] Span), + #[label(ty_utils::logical_op_not_supported)] + LogicalOpNotSupported(#[primary_span] Span), + #[label(ty_utils::assign_not_supported)] + AssignNotSupported(#[primary_span] Span), + #[label(ty_utils::closure_and_return_not_supported)] + ClosureAndReturnNotSupported(#[primary_span] Span), + #[label(ty_utils::control_flow_not_supported)] + ControlFlowNotSupported(#[primary_span] Span), + #[label(ty_utils::inline_asm_not_supported)] + InlineAsmNotSupported(#[primary_span] Span), + #[label(ty_utils::operation_not_supported)] + OperationNotSupported(#[primary_span] Span), +} diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs new file mode 100644 index 000000000..f0d8c240e --- /dev/null +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -0,0 +1,61 @@ +use crate::rustc_middle::ty::DefIdTree; +use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { assumed_wf_types, ..*providers }; +} + +fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::List> { + match tcx.def_kind(def_id) { + DefKind::Fn => { + let sig = tcx.fn_sig(def_id); + let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); + liberated_sig.inputs_and_output + } + DefKind::AssocFn => { + let sig = tcx.fn_sig(def_id); + let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); + let mut assumed_wf_types: Vec<_> = + tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into(); + assumed_wf_types.extend(liberated_sig.inputs_and_output); + tcx.intern_type_list(&assumed_wf_types) + } + DefKind::Impl => match tcx.impl_trait_ref(def_id) { + Some(trait_ref) => { + let types: Vec<_> = trait_ref.substs.types().collect(); + tcx.intern_type_list(&types) + } + // Only the impl self type + None => tcx.intern_type_list(&[tcx.type_of(def_id)]), + }, + DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)), + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static(_) + | DefKind::Ctor(_, _) + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Closure + | DefKind::Generator => ty::List::empty(), + } +} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index bd1d568cd..05738b6c4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -3,115 +3,11 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{ - self, Binder, Instance, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; +use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable}; use rustc_span::{sym, DUMMY_SP}; use rustc_trait_selection::traits; use traits::{translate_substs, Reveal}; -use rustc_data_structures::sso::SsoHashSet; -use std::collections::btree_map::Entry; -use std::collections::BTreeMap; -use std::ops::ControlFlow; - -use tracing::debug; - -// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used -// outside of `resolve_associated_item`. It's just to address #64494, -// #83765, and #85848 which are creating bound types/regions that lose -// their `Binder` *unintentionally*. -// It's ideal to remove `BoundVarsCollector` and just use -// `ty::Binder::*` methods but we use this stopgap until we figure out -// the "real" fix. -struct BoundVarsCollector<'tcx> { - binder_index: ty::DebruijnIndex, - vars: BTreeMap, - // We may encounter the same variable at different levels of binding, so - // this can't just be `Ty` - visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, -} - -impl<'tcx> BoundVarsCollector<'tcx> { - fn new() -> Self { - BoundVarsCollector { - binder_index: ty::INNERMOST, - vars: BTreeMap::new(), - visited: SsoHashSet::default(), - } - } - - fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List { - let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or(0); - for i in 0..max { - if let None = self.vars.get(&i) { - panic!("Unknown variable: {:?}", i); - } - } - - tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v)) - } -} - -impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - type BreakTy = (); - - fn visit_binder>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if t.outer_exclusive_binder() < self.binder_index - || !self.visited.insert((self.binder_index, t)) - { - return ControlFlow::CONTINUE; - } - match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - match self.vars.entry(bound_ty.var.as_u32()) { - Entry::Vacant(entry) => { - entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind)); - } - Entry::Occupied(entry) => match entry.get() { - ty::BoundVariableKind::Ty(_) => {} - _ => bug!("Conflicting bound vars"), - }, - } - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - match *r { - ty::ReLateBound(index, br) if index == self.binder_index => { - match self.vars.entry(br.var.as_u32()) { - Entry::Vacant(entry) => { - entry.insert(ty::BoundVariableKind::Region(br.kind)); - } - Entry::Occupied(entry) => match entry.get() { - ty::BoundVariableKind::Region(_) => {} - _ => bug!("Conflicting bound vars"), - }, - } - } - - _ => (), - }; - - r.super_visit_with(self) - } -} - fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, @@ -203,19 +99,14 @@ fn resolve_associated_item<'tcx>( let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - // See FIXME on `BoundVarsCollector`. - let mut bound_vars_collector = BoundVarsCollector::new(); - trait_ref.visit_with(&mut bound_vars_collector); - let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx)); - let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) { + let vtbl = match tcx.codegen_select_candidate((param_env, ty::Binder::dummy(trait_ref))) { Ok(vtbl) => vtbl, Err(CodegenObligationError::Ambiguity) => { let reported = tcx.sess.delay_span_bug( tcx.def_span(trait_item_id), &format!( - "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ + "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ overflow or prior type error", - trait_binder ), ); return Err(reported); @@ -372,7 +263,10 @@ fn resolve_associated_item<'tcx>( let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); match self_ty.kind() { _ if is_copy => (), - ty::Closure(..) | ty::Tuple(..) => {} + ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Closure(..) + | ty::Tuple(..) => {} _ => return Ok(None), }; @@ -397,7 +291,8 @@ fn resolve_associated_item<'tcx>( | traits::ImplSource::DiscriminantKind(..) | traits::ImplSource::Pointee(..) | traits::ImplSource::TraitUpcasting(_) - | traits::ImplSource::ConstDestruct(_) => None, + | traits::ImplSource::ConstDestruct(_) + | traits::ImplSource::Tuple => None, }) } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 09f5c2a11..8524e57cb 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,10 +6,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(control_flow_enum)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; @@ -21,6 +23,8 @@ use rustc_middle::ty::query::Providers; mod assoc; mod common_traits; mod consts; +mod errors; +mod implied_bounds; pub mod instance; mod needs_drop; pub mod representability; @@ -30,6 +34,7 @@ pub fn provide(providers: &mut Providers) { assoc::provide(providers); common_traits::provide(providers); consts::provide(providers); + implied_bounds::provide(providers); needs_drop::provide(providers); ty::provide(providers); instance::provide(providers); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 9ad44d14d..ab5a3d8ae 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::{sym, DUMMY_SP}; +use crate::errors::NeedsDropOverflow; + type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -90,10 +92,7 @@ where if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. - tcx.sess.span_err( - DUMMY_SP, - &format!("overflow while checking whether `{}` requires drop", self.query_ty), - ); + tcx.sess.emit_err(NeedsDropOverflow { query_ty: self.query_ty }); return Some(Err(AlwaysRequiresDrop)); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index db0d45b86..9266e4e3f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -104,7 +104,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain } /// See `ParamEnv` struct definition for details. -#[instrument(level = "debug", skip(tcx))] fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // The param_env of an impl Trait type is its defining function's param_env if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { @@ -348,7 +347,7 @@ fn instance_def_size_estimate<'tcx>( match instance_def { InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { let mir = tcx.instance_mir(instance_def); - mir.basic_blocks().iter().map(|bb| bb.statements.len() + 1).sum() + mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() } // Estimate the size of other compiler-generated shims to be 1. _ => 1, @@ -390,7 +389,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let self_ty = trait_ref.self_ty(); let self_ty_matches = match self_ty.kind() { - ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(), + ty::Dynamic(ref data, re, _) if re.is_static() => data.principal().is_none(), _ => false, }; @@ -410,7 +409,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { } /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. -#[instrument(level = "debug", skip(tcx))] pub fn conservative_is_privately_uninhabited_raw<'tcx>( tcx: TyCtxt<'tcx>, param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 791e9e0f5..da30344ef 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,6 +1,8 @@ #![feature(fmt_helpers_for_derive)] #![feature(min_specialization)] #![feature(rustc_attrs)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate bitflags; @@ -21,6 +23,9 @@ pub mod sty; pub use codec::*; pub use sty::*; +/// Needed so we can use #[derive(HashStable_Generic)] +pub trait HashStableContext {} + pub trait Interner { type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; @@ -293,6 +298,7 @@ rustc_index::newtype_index! { /// is the outer fn. /// /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index + #[derive(HashStable_Generic)] pub struct DebruijnIndex { DEBUG_FORMAT = "DebruijnIndex({})", const INNERMOST = 0, @@ -364,7 +370,7 @@ impl DebruijnIndex { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum IntTy { Isize, I8, @@ -411,7 +417,7 @@ impl IntTy { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum UintTy { Usize, U8, @@ -458,7 +464,7 @@ impl UintTy { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum FloatTy { F32, F64, @@ -595,7 +601,7 @@ impl UnifyKey for FloatVid { } } -#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)] +#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)] #[rustc_pass_by_value] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -664,30 +670,6 @@ impl Variance { } } -impl HashStable for DebruijnIndex { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.as_u32().hash_stable(ctx, hasher); - } -} - -impl HashStable for IntTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - -impl HashStable for UintTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - -impl HashStable for FloatTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - impl HashStable for InferTy { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; @@ -701,12 +683,6 @@ impl HashStable for InferTy { } } -impl HashStable for Variance { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - impl fmt::Debug for IntVarValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -809,6 +785,7 @@ rustc_index::newtype_index! { /// declared, but a type name in a non-zero universe is a placeholder /// type -- an idealized representative of "types in general" that we /// use for checking generic functions. + #[derive(HashStable_Generic)] pub struct UniverseIndex { DEBUG_FORMAT = "U{}", } @@ -848,9 +825,3 @@ impl UniverseIndex { self.private < other.private } } - -impl HashStable for UniverseIndex { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.private.hash_stable(ctx, hasher); - } -} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 74737e30b..6d54924e5 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -5,12 +5,12 @@ use std::{fmt, hash}; use crate::DebruijnIndex; use crate::FloatTy; +use crate::HashStableContext; use crate::IntTy; use crate::Interner; use crate::TyDecoder; use crate::TyEncoder; use crate::UintTy; -use crate::UniverseIndex; use self::RegionKind::*; use self::TyKind::*; @@ -18,6 +18,34 @@ use self::TyKind::*; use rustc_data_structures::stable_hasher::HashStable; use rustc_serialize::{Decodable, Decoder, Encodable}; +/// Specifies how a trait object is represented. +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Encodable, + Decodable, + HashStable_Generic +)] +pub enum DynKind { + /// An unsized `dyn Trait` object + Dyn, + /// A sized `dyn* Trait` object + /// + /// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value + /// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to + /// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait` + /// or similar, but the drop function included in the vtable is responsible for freeing the + /// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with + /// respect to whether it points to a `Box`, `Rc`, etc. + DynStar, +} + /// Defines the kinds of types used by the type system. /// /// Types written by the user start out as `hir::TyKind` and get @@ -95,7 +123,7 @@ pub enum TyKind { FnPtr(I::PolyFnSig), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(I::ListBinderExistentialPredicate, I::Region), + Dynamic(I::ListBinderExistentialPredicate, I::Region, DynKind), /// The anonymous type of a closure. Used to represent the type of `|a| a`. /// @@ -218,7 +246,7 @@ const fn tykind_discriminant(value: &TyKind) -> usize { Ref(_, _, _) => 11, FnDef(_, _) => 12, FnPtr(_) => 13, - Dynamic(_, _) => 14, + Dynamic(..) => 14, Closure(_, _) => 15, Generator(_, _, _) => 16, GeneratorWitness(_) => 17, @@ -252,7 +280,7 @@ impl Clone for TyKind { Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), - Dynamic(p, r) => Dynamic(p.clone(), r.clone()), + Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()), Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), @@ -297,9 +325,10 @@ impl PartialEq for TyKind { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && self_repr == arg_repr, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } @@ -384,12 +413,16 @@ impl Ord for TyKind { } } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => match Ord::cmp(__self_0, __arg_1_0) { + Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { + Ordering::Equal => Ord::cmp(self_repr, arg_repr), cmp => cmp, - } - } + }, + cmp => cmp, + }, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { match Ord::cmp(__self_0, __arg_1_0) { Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), @@ -492,10 +525,11 @@ impl hash::Hash for TyKind { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } - (&Dynamic(ref __self_0, ref __self_1),) => { + (&Dynamic(ref __self_0, ref __self_1, ref repr),) => { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) + hash::Hash::hash(__self_1, state); + hash::Hash::hash(repr, state) } (&Closure(ref __self_0, ref __self_1),) => { hash::Hash::hash(&tykind_discriminant(self), state); @@ -570,7 +604,7 @@ impl fmt::Debug for TyKind { Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2), FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1), FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0), - Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1), + Dynamic(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Dynamic", f0, f1, f2), Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1), Generator(f0, f1, f2) => { Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2) @@ -659,9 +693,10 @@ where FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| { polyfnsig.encode(e); }), - Dynamic(l, r) => e.emit_enum_variant(disc, |e| { + Dynamic(l, r, repr) => e.emit_enum_variant(disc, |e| { l.encode(e); r.encode(e); + repr.encode(e); }), Closure(def_id, substs) => e.emit_enum_variant(disc, |e| { def_id.encode(e); @@ -748,7 +783,7 @@ where 11 => Ref(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 12 => FnDef(Decodable::decode(d), Decodable::decode(d)), 13 => FnPtr(Decodable::decode(d)), - 14 => Dynamic(Decodable::decode(d), Decodable::decode(d)), + 14 => Dynamic(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 15 => Closure(Decodable::decode(d), Decodable::decode(d)), 16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 17 => GeneratorWitness(Decodable::decode(d)), @@ -774,7 +809,7 @@ where // This is not a derived impl because a derive would require `I: HashStable` #[allow(rustc::usage_of_ty_tykind)] -impl HashStable for TyKind +impl HashStable for TyKind where I::AdtDef: HashStable, I::DefId: HashStable, @@ -845,9 +880,10 @@ where FnPtr(polyfnsig) => { polyfnsig.hash_stable(__hcx, __hasher); } - Dynamic(l, r) => { + Dynamic(l, r, repr) => { l.hash_stable(__hcx, __hasher); r.hash_stable(__hcx, __hasher); + repr.hash_stable(__hcx, __hasher); } Closure(def_id, substs) => { def_id.hash_stable(__hcx, __hasher); @@ -1023,14 +1059,6 @@ pub enum RegionKind { /// Should not exist outside of type inference. RePlaceholder(I::PlaceholderRegion), - /// Empty lifetime is for data that is never accessed. We tag the - /// empty lifetime with a universe -- the idea is that we don't - /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable. - /// Therefore, the `'empty` in a universe `U` is less than all - /// regions visible from `U`, but not less than regions not visible - /// from `U`. - ReEmpty(UniverseIndex), - /// Erased region, used by trait selection, in MIR and during codegen. ReErased, } @@ -1046,8 +1074,7 @@ const fn regionkind_discriminant(value: &RegionKind) -> usize { ReStatic => 3, ReVar(_) => 4, RePlaceholder(_) => 5, - ReEmpty(_) => 6, - ReErased => 7, + ReErased => 6, } } @@ -1072,7 +1099,6 @@ impl Clone for RegionKind { ReStatic => ReStatic, ReVar(a) => ReVar(a.clone()), RePlaceholder(a) => RePlaceholder(a.clone()), - ReEmpty(a) => ReEmpty(a.clone()), ReErased => ReErased, } } @@ -1099,7 +1125,6 @@ impl PartialEq for RegionKind { (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { __self_0 == __arg_1_0 } - (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => __self_0 == __arg_1_0, (&ReErased, &ReErased) => true, _ => true, } @@ -1144,7 +1169,6 @@ impl Ord for RegionKind { (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { Ord::cmp(__self_0, __arg_1_0) } - (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), (&ReErased, &ReErased) => Ordering::Equal, _ => Ordering::Equal, } @@ -1182,10 +1206,6 @@ impl hash::Hash for RegionKind { hash::Hash::hash(®ionkind_discriminant(self), state); hash::Hash::hash(__self_0, state) } - (&ReEmpty(ref __self_0),) => { - hash::Hash::hash(®ionkind_discriminant(self), state); - hash::Hash::hash(__self_0, state) - } (&ReErased,) => { hash::Hash::hash(®ionkind_discriminant(self), state); } @@ -1211,8 +1231,6 @@ impl fmt::Debug for RegionKind { RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder), - ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui), - ReErased => write!(f, "ReErased"), } } @@ -1247,9 +1265,6 @@ where RePlaceholder(a) => e.emit_enum_variant(disc, |e| { a.encode(e); }), - ReEmpty(a) => e.emit_enum_variant(disc, |e| { - a.encode(e); - }), ReErased => e.emit_enum_variant(disc, |_| {}), } } @@ -1272,8 +1287,7 @@ where 3 => ReStatic, 4 => ReVar(Decodable::decode(d)), 5 => RePlaceholder(Decodable::decode(d)), - 6 => ReEmpty(Decodable::decode(d)), - 7 => ReErased, + 6 => ReErased, _ => panic!( "{}", format!( @@ -1286,7 +1300,7 @@ where } // This is not a derived impl because a derive would require `I: HashStable` -impl HashStable for RegionKind +impl HashStable for RegionKind where I::EarlyBoundRegion: HashStable, I::BoundRegion: HashStable, @@ -1305,9 +1319,6 @@ where ReErased | ReStatic => { // No variant fields to hash for these ... } - ReEmpty(universe) => { - universe.hash_stable(hcx, hasher); - } ReLateBound(db, br) => { db.hash_stable(hcx, hasher); br.hash_stable(hcx, hasher); diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index faf52e269..cae29c1d3 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" } rustc_lint = { path = "../rustc_lint" } rustc_serialize = { path = "../rustc_serialize" } rustc_type_ir = { path = "../rustc_type_ir" } +rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index ff39bf361..a9152bdc5 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -29,6 +29,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.tcx().sess.emit_err(MissingTypeParams { span, def_span: self.tcx().def_span(def_id), + span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(), missing_type_params, empty_generic_args, }); diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 40aa27a29..afac75de2 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -298,9 +298,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // show that order to the user as a possible order for the parameters let mut param_types_present = defs .params - .clone() - .into_iter() - .map(|param| (param.kind.to_ord(), param)) + .iter() + .map(|param| (param.kind.to_ord(), param.clone())) .collect::>(); param_types_present.sort_by_key(|(ord, _)| *ord); let (mut param_types_present, ordered_params): ( @@ -648,7 +647,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { multispan.push_span_label(span_late, note); tcx.struct_span_lint_hir( LATE_BOUND_LIFETIME_ARGUMENTS, - args.args[0].id(), + args.args[0].hir_id(), multispan, |lint| { lint.build(msg).emit(); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8a5c7fee6..4bf9562e2 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -16,7 +16,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -26,6 +27,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, @@ -34,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; @@ -43,7 +45,7 @@ use rustc_trait_selection::traits::error_reporting::{ }; use rustc_trait_selection::traits::wf::object_region_bounds; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; use std::slice; @@ -143,7 +145,7 @@ enum ConvertedBindingKind<'a, 'tcx> { /// instantiated with some generic arguments providing `'a` explicitly, /// we taint those arguments with `ExplicitLateBound::Yes` so that we /// can provide an appropriate diagnostic later. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ExplicitLateBound { Yes, No, @@ -166,7 +168,7 @@ pub(crate) enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct GenericArgCountMismatch { /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). pub reported: Option, @@ -176,7 +178,7 @@ pub struct GenericArgCountMismatch { /// Decorates the result of a generic argument count mismatch /// check with whether explicit late bounds were provided. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct GenericArgCountResult { pub explicit_late_bound: ExplicitLateBound, pub correct: Result<(), GenericArgCountMismatch>, @@ -200,7 +202,7 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { } impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn ast_region_to_region( &self, lifetime: &hir::Lifetime, @@ -209,7 +211,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); - let r = match tcx.named_region(lifetime.hir_id) { + match tcx.named_region(lifetime.hir_id) { Some(rl::Region::Static) => tcx.lifetimes.re_static, Some(rl::Region::LateBound(debruijn, index, def_id)) => { @@ -221,9 +223,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::EarlyBound(index, id)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) + Some(rl::Region::EarlyBound(def_id)) => { + let name = tcx.hir().ty_param_name(def_id.expect_local()); + let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name })) } Some(rl::Region::Free(scope, id)) => { @@ -251,11 +256,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.lifetimes.re_static }) } - }; - - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - - r + } } /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, @@ -315,7 +316,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// `[Vec, u8]` and `generic_args` are the arguments for the associated /// type itself: `['a]`. The returned `SubstsRef` concatenates these two /// lists: `[Vec, u8, 'a]`. - #[tracing::instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span), ret)] fn create_substs_for_ast_path<'a>( &self, span: Span, @@ -367,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.intern_substs(&[]), arg_count); } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec, inferred_params: Vec, infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - } } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -420,7 +398,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if has_default { tcx.check_optional_stability( param.def_id, - Some(arg.id()), + Some(arg.hir_id()), arg.span(), None, AllowUnstable::No, @@ -499,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); - tcx.ty_error().into() - } else { - // This is a default type parameter. - let substs = substs.unwrap(); - if substs.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { - // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error().into(); - } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) - .into() + let substs = substs.unwrap(); + if substs.iter().any(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.references_error(), + _ => false, + }) { + // Avoid ICE #86756 when type error recovery goes awry. + return tcx.ty_error().into(); } + self.astconv + .normalize_ty( + self.span, + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), + ) + .into() } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() + self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() @@ -563,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, span, generic_args, - missing_type_params: vec![], inferred_params: vec![], infer_args, - is_object, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -578,18 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - - debug!( - "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", - generics, self_ty, substs - ); - (substs, arg_count) } @@ -655,7 +601,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs } else { - self.create_substs_for_ast_path( + let (args, _) = self.create_substs_for_ast_path( span, item_def_id, parent_substs, @@ -663,8 +609,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.args(), item_segment.infer_args, None, - ) - .0 + ); + + let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args()); + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } + + args } } @@ -764,7 +716,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, /// however. - #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))] + #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))] pub(crate) fn instantiate_poly_trait_ref( &self, trait_ref: &hir::TraitRef<'_>, @@ -856,7 +808,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::TraitRef::new(trait_def_id, substs) } - #[tracing::instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span))] fn create_substs_for_ast_trait_ref<'a>( &self, span: Span, @@ -970,7 +922,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** there is an implied binder around /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. - #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))] + #[instrument(level = "debug", skip(self, ast_bounds, bounds))] pub(crate) fn add_bounds<'hir, I: Iterator>>( &self, param_ty: Ty<'tcx>, @@ -1076,10 +1028,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** given something like `T: for<'a> Iterator`, the /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* /// the binder (e.g., `&'a u32`) and hence may reference bound regions. - #[tracing::instrument( - level = "debug", - skip(self, bounds, speculative, dup_bindings, path_span) - )] + #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))] fn add_predicates_for_ast_type_binding( &self, hir_ref_id: hir::HirId, @@ -1171,8 +1120,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ident = Ident::new(assoc_item.name, binding.item_name.span); let item_segment = hir::PathSegment { ident, - hir_id: Some(binding.hir_id), - res: None, + hir_id: binding.hir_id, + res: Res::Err, args: Some(binding.gen_args), infer_args: false, }; @@ -1241,11 +1190,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // `::Item = u32` let assoc_item_def_id = projection_ty.skip_binder().item_def_id; let def_kind = tcx.def_kind(assoc_item_def_id); - match (def_kind, term) { - (hir::def::DefKind::AssocTy, ty::Term::Ty(_)) - | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (), + match (def_kind, term.unpack()) { + (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_)) + | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (), (_, _) => { - let got = if let ty::Term::Ty(_) = term { "type" } else { "constant" }; + let got = if let Some(_) = term.ty() { "type" } else { "constant" }; let expected = def_kind.descr(assoc_item_def_id); tcx.sess .struct_span_err( @@ -1310,6 +1259,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds: &[hir::PolyTraitRef<'_>], lifetime: &hir::Lifetime, borrowed: bool, + representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1433,9 +1383,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. - let references_self = match pred.skip_binder().term { - ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()), + let references_self = match pred.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), + ty::TermKind::Const(c) => { + c.ty().walk().any(|arg| arg == dummy_self.into()) + } }; // If the projection output contains `Self`, force the user to @@ -1489,31 +1441,94 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if arg == dummy_self.into() { + let param = &generics.params[index]; + missing_type_params.push(param.name); + return tcx.ty_error().into(); + } else if arg.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + return tcx.ty_error().into(); + } + arg + }) + .collect(); + let substs = tcx.intern_substs(&substs[..]); + + let span = i.bottom().1; + let empty_generic_args = trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_kind(def_id).descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), ); + err.emit(); } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|b| { - if b.projection_ty.self_ty() != dummy_self { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b), - ); + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); + + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + false + }); + if references_self { + tcx.sess + .delay_span_bug(span, "trait object projection bounds reference `Self`"); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return tcx.ty_error().into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.intern_substs(&substs[..]); } + ty::ExistentialProjection::erase_self_ty(tcx, b) }) }); @@ -1565,7 +1580,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!("region_bound: {:?}", region_bound); - let ty = tcx.mk_dynamic(existential_predicates, region_bound); + let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation); debug!("trait_object_type: {:?}", ty); ty } @@ -1840,7 +1855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { [.., hir::PathSegment { ident, args, - res: Some(Res::Def(DefKind::Enum, _)), + res: Res::Def(DefKind::Enum, _), .. }, _] => ( // We need to include the `::` in `Type::Variant::` @@ -2106,7 +2121,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn prohibit_generics<'a>( &self, segments: impl Iterator> + Clone, - extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), + extend: impl Fn(&mut Diagnostic), ) -> bool { let args = segments.clone().flat_map(|segment| segment.args().args); @@ -2122,24 +2137,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let types_and_spans: Vec<_> = segments .clone() .flat_map(|segment| { - segment.res.and_then(|res| { - if segment.args().args.is_empty() { - None - } else { - Some(( - match res { - Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()), + if segment.args().args.is_empty() { + None + } else { + Some(( + match segment.res { + Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()), Res::Def(_, def_id) if let Some(name) = self.tcx().opt_item_name(def_id) => { - format!("{} `{name}`", res.descr()) + format!("{} `{name}`", segment.res.descr()) } Res::Err => "this type".to_string(), - _ => res.descr().to_string(), + _ => segment.res.descr().to_string(), }, segment.ident.span, )) - } - }) + } }) .collect(); let this_type = match &types_and_spans[..] { @@ -2355,7 +2368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let span = path.span; match path.res { - Res::Def(DefKind::OpaqueTy, did) => { + Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => { // Check for desugared `impl Trait`. assert!(ty::is_impl_trait_defn(tcx, did).is_none()); let item_segment = path.segments.split_last().unwrap(); @@ -2584,7 +2597,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2613,22 +2626,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(ast_ty), )) } - hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, ref lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) + let repr = match repr { + TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, + TraitObjectSyntax::DynStar => ty::DynStar, + }; + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } - hir::TyKind::OpaqueDef(item_id, lifetimes) => { + hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { let opaque_ty = tcx.hir().item(item_id); let def_id = item_id.def_id.to_def_id(); match opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - self.impl_trait_ty_to_ty(def_id, lifetimes, origin) + self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait) } ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } @@ -2667,7 +2684,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { - let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty_erased = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty = tcx.fold_regions(ty_erased, |r, _| { + if r.is_erased() { tcx.lifetimes.re_static } else { r } + }); let span = ast_ty.span; tcx.sess.emit_err(TypeofReservedKeywordUsed { span, @@ -2688,17 +2708,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::Err => tcx.ty_error(), }; - debug!(?result_ty); - self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); result_ty } + #[instrument(level = "debug", skip(self), ret)] fn impl_trait_ty_to_ty( &self, def_id: DefId, lifetimes: &[hir::GenericArg<'_>], origin: OpaqueTyOrigin, + in_trait: bool, ) -> Ty<'tcx> { debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); let tcx = self.tcx(); @@ -2742,9 +2762,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); debug!("impl_trait_ty_to_ty: substs={:?}", substs); - let ty = tcx.mk_opaque(def_id, substs); - debug!("impl_trait_ty_to_ty: {}", ty); - ty + if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) } } pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { @@ -2839,10 +2857,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if !infer_replacements.is_empty() { - diag.multipart_suggestion(&format!( + diag.multipart_suggestion( + &format!( "try replacing `_` with the type{} in the corresponding trait method signature", rustc_errors::pluralize!(infer_replacements.len()), - ), infer_replacements, Applicability::MachineApplicable); + ), + infer_replacements, + Applicability::MachineApplicable, + ); } diag.emit(); @@ -2934,8 +2956,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // though we can easily give a hint that ought to be // relevant. err.note( - "lifetimes appearing in an associated type are not considered constrained", + "lifetimes appearing in an associated or opaque type are not considered constrained", ); + err.note("consider introducing a named lifetime parameter"); } err.emit(); @@ -2984,11 +3007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_lint_blanket_trait_impl( - &self, - self_ty: &hir::Ty<'_>, - diag: &mut DiagnosticBuilder<'_, T>, - ) { + fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id); if let hir::Node::Item(hir::Item { @@ -3081,7 +3100,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { sugg, Applicability::MachineApplicable, ); - self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag); + self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); diag.emit(); }, ); diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 1b13c98e4..20332e75c 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Subst, ToPredicate, Ty}; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ @@ -12,7 +12,7 @@ use rustc_trait_selection::traits::{ }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub fn check_match( &self, expr: &'tcx hir::Expr<'tcx>, @@ -94,7 +94,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected); + let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| { + self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected) + }); let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { (Some(blk.hir_id), self.find_block_span(blk)) @@ -135,9 +137,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(&arm.body), arm_ty, Some(&mut |err| { - let Some(ret) = self.ret_type_span else { - return; - }; + let Some(ret) = self + .tcx + .hir() + .find_by_def_id(self.body_id.owner) + .and_then(|owner| owner.fn_decl()) + .map(|decl| decl.output.span()) + else { return; }; let Expectation::IsLast(stmt) = orig_expected else { return }; @@ -210,9 +216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We won't diverge unless the scrutinee or all arms diverge. self.diverges.set(scrut_diverges | all_arms_diverge); - let match_ty = coercion.complete(self); - debug!(?match_ty); - match_ty + coercion.complete(self) } /// When the previously checked expression (the scrutinee) diverges, @@ -468,53 +472,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` - // we check if the different arms would work with boxed trait objects instead and - // provide a structured suggestion in that case. + /// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` + /// we check if the different arms would work with boxed trait objects instead and + /// provide a structured suggestion in that case. pub(crate) fn opt_suggest_box_span( &self, - outer_ty: Ty<'tcx>, + first_ty: Ty<'tcx>, + second_ty: Ty<'tcx>, orig_expected: Expectation<'tcx>, ) -> Option { + // FIXME(compiler-errors): This really shouldn't need to be done during the + // "good" path of typeck, but here we are. match orig_expected { - Expectation::ExpectHasType(expected) - if self.in_tail_expr - && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types() - && self.can_coerce(outer_ty, expected) => - { - let obligations = self.fulfillment_cx.borrow().pending_obligations(); - let mut suggest_box = !obligations.is_empty(); - for o in obligations { - match o.predicate.kind().skip_binder() { - ty::PredicateKind::Trait(t) => { - let pred = - ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: t.def_id(), - substs: self.tcx.mk_substs_trait(outer_ty, &[]), - }, - constness: t.constness, - polarity: t.polarity, - })); - let obl = Obligation::new( - o.cause.clone(), - self.param_env, - pred.to_predicate(self.tcx), - ); - suggest_box &= self.predicate_must_hold_modulo_regions(&obl); - if !suggest_box { - // We've encountered some obligation that didn't hold, so the - // return expression can't just be boxed. We don't need to - // evaluate the rest of the obligations. - break; + Expectation::ExpectHasType(expected) => { + let TypeVariableOrigin { + span, + kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id), + .. + } = self.type_var_origin(expected)? else { return None; }; + + let sig = *self + .typeck_results + .borrow() + .liberated_fn_sigs() + .get(hir::HirId::make_owner(self.body_id.owner))?; + + let substs = sig.output().walk().find_map(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Opaque(def_id, substs) = *ty.kind() + && def_id == rpit_def_id + { + Some(substs) + } else { + None + } + })?; + let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs); + + if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) { + return None; + } + + for ty in [first_ty, second_ty] { + for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() { + let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs); + let pred = match pred.kind().skip_binder() { + ty::PredicateKind::Trait(mut trait_pred) => { + assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty); + trait_pred.trait_ref.substs = + self.tcx.mk_substs_trait(ty, &trait_pred.trait_ref.substs[1..]); + pred.kind().rebind(trait_pred).to_predicate(self.tcx) } + ty::PredicateKind::Projection(mut proj_pred) => { + assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty); + proj_pred.projection_ty.substs = self + .tcx + .mk_substs_trait(ty, &proj_pred.projection_ty.substs[1..]); + pred.kind().rebind(proj_pred).to_predicate(self.tcx) + } + _ => continue, + }; + if !self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::misc(span, self.body_id), + self.param_env, + pred, + )) { + return None; } - _ => {} } } - // If all the obligations hold (or there are no obligations) the tail expression - // we can suggest to return a boxed trait object instead of an opaque type. - if suggest_box { self.ret_type_span } else { None } + + Some(span) } _ => None, } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 75f5aced8..0d35c2479 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -1,5 +1,5 @@ use super::method::MethodCallee; -use super::{Expectation, FnCtxt, TupleArgumentsFlag}; +use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, Diagnostic}; @@ -24,7 +24,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::autoderef::Autoderef; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::iter; @@ -471,7 +472,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { - err.span_label(call_expr.span, "call expression requires function"); + if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty) + && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) + { + let descr = match maybe_def { + DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id), + DefIdOrName::Name(name) => name, + }; + err.span_label( + callee_expr.span, + format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called") + ); + if let DefIdOrName::DefId(def_id) = maybe_def + && let Some(def_span) = self.tcx.hir().span_if_local(def_id) + { + err.span_label(def_span, "the callable type is defined here"); + } + } else { + err.span_label(call_expr.span, "call expression requires function"); + } } if let Some(span) = self.tcx.hir().res_span(def) { diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7aaddc2bd..81a979865 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -32,30 +32,33 @@ use super::FnCtxt; use crate::hir::def_id::DefId; use crate::type_error_struct; +use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] pub struct CastCheck<'tcx> { + /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, + /// The source type for the cast expression expr_ty: Ty<'tcx>, expr_span: Span, + /// The target type. That is, the type we are casting to. cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -96,13 +99,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Err(reported); } - if self.type_is_known_to_be_sized_modulo_regions(t, span) { + if self.type_is_sized_modulo_regions(self.param_env, t, span) { return Ok(Some(PointerKind::Thin)); } Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -139,6 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Generator(..) | ty::Adt(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { let reported = self .tcx @@ -173,6 +177,7 @@ pub enum CastError { /// or "a length". If this argument is None, then the metadata is unknown, for example, /// when we're typechecking a type parameter with a ?Sized bound. IntToFatCast(Option<&'static str>), + ForeignNonExhaustiveAdt, } impl From for CastError { @@ -199,8 +204,76 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +pub enum CastCheckResult<'tcx> { + Ok, + Deferred(CastCheck<'tcx>), + Err(ErrorGuaranteed), +} + +pub fn check_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span, +) -> CastCheckResult<'tcx> { + if cast_ty.is_dyn_star() { + check_dyn_star_cast(fcx, expr, expr_ty, cast_ty) + } else { + match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { + Ok(check) => CastCheckResult::Deferred(check), + Err(e) => CastCheckResult::Err(e), + } + } +} + +fn check_dyn_star_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, +) -> CastCheckResult<'tcx> { + // Find the bounds in the dyn*. For eaxmple, if we have + // + // let x = 22_usize as dyn* (Clone + Debug + 'static) + // + // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. + let (existential_predicates, region) = match cast_ty.kind() { + ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let cause = ObligationCause::new( + expr.span, + fcx.body_id, + // FIXME(dyn-star): Use a better obligation cause code + ObligationCauseCode::MiscObligation, + ); + + // For each existential predicate (e.g., `?Self: Clone`) substitute + // the type of the expression (e.g., `usize` in our example above) + // and then require that the resulting predicate (e.g., `usize: Clone`) + // holds (it does). + for existential_predicate in existential_predicates.iter() { + let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty); + fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate)); + } + + // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + fcx.register_predicate(Obligation::new( + cause, + fcx.param_env, + fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(expr_ty, *region), + ))), + )); + + CastCheckResult::Ok +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, @@ -215,7 +288,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cases now. We do a more thorough check at the end, once // inference is more completely known. match cast_ty.kind() { - ty::Dynamic(..) | ty::Slice(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => { let reported = check.report_cast_to_unsized_type(fcx); Err(reported) } @@ -591,6 +664,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { } err.emit(); } + CastError::ForeignNonExhaustiveAdt => { + make_invalid_casting_error( + fcx.tcx.sess, + self.span, + self.expr_ty, + self.cast_ty, + fcx, + ) + .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") + .emit(); + } } } @@ -692,7 +776,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) + if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) && !self.cast_ty.has_infer_types() { self.report_cast_to_unsized_type(fcx); @@ -789,6 +873,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { _ => return Err(CastError::NonScalar), }; + if let ty::Adt(adt_def, _) = *self.expr_ty.kind() { + if adt_def.did().krate != LOCAL_CRATE { + if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { + return Err(CastError::ForeignNonExhaustiveAdt); + } + } + } + match (t_from, t_cast) { // These types have invariants! can't cast into them. (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), @@ -835,6 +927,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + + // FIXME(dyn-star): this needs more conditions... + (_, DynStar) => Ok(CastKind::DynStarCast), + + // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts? + (DynStar, _) => Err(CastError::IllegalCast), } } @@ -1063,10 +1161,3 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } } - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) - } -} diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 9c1fd9b30..d6fa74c87 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -32,7 +33,6 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_ty_utils::representability::{self, Representability}; -use std::iter; use std::ops::ControlFlow; pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { @@ -101,12 +101,11 @@ pub(super) fn check_fn<'a, 'tcx>( decl.output.span(), param_env, )); - // If we replaced declared_ret_ty with infer vars, then we must be infering + // If we replaced declared_ret_ty with infer vars, then we must be inferring // an opaque type, so set a flag so we can improve diagnostics. fcx.return_type_has_opaque = ret_ty != declared_ret_ty; fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); - fcx.ret_type_span = Some(decl.output.span()); let span = body.value.span; @@ -610,12 +609,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { - [ - PathSegment { - res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }), - .. - }, - ] => { + [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => { let impl_ty_name = impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id)); self.selftys.push((path.span, impl_ty_name)); @@ -1104,12 +1098,28 @@ fn check_impl_items_against_trait<'tcx>( missing_items.push(tcx.associated_item(trait_item_id)); } - if let Some(required_items) = &must_implement_one_of { - // true if this item is specifically implemented in this impl - let is_implemented_here = ancestors - .leaf_def(tcx, trait_item_id) - .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + // true if this item is specifically implemented in this impl + let is_implemented_here = ancestors + .leaf_def(tcx, trait_item_id) + .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + + if !is_implemented_here { + match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { + EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( + tcx, + full_impl_span, + trait_item_id, + feature, + reason, + issue, + ), + // Unmarked default bodies are considered stable (at least for now). + EvalResult::Allow | EvalResult::Unmarked => {} + } + } + + if let Some(required_items) = &must_implement_one_of { if is_implemented_here { let trait_item = tcx.associated_item(trait_item_id); if required_items.contains(&trait_item.ident(tcx)) { @@ -1448,7 +1458,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { - if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) { + if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { struct_span_err!( tcx.sess, attr.span, @@ -1494,76 +1504,107 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L } } - let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); - // This tracks the previous variant span (in the loop) incase we need it for diagnostics - let mut prev_variant_span: Span = DUMMY_SP; - for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) { - // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variant(VariantIdx::new(i)).def_id; - let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); - let variant_i = tcx.hir().expect_variant(variant_i_hir_id); - let i_span = match variant_i.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => tcx.def_span(variant_did), - }; - let span = match v.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => v.span, - }; - let display_discr = format_discriminant_overflow(tcx, v, discr); - let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]); - let no_disr = v.disr_expr.is_none(); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0081, - "discriminant value `{}` assigned more than once", - discr, - ); - - err.span_label(i_span, format!("first assignment of {display_discr_i}")); - err.span_label(span, format!("second assignment of {display_discr}")); - - if no_disr { - err.span_label( - prev_variant_span, - format!( - "assigned discriminant for `{}` was incremented from this discriminant", - v.ident - ), - ); - } - err.emit(); - } - - disr_vals.push(discr); - prev_variant_span = v.span; - } + detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp); check_representable(tcx, sp, def_id); check_transparent(tcx, sp, def); } -/// In the case that a discriminant is both a duplicate and an overflowing literal, -/// we insert both the assigned discriminant and the literal it overflowed from into the formatted -/// output. Otherwise we format the discriminant normally. -fn format_discriminant_overflow<'tcx>( +/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal +fn detect_discriminant_duplicate<'tcx>( tcx: TyCtxt<'tcx>, - variant: &hir::Variant<'_>, - dis: Discr<'tcx>, -) -> String { - if let Some(expr) = &variant.disr_expr { - let body = &tcx.hir().body(expr.body).value; - if let hir::ExprKind::Lit(lit) = &body.kind - && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node - && dis.val != *lit_value - { - return format!("`{dis}` (overflowed from `{lit_value}`)"); + mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, + vs: &'tcx [hir::Variant<'tcx>], + self_span: Span, +) { + // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. + // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` + let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| { + let var = &vs[idx]; // HIR for the duplicate discriminant + let (span, display_discr) = match var.disr_expr { + Some(ref expr) => { + // In the case the discriminant is both a duplicate and overflowed, let the user know + if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind + && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node + && *lit_value != dis.val + { + (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)")) + // Otherwise, format the value as-is + } else { + (tcx.hir().span(expr.hir_id), format!("`{dis}`")) + } + } + None => { + // At this point we know this discriminant is a duplicate, and was not explicitly + // assigned by the user. Here we iterate backwards to fetch the HIR for the last + // explicitly assigned discriminant, and letting the user know that this was the + // increment startpoint, and how many steps from there leading to the duplicate + if let Some((n, hir::Variant { span, ident, .. })) = + vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) + { + let ve_ident = var.ident; + let n = n + 1; + let sp = if n > 1 { "variants" } else { "variant" }; + + err.span_label( + *span, + format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"), + ); + } + + (vs[idx].span, format!("`{dis}`")) + } + }; + + err.span_label(span, format!("{display_discr} assigned here")); + }; + + // Here we loop through the discriminants, comparing each discriminant to another. + // When a duplicate is detected, we instantiate an error and point to both + // initial and duplicate value. The duplicate discriminant is then discarded by swapping + // it with the last element and decrementing the `vec.len` (which is why we have to evaluate + // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional + // style as we are mutating `discrs` on the fly). + let mut i = 0; + while i < discrs.len() { + let hir_var_i_idx = discrs[i].0.index(); + let mut error: Option> = None; + + let mut o = i + 1; + while o < discrs.len() { + let hir_var_o_idx = discrs[o].0.index(); + + if discrs[i].1.val == discrs[o].1.val { + let err = error.get_or_insert_with(|| { + let mut ret = struct_span_err!( + tcx.sess, + self_span, + E0081, + "discriminant value `{}` assigned more than once", + discrs[i].1, + ); + + report(discrs[i].1, hir_var_i_idx, &mut ret); + + ret + }); + + report(discrs[o].1, hir_var_o_idx, err); + + // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty + discrs[o] = *discrs.last().unwrap(); + discrs.pop(); + } else { + o += 1; + } } - } - format!("`{dis}`") + if let Some(mut e) = error { + e.emit(); + } + + i += 1; + } } pub(super) fn check_type_params_are_used<'tcx>( diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index fee872155..9b943b160 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -4,6 +4,7 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use crate::astconv::AstConv; use crate::rustc_middle::ty::subst::Subst; +use hir::def::DefKind; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -29,7 +30,12 @@ struct ExpectedSig<'tcx> { } struct ClosureSignatures<'tcx> { + /// The signature users of the closure see. bound_sig: ty::PolyFnSig<'tcx>, + /// The signature within the function body. + /// This mostly differs in the sense that lifetimes are now early bound and any + /// opaque types from the signature expectation are overriden in case there are + /// explicit hidden types written by the user in the closure signature. liberated_sig: ty::FnSig<'tcx>, } @@ -58,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_closure(expr, expected_kind, decl, body, gen, expected_sig) } - #[instrument(skip(self, expr, body, decl), level = "debug")] + #[instrument(skip(self, expr, body, decl), level = "debug", ret)] fn check_closure( &self, expr: &hir::Expr<'_>, @@ -158,11 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); - - debug!(?expr.hir_id, ?closure_type); - - closure_type + self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs) } /// Given the expected type, figures out what it can about this closure we @@ -262,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// The `cause_span` should be the span that caused us to /// have this expected signature, or `None` if we can't readily /// know that. - #[instrument(level = "debug", skip(self, cause_span))] + #[instrument(level = "debug", skip(self, cause_span), ret)] fn deduce_sig_from_projection( &self, cause_span: Option, @@ -317,7 +319,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Unsafety::Normal, Abi::Rust, )); - debug!(?sig); Some(ExpectedSig { cause_span, sig }) } @@ -448,18 +449,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Along the way, it also writes out entries for types that the user // wrote into our typeck results, which are then later used by the privacy // check. - match self.check_supplied_sig_against_expectation( + match self.merge_supplied_sig_with_expectation( hir_id, expr_def_id, decl, body, - &closure_sigs, + closure_sigs, ) { Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok), - Err(_) => return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body), + Err(_) => self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body), } - - closure_sigs } fn sig_of_closure_with_mismatched_number_of_arguments( @@ -501,21 +500,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Enforce the user's types against the expectation. See /// `sig_of_closure_with_expectation` for details on the overall /// strategy. - fn check_supplied_sig_against_expectation( + #[instrument(level = "debug", skip(self, hir_id, expr_def_id, decl, body, expected_sigs))] + fn merge_supplied_sig_with_expectation( &self, hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, - expected_sigs: &ClosureSignatures<'tcx>, - ) -> InferResult<'tcx, ()> { + mut expected_sigs: ClosureSignatures<'tcx>, + ) -> InferResult<'tcx, ClosureSignatures<'tcx>> { // Get the signature S that the user gave. // // (See comment on `sig_of_closure_with_expectation` for the // meaning of these letters.) let supplied_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); - debug!("check_supplied_sig_against_expectation: supplied_sig={:?}", supplied_sig); + debug!(?supplied_sig); // FIXME(#45727): As discussed in [this comment][c1], naively // forcing equality here actually results in suboptimal error @@ -533,23 +533,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 self.commit_if_ok(|_| { let mut all_obligations = vec![]; + let inputs: Vec<_> = iter::zip( + decl.inputs, + supplied_sig.inputs().skip_binder(), // binder moved to (*) below + ) + .map(|(hir_ty, &supplied_ty)| { + // Instantiate (this part of..) S to S', i.e., with fresh variables. + self.replace_bound_vars_with_fresh_vars( + hir_ty.span, + LateBoundRegionConversionTime::FnCall, + // (*) binder moved to here + supplied_sig.inputs().rebind(supplied_ty), + ) + }) + .collect(); // The liberated version of this signature should be a subtype // of the liberated form of the expectation. for ((hir_ty, &supplied_ty), expected_ty) in iter::zip( - iter::zip( - decl.inputs, - supplied_sig.inputs().skip_binder(), // binder moved to (*) below - ), + iter::zip(decl.inputs, &inputs), expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. ) { - // Instantiate (this part of..) S to S', i.e., with fresh variables. - let supplied_ty = self.replace_bound_vars_with_fresh_vars( - hir_ty.span, - LateBoundRegionConversionTime::FnCall, - supplied_sig.inputs().rebind(supplied_ty), - ); // recreated from (*) above - // Check that E' = S'. let cause = self.misc(hir_ty.span); let InferOk { value: (), obligations } = @@ -568,7 +572,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; all_obligations.extend(obligations); - Ok(InferOk { value: (), obligations: all_obligations }) + let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty)); + + expected_sigs.liberated_sig = self.tcx.mk_fn_sig( + inputs, + supplied_output_ty, + expected_sigs.liberated_sig.c_variadic, + hir::Unsafety::Normal, + Abi::RustCall, + ); + + Ok(InferOk { value: expected_sigs, obligations: all_obligations }) }) } @@ -576,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. /// /// Also, record this closure signature for later. - #[instrument(skip(self, decl, body), level = "debug")] + #[instrument(skip(self, decl, body), level = "debug", ret)] fn supplied_sig_of_closure( &self, hir_id: hir::HirId, @@ -629,8 +643,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_vars, ); - debug!(?result); - let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); @@ -643,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// user specified. The "desugared" return type is an `impl /// Future`, so we do this by searching through the /// obligations to extract the `T`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn deduce_future_output_from_obligations( &self, expr_def_id: DefId, @@ -687,9 +699,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|e| e.map_bound(|e| *e).transpose_tuple2()) .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?, ty::Error(_) => return None, + ty::Projection(proj) + if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => + { + self.tcx + .bound_explicit_item_bounds(proj.item_def_id) + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))? + } _ => span_bug!( self.tcx.def_span(expr_def_id), - "async fn generator return type not an inference variable" + "async fn generator return type not an inference variable: {ret_ty}" ), }; @@ -704,7 +725,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.register_predicates(obligations); - debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); Some(output_ty) } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 2ed5f569b..def592c46 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -38,10 +38,12 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::Expr; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt}; @@ -87,6 +89,19 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; +struct CollectRetsVisitor<'tcx> { + ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, +} + +impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if let hir::ExprKind::Ret(_) = expr.kind { + self.ret_exprs.push(expr); + } + intravisit::walk_expr(self, expr); + } +} + /// Coercing a mutable reference to an immutable works, while /// coercing `&T` to `&mut T` should be forbidden. fn coerce_mutbls<'tcx>( @@ -1464,23 +1479,29 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } Err(coercion_error) => { + // Mark that we've failed to coerce the types here to suppress + // any superfluous errors we might encounter while trying to + // emit or provide suggestions on how to fix the initial error. + fcx.set_tainted_by_errors(); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like // `break`, we want to call the `()` "expected" // since it is implied by the syntax. // (Note: not all force-units work this way.)" - (expression_ty, self.final_ty.unwrap_or(self.expected_ty)) + (expression_ty, self.merged_ty()) } else { // Otherwise, the "expected" type for error // reporting is the current unification type, // which is basically the LUB of the expressions // we've seen so far (combined with the expected // type) - (self.final_ty.unwrap_or(self.expected_ty), expression_ty) + (self.merged_ty(), expression_ty) }; + let (expected, found) = fcx.resolve_vars_if_possible((expected, found)); let mut err; let mut unsized_return = false; + let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; match *cause.code() { ObligationCauseCode::ReturnNoExpression => { err = struct_span_err!( @@ -1506,6 +1527,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if !fcx.tcx.features().unsized_locals { unsized_return = self.is_return_ty_unsized(fcx, blk_id); } + if let Some(expression) = expression + && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { + intravisit::walk_block(& mut visitor, loop_blk); + } } ObligationCauseCode::ReturnValue(id) => { err = self.report_return_mismatched_types( @@ -1551,12 +1576,47 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } + if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { + self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); + } err.emit_unless(unsized_return); self.final_ty = Some(fcx.tcx.ty_error()); } } } + fn note_unreachable_loop_return( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, + ) { + let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; + let mut span: MultiSpan = vec![loop_span].into(); + span.push_span_label(loop_span, "this might have zero elements to iterate on"); + const MAXITER: usize = 3; + let iter = ret_exprs.iter().take(MAXITER); + for ret_expr in iter { + span.push_span_label( + ret_expr.span, + "if the loop doesn't execute, this value would never get returned", + ); + } + err.span_note( + span, + "the function expects a value to always be returned, but loops might run zero times", + ); + if MAXITER < ret_exprs.len() { + err.note(&format!( + "if the loop doesn't execute, {} other values would never get returned", + ret_exprs.len() - MAXITER + )); + } + err.help( + "return a value for the case when the loop has zero elements to iterate on, or \ + consider changing the return type to account for that possibility", + ); + } fn report_return_mismatched_types<'a>( &self, @@ -1648,9 +1708,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } - if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { + let ret_coercion_span = fcx.ret_coercion_span.get(); + + if let Some(sp) = ret_coercion_span + // If the closure has an explicit return type annotation, or if + // the closure's return type has been inferred from outside + // requirements (such as an Fn* trait bound), then a type error + // may occur at the first return expression we see in the closure + // (if it conflicts with the declared return type). Skip adding a + // note in this case, since it would be incorrect. + && !fcx.return_type_pre_known + { + err.span_note( + sp, + &format!( + "return type inferred to be `{}` here", + expected + ), + ); + } + + if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) { self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output); } + err } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 666498403..59d591acd 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,23 +1,26 @@ use super::potentially_plural_count; -use crate::check::regionck::OutlivesEnvironmentExt; -use crate::check::wfcheck; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use rustc_data_structures::fx::FxHashSet; +use hir::def_id::DefId; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::util::ExplicitSelf; -use rustc_middle::ty::{self, DefIdTree}; +use rustc_middle::ty::{ + self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, +}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; @@ -71,11 +74,78 @@ pub(crate) fn compare_impl_method<'tcx>( } } +/// This function is best explained by example. Consider a trait: +/// +/// trait Trait<'t, T> { +/// // `trait_m` +/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; +/// } +/// +/// And an impl: +/// +/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { +/// // `impl_m` +/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo; +/// } +/// +/// We wish to decide if those two method types are compatible. +/// For this we have to show that, assuming the bounds of the impl hold, the +/// bounds of `trait_m` imply the bounds of `impl_m`. +/// +/// We start out with `trait_to_impl_substs`, that maps the trait +/// type parameters to impl type parameters. This is taken from the +/// impl trait reference: +/// +/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} +/// +/// We create a mapping `dummy_substs` that maps from the impl type +/// parameters to fresh types and regions. For type parameters, +/// this is the identity transform, but we could as well use any +/// placeholder types. For regions, we convert from bound to free +/// regions (Note: but only early-bound regions, i.e., those +/// declared on the impl or used in type parameter bounds). +/// +/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } +/// +/// Now we can apply `placeholder_substs` to the type of the impl method +/// to yield a new function type in terms of our fresh, placeholder +/// types: +/// +/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// +/// We now want to extract and substitute the type of the *trait* +/// method and compare it. To do so, we must create a compound +/// substitution by combining `trait_to_impl_substs` and +/// `impl_to_placeholder_substs`, and also adding a mapping for the method +/// type parameters. We extend the mapping to also include +/// the method parameters. +/// +/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } +/// +/// Applying this to the trait method type yields: +/// +/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// +/// This type is also the same but the name of the bound region (`'a` +/// vs `'b`). However, the normal subtyping rules on fn types handle +/// this kind of equivalency just fine. +/// +/// We now use these substitutions to ensure that all declared bounds are +/// satisfied by the implementation's method. +/// +/// We do this by creating a parameter environment which contains a +/// substitution corresponding to `impl_to_placeholder_substs`. We then build +/// `trait_to_placeholder_substs` and use it to convert the predicates contained +/// in the `trait_m` generics to the placeholder form. +/// +/// Finally we register each of these predicates as an obligation and check that +/// they hold. +#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))] fn compare_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, - impl_m: &ty::AssocItem, + impl_m: &AssocItem, impl_m_span: Span, - trait_m: &ty::AssocItem, + trait_m: &AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let trait_to_impl_substs = impl_trait_ref.substs; @@ -97,69 +167,6 @@ fn compare_predicate_entailment<'tcx>( }, ); - // This code is best explained by example. Consider a trait: - // - // trait Trait<'t, T> { - // fn method<'a, M>(t: &'t T, m: &'a M) -> Self; - // } - // - // And an impl: - // - // impl<'i, 'j, U> Trait<'j, &'i U> for Foo { - // fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo; - // } - // - // We wish to decide if those two method types are compatible. - // - // We start out with trait_to_impl_substs, that maps the trait - // type parameters to impl type parameters. This is taken from the - // impl trait reference: - // - // trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} - // - // We create a mapping `dummy_substs` that maps from the impl type - // parameters to fresh types and regions. For type parameters, - // this is the identity transform, but we could as well use any - // placeholder types. For regions, we convert from bound to free - // regions (Note: but only early-bound regions, i.e., those - // declared on the impl or used in type parameter bounds). - // - // impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } - // - // Now we can apply placeholder_substs to the type of the impl method - // to yield a new function type in terms of our fresh, placeholder - // types: - // - // <'b> fn(t: &'i0 U0, m: &'b) -> Foo - // - // We now want to extract and substitute the type of the *trait* - // method and compare it. To do so, we must create a compound - // substitution by combining trait_to_impl_substs and - // impl_to_placeholder_substs, and also adding a mapping for the method - // type parameters. We extend the mapping to also include - // the method parameters. - // - // trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } - // - // Applying this to the trait method type yields: - // - // <'a> fn(t: &'i0 U0, m: &'a) -> Foo - // - // This type is also the same but the name of the bound region ('a - // vs 'b). However, the normal subtyping rules on fn types handle - // this kind of equivalency just fine. - // - // We now use these substitutions to ensure that all declared bounds are - // satisfied by the implementation's method. - // - // We do this by creating a parameter environment which contains a - // substitution corresponding to impl_to_placeholder_substs. We then build - // trait_to_placeholder_substs and use it to convert the predicates contained - // in the trait_m.generics to the placeholder form. - // - // Finally we register each of these predicates as an obligation in - // a fresh FulfillmentCtxt, and invoke select_all_or_error. - // Create mapping from impl to placeholder. let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); @@ -264,8 +271,14 @@ fn compare_predicate_entailment<'tcx>( let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); + + // Next, add all inputs and output as well-formed tys. Importantly, + // we have to do this before normalization, since the normalized ty may + // not contain the input parameters. See issue #87748. + wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); - // Add the resulting inputs and output as well-formed. + // We also have to add the normalized trait signature + // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); @@ -277,16 +290,30 @@ fn compare_predicate_entailment<'tcx>( // type would be more appropriate. In other places we have a `Vec` // corresponding to their `Vec`, but we don't have that here. // Fixing this would improve the output of test `issue-83765.rs`. - let sub_result = infcx + let mut result = infcx .at(&cause, param_env) .sup(trait_fty, impl_fty) .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); - if let Err(terr) = sub_result { + // HACK(RPITIT): #101614. When we are trying to infer the hidden types for + // RPITITs, we need to equate the output tys instead of just subtyping. If + // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes + // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets + // fixed up to `ReEmpty`, and which is certainly not what we want. + if trait_fty.has_infer_types() { + result = result.and_then(|()| { + infcx + .at(&cause, param_env) + .eq(trait_sig.output(), impl_sig.output()) + .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)) + }); + } + + if let Err(terr) = result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); let (impl_err_span, trait_err_span) = - extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m); + extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m); cause.span = impl_err_span; @@ -376,7 +403,7 @@ fn compare_predicate_entailment<'tcx>( expected: trait_fty.into(), found: impl_fty.into(), })), - &terr, + terr, false, false, ); @@ -394,8 +421,11 @@ fn compare_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id); + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(infcx), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + ); infcx.check_region_obligations_and_report_errors( impl_m.def_id.expect_local(), &outlives_environment, @@ -405,6 +435,227 @@ fn compare_predicate_entailment<'tcx>( }) } +pub fn collect_trait_impl_trait_tys<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> { + let impl_m = tcx.opt_associated_item(def_id).unwrap(); + let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); + let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap(); + let param_env = tcx.param_env(def_id); + + let trait_to_impl_substs = impl_trait_ref.substs; + + let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); + let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); + let cause = ObligationCause::new( + return_span, + impl_m_hir_id, + ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_m.def_id.expect_local(), + trait_item_def_id: trait_m.def_id, + kind: impl_m.kind, + }, + ); + + // Create mapping from impl to placeholder. + let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); + + // Create mapping from trait to placeholder. + let trait_to_placeholder_substs = + impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs); + + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); + + let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); + let impl_return_ty = ocx.normalize( + norm_cause.clone(), + param_env, + infcx + .replace_bound_vars_with_fresh_vars( + return_span, + infer::HigherRankedType, + tcx.fn_sig(impl_m.def_id), + ) + .output(), + ); + + let mut collector = + ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); + let unnormalized_trait_return_ty = tcx + .liberate_late_bound_regions( + impl_m.def_id, + tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), + ) + .output() + .fold_with(&mut collector); + let trait_return_ty = + ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty); + + let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]); + + match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) { + Ok(infer::InferOk { value: (), obligations }) => { + ocx.register_obligations(obligations); + } + Err(terr) => { + let mut diag = struct_span_err!( + tcx.sess, + cause.span(), + E0053, + "method `{}` has an incompatible return type for trait", + trait_m.name + ); + let hir = tcx.hir(); + infcx.note_type_err( + &mut diag, + &cause, + hir.get_if_local(impl_m.def_id) + .and_then(|node| node.fn_decl()) + .map(|decl| (decl.output.span(), "return type in trait".to_owned())), + Some(infer::ValuePairs::Terms(ExpectedFound { + expected: trait_return_ty.into(), + found: impl_return_ty.into(), + })), + terr, + false, + false, + ); + return Err(diag.emit()); + } + } + + // Check that all obligations are satisfied by the implementation's + // RPITs. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.report_fulfillment_errors(&errors, None, false); + return Err(reported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(infcx), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + ); + infcx.check_region_obligations_and_report_errors( + impl_m.def_id.expect_local(), + &outlives_environment, + ); + + let mut collected_tys = FxHashMap::default(); + for (def_id, (ty, substs)) in collector.types { + match infcx.fully_resolve(ty) { + Ok(ty) => { + // `ty` contains free regions that we created earlier while liberating the + // trait fn signature. However, projection normalization expects `ty` to + // contains `def_id`'s early-bound regions. + let id_substs = InternalSubsts::identity_for_item(tcx, def_id); + debug!(?id_substs, ?substs); + let map: FxHashMap, ty::GenericArg<'tcx>> = substs + .iter() + .enumerate() + .map(|(index, arg)| (arg, id_substs[index])) + .collect(); + debug!(?map); + + let ty = tcx.fold_regions(ty, |region, _| { + if let ty::ReFree(_) = region.kind() { + map[®ion.into()].expect_region() + } else { + region + } + }); + debug!(%ty); + collected_tys.insert(def_id, ty); + } + Err(err) => { + tcx.sess.delay_span_bug( + return_span, + format!("could not fully resolve: {ty} => {err:?}"), + ); + collected_tys.insert(def_id, tcx.ty_error()); + } + } + } + + Ok(&*tcx.arena.alloc(collected_tys)) + }) +} + +struct ImplTraitInTraitCollector<'a, 'tcx> { + ocx: &'a ObligationCtxt<'a, 'tcx>, + types: FxHashMap, ty::SubstsRef<'tcx>)>, + span: Span, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, +} + +impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { + fn new( + ocx: &'a ObligationCtxt<'a, 'tcx>, + span: Span, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ) -> Self { + ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id } + } +} + +impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.ocx.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Projection(proj) = ty.kind() + && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder + { + if let Some((ty, _)) = self.types.get(&proj.item_def_id) { + return *ty; + } + //FIXME(RPITIT): Deny nested RPITIT in substs too + if proj.substs.has_escaping_bound_vars() { + bug!("FIXME(RPITIT): error here"); + } + // Replace with infer var + let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin { + span: self.span, + kind: TypeVariableOriginKind::MiscVariable, + }); + self.types.insert(proj.item_def_id, (infer_ty, proj.substs)); + // Recurse into bounds + for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() { + let pred_span = pred.0.1; + + let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs); + let pred = pred.fold_with(self); + let pred = self.ocx.normalize( + ObligationCause::misc(self.span, self.body_id), + self.param_env, + pred, + ); + + self.ocx.register_obligation(traits::Obligation::new( + ObligationCause::new( + self.span, + self.body_id, + ObligationCauseCode::BindingObligation(proj.item_def_id, pred_span), + ), + self.param_env, + pred, + )); + } + infer_ty + } else { + ty.super_fold_with(self) + } + } +} + fn check_region_bounds_on_impl_item<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, @@ -463,7 +714,7 @@ fn check_region_bounds_on_impl_item<'tcx>( #[instrument(level = "debug", skip(infcx))] fn extract_spans_for_error_reporting<'a, 'tcx>( infcx: &infer::InferCtxt<'a, 'tcx>, - terr: &TypeError<'_>, + terr: TypeError<'_>, cause: &ObligationCause<'tcx>, impl_m: &ty::AssocItem, trait_m: &ty::AssocItem, @@ -483,7 +734,7 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m), }); - match *terr { + match terr { TypeError::ArgumentMutability(i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } @@ -848,8 +1099,7 @@ fn compare_synthetic_generics<'tcx>( { if impl_synthetic != trait_synthetic { let impl_def_id = impl_def_id.expect_local(); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id); - let impl_span = tcx.hir().span(impl_hir_id); + let impl_span = tcx.def_span(impl_def_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!( tcx.sess, @@ -868,17 +1118,16 @@ fn compare_synthetic_generics<'tcx>( // try taking the name from the trait impl // FIXME: this is obviously suboptimal since the name can already be used // as another generic argument - let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?; + let new_name = tcx.opt_item_name(trait_def_id)?; let trait_m = trait_m.def_id.as_local()?; - let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }); + let trait_m = tcx.hir().expect_trait_item(trait_m); let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list - let new_generics_span = - tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi(); + let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi(); // in case there are generics, just replace them let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span); @@ -890,7 +1139,7 @@ fn compare_synthetic_generics<'tcx>( "try changing the `impl Trait` argument to a generic parameter", vec![ // replace `impl Trait` with `T` - (impl_span, new_name), + (impl_span, new_name.to_string()), // replace impl method generics with trait method generics // This isn't quite right, as users might have changed the names // of the generics, but it works for the common case @@ -907,7 +1156,7 @@ fn compare_synthetic_generics<'tcx>( err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); (|| { let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); let input_tys = match impl_m.kind { hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), @@ -1138,7 +1387,7 @@ pub(crate) fn compare_const_impl<'tcx>( expected: trait_ty.into(), found: impl_ty.into(), })), - &terr, + terr, false, false, ); @@ -1300,7 +1549,7 @@ fn compare_type_predicate_entailment<'tcx>( /// For default associated types the normalization is not possible (the value /// from the impl could be overridden). We also can't normalize generic /// associated types (yet) because they contain bound parameters. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] pub fn check_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_ty: &ty::AssocItem, @@ -1440,14 +1689,17 @@ pub fn check_type_bounds<'tcx>( }; debug!(?normalize_param_env); + let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); tcx.infer_ctxt().enter(move |infcx| { let ocx = ObligationCtxt::new(&infcx); + let assumed_wf_types = + ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local()); + let mut selcx = traits::SelectionContext::new(&infcx); - let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); let normalize_cause = ObligationCause::new( impl_ty_span, impl_ty_hir_id, @@ -1458,7 +1710,7 @@ pub fn check_type_bounds<'tcx>( ); let mk_cause = |span: Span| { let code = if span.is_dummy() { - traits::MiscObligation + traits::ItemObligation(trait_ty.def_id) } else { traits::BindingObligation(trait_ty.def_id, span) }; @@ -1503,17 +1755,10 @@ pub fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let implied_bounds = match impl_ty.container { - ty::TraitContainer => FxHashSet::default(), - ty::ImplContainer => wfcheck::impl_implied_bounds( - tcx, - param_env, - container_id.expect_local(), - impl_ty_span, - ), - }; - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id); + let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); + infcx.check_region_obligations_and_report_errors( impl_ty.def_id.expect_local(), &outlives_environment, diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 4de48dc5b..e1d55ff82 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -42,10 +42,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); self.suggest_missing_parentheses(err, expr); self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected); + self.suggest_copied_or_cloned(err, expr, expr_ty, expected); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); - self.report_closure_inferred_return_type(err, expected); } // Requires that the two types unify, and prints an error message if @@ -131,7 +131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` /// will be permitted if the diverges flag is currently "always". - #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] + #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] pub fn demand_coerce_diag( &self, expr: &hir::Expr<'tcx>, @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_is_local = sole_field.did.is_local(); let field_is_accessible = - sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx) + sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx) // Skip suggestions for unstable public fields (for example `Pin::pointer`) && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); @@ -590,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_params_len = closure_fn_decl.inputs.len(); let ( Some(Node::Expr(hir::Expr { - kind: hir::ExprKind::MethodCall(method_path, method_expr, _), + kind: hir::ExprKind::MethodCall(method_path, receiver, ..), .. })), 1, @@ -598,14 +598,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]); - let self_ty = format!("{:?}", self_ty); + let self_ty = self.typeck_results.borrow().expr_ty(receiver); let name = method_path.ident.name; - let is_as_ref_able = (self_ty.starts_with("&std::option::Option") - || self_ty.starts_with("&std::result::Result") - || self_ty.starts_with("std::option::Option") - || self_ty.starts_with("std::result::Result")) - && (name == sym::map || name == sym::and_then); + let is_as_ref_able = match self_ty.peel_refs().kind() { + ty::Adt(def, _) => { + (self.tcx.is_diagnostic_item(sym::Option, def.did()) + || self.tcx.is_diagnostic_item(sym::Result, def.did())) + && (name == sym::map || name == sym::and_then) + } + _ => false, + }; match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) { (true, Ok(src)) => { let suggestion = format!("as_ref().{}", src); @@ -637,11 +639,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }?; match hir.find(hir.get_parent_node(expr.hir_id))? { - Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => { - for field in *fields { - if field.ident.name == local.name && field.is_shorthand { - return Some(local.name); - } + Node::ExprField(field) => { + if field.ident.name == local.name && field.is_shorthand { + return Some(local.name); } } _ => {} @@ -767,22 +767,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if self.can_coerce(ref_ty, expected) { let mut sugg_sp = sp; - if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind { + if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind { let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); - if let ([arg], Some(true), sym::clone) = ( - &args[..], - self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( + if args.is_empty() + && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( |did| { let ai = self.tcx.associated_item(did); ai.trait_container(self.tcx) == Some(clone_trait) }, - ), - segment.ident.name, - ) { + ) == Some(true) + && segment.ident.name == sym::clone + { // If this expression had a clone call when suggesting borrowing // we want to suggest removing it because it'd now be unnecessary. - sugg_sp = arg.span; + sugg_sp = receiver.span; } } if let Ok(src) = sm.span_to_snippet(sugg_sp) { @@ -793,7 +792,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ if is_range_literal(expr) => true, _ => false, }; - let sugg_expr = if needs_parens { format!("({src})") } else { src }; if let Some(sugg) = self.can_use_as_ref(expr) { return Some(( @@ -821,6 +819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + let sugg_expr = if needs_parens { format!("({src})") } else { src }; return Some(match mutability { hir::Mutability::Mut => ( sp, @@ -1072,21 +1071,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg = vec![]; - if let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Struct(_, fields, _), .. - })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) + if let Some(hir::Node::ExprField(field)) = + self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { // `expr` is a literal field for a struct, only suggest if appropriate - match (*fields) - .iter() - .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand) - { + if field.is_shorthand { // This is a field literal - Some(field) => { - sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); - } + sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident))); + } else { // Likely a field was meant, but this field wasn't found. Do not suggest anything. - None => return false, + return false; } }; @@ -1418,25 +1412,4 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, } } - - // Report the type inferred by the return statement. - fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) { - if let Some(sp) = self.ret_coercion_span.get() - // If the closure has an explicit return type annotation, or if - // the closure's return type has been inferred from outside - // requirements (such as an Fn* trait bound), then a type error - // may occur at the first return expression we see in the closure - // (if it conflicts with the declared return type). Skip adding a - // note in this case, since it would be incorrect. - && !self.return_type_pre_known - { - err.span_note( - sp, - &format!( - "return type inferred to be `{}` here", - self.resolve_vars_if_possible(expected) - ), - ); - } - } } diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 321064ec0..ab143c059 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -144,6 +144,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; + debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates); + let self_param_env = tcx.param_env(self_type_did); // An earlier version of this code attempted to do this checking diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 6e97b0bf2..93b008500 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -3,32 +3,28 @@ //! See `mod.rs` for more context on type checking in general. use crate::astconv::AstConv as _; -use crate::check::cast; +use crate::check::cast::{self, CastCheckResult}; use crate::check::coercion::CoerceMany; use crate::check::fatally_break_rust; use crate::check::method::SelfSource; -use crate::check::report_unexpected_variant_res; -use crate::check::BreakableCtxt; -use crate::check::Diverges; -use crate::check::DynamicCoerceMany; use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::check::FnCtxt; -use crate::check::Needs; -use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::check::{ + report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs, + TupleArgumentsFlag::DontTupleArguments, +}; use crate::errors::{ FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, YieldExprOutsideOfGenerator, }; use crate::type_error_struct; -use super::suggest_call_constructor; use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - EmissionGuarantee, ErrorGuaranteed, + ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -44,13 +40,12 @@ use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::TypeError::FieldMisMatch; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable}; +use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable}; use rustc_session::parse::feature_err; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -326,8 +321,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected), - ExprKind::MethodCall(segment, args, _) => { - self.check_method_call(expr, segment, args, expected) + ExprKind::MethodCall(segment, receiver, args, _) => { + self.check_method_call(expr, segment, receiver, args, expected) } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { @@ -880,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs: &'tcx hir::Expr<'tcx>, err_code: &'static str, op_span: Span, - adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), + adjust_err: impl FnOnce(&mut Diagnostic), ) { if lhs.is_syntactic_place_expr() { return; @@ -1002,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); + let opt_suggest_box_span = self.opt_suggest_box_span(then_ty, else_ty, orig_expected); let if_cause = self.if_cause( sp, cond_expr.span, @@ -1090,8 +1085,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, - rhs_ty: Ty<'tcx>| { + let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { // Can only assign if the type is sized, so if `DerefMut` yields a type that is // unsized, do not suggest dereferencing it. @@ -1198,13 +1192,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, segment: &hir::PathSegment<'_>, + rcvr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let rcvr = &args[0]; let rcvr_t = self.check_expr(&rcvr); // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); + let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t); let span = segment.ident.span; let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { @@ -1221,9 +1215,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_t, segment.ident, - SelfSource::MethodCall(&args[0]), + SelfSource::MethodCall(rcvr), error, - Some(args), + Some((rcvr, args)), ) { err.emit(); } @@ -1233,14 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types( - span, - expr, - method, - &args[1..], - DontTupleArguments, - expected, - ) + self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected) } fn check_expr_cast( @@ -1262,8 +1249,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { - Ok(cast_check) => { + match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) { + CastCheckResult::Ok => t_cast, + CastCheckResult::Deferred(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", t_cast, t_expr, cast_check, @@ -1271,7 +1259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(_) => self.tcx.ty_error(), + CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(), } } } @@ -1309,7 +1297,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: expr.span, }) }; - self.tcx.mk_array(element_ty, args.len() as u64) + let array_len = args.len() as u64; + self.suggest_array_len(expr, array_len); + self.tcx.mk_array(element_ty, array_len) + } + + fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) { + let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| { + !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. })) + }); + let Some((_, + hir::Node::Local(hir::Local { ty: Some(ty), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) + ) = parent_node else { + return + }; + if let hir::TyKind::Array(_, length) = ty.peel_refs().kind + && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let Some(span) = self.tcx.hir().opt_span(hir_id) + { + match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { + Some(mut err) => { + err.span_suggestion( + span, + "consider specifying the array length", + array_len, + Applicability::MaybeIncorrect, + ); + err.emit(); + } + None => () + } + } } fn check_expr_const_block( @@ -1335,10 +1354,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element: &'tcx hir::Expr<'tcx>, count: &'tcx hir::ArrayLen, expected: Expectation<'tcx>, - _expr: &'tcx hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let count = self.array_length_to_const(count); + if let Some(count) = count.try_eval_usize(tcx, self.param_env) { + self.suggest_array_len(expr, count); + } let uty = match expected { ExpectHasType(uty) => match *uty.kind() { @@ -1518,7 +1540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut error_happened = false; // Type-check each field. - for field in ast_fields { + for (idx, field) in ast_fields.iter().enumerate() { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { seen_fields.insert(ident, field.span); @@ -1556,7 +1578,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. - self.check_expr_coercable_to_type(&field.expr, field_type, None); + let ty = self.check_expr_with_hint(&field.expr, field_type); + let (_, diag) = + self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No); + + if let Some(mut diag) = diag { + if idx == ast_fields.len() - 1 && remaining_fields.is_empty() { + self.suggest_fru_from_range(field, variant, substs, &mut diag); + } + diag.emit(); + } } // Make sure the programmer specified correct number of fields. @@ -1695,9 +1726,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let private_fields: Vec<&ty::FieldDef> = variant .fields .iter() - .filter(|field| { - !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) - }) + .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx)) .collect(); if !private_fields.is_empty() { @@ -1784,25 +1813,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); - // If the last field is a range literal, but it isn't supposed to be, then they probably - // meant to use functional update syntax. - // + if let Some(last) = ast_fields.last() { + self.suggest_fru_from_range(last, variant, substs, &mut err); + } + + err.emit(); + } + + /// If the last field is a range literal, but it isn't supposed to be, then they probably + /// meant to use functional update syntax. + fn suggest_fru_from_range( + &self, + last_expr_field: &hir::ExprField<'tcx>, + variant: &ty::VariantDef, + substs: SubstsRef<'tcx>, + err: &mut Diagnostic, + ) { // I don't use 'is_range_literal' because only double-sided, half-open ranges count. - if let Some(( - last, - ExprKind::Struct( + if let ExprKind::Struct( QPath::LangItem(LangItem::Range, ..), &[ref range_start, ref range_end], _, - ), - )) = ast_fields.last().map(|last| (last, &last.expr.kind)) && - let variant_field = - variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) && - let range_def_id = self.tcx.lang_items().range_struct() && - variant_field - .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) - .map(|adt| adt.did()) - != range_def_id + ) = last_expr_field.expr.kind + && let variant_field = + variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident) + && let range_def_id = self.tcx.lang_items().range_struct() + && variant_field + .and_then(|field| field.ty(self.tcx, substs).ty_adt_def()) + .map(|adt| adt.did()) + != range_def_id { let instead = self .tcx @@ -1818,8 +1857,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - - err.emit(); } /// Report an error for a struct field expression when there are invisible fields. @@ -2086,15 +2123,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Ident, ) -> Ty<'tcx> { debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field); - let expr_t = self.check_expr(base); - let expr_t = self.structurally_resolved_type(base.span, expr_t); + let base_ty = self.check_expr(base); + let base_ty = self.structurally_resolved_type(base.span, base_ty); let mut private_candidate = None; - let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, _)) = autoderef.next() { - debug!("base_t: {:?}", base_t); - match base_t.kind() { + let mut autoderef = self.autoderef(expr.span, base_ty); + while let Some((deref_base_ty, _)) = autoderef.next() { + debug!("deref_base_ty: {:?}", deref_base_ty); + match deref_base_ty.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { - debug!("struct named {:?}", base_t); + debug!("struct named {:?}", deref_base_ty); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id); let fields = &base_def.non_enum_variant().fields; @@ -2142,25 +2179,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (#90483) apply adjustments to avoid ExprUseVisitor from // creating erroneous projection. self.apply_adjustments(base, adjustments); - self.ban_private_field_access(expr, expr_t, field, did); + self.ban_private_field_access(expr, base_ty, field, did); return field_ty; } if field.name == kw::Empty { - } else if self.method_exists(field, expr_t, expr.hir_id, true) { - self.ban_take_value_of_method(expr, expr_t, field); - } else if !expr_t.is_primitive_ty() { - self.ban_nonexisting_field(field, base, expr, expr_t); + } else if self.method_exists(field, base_ty, expr.hir_id, true) { + self.ban_take_value_of_method(expr, base_ty, field); + } else if !base_ty.is_primitive_ty() { + self.ban_nonexisting_field(field, base, expr, base_ty); } else { let field_name = field.to_string(); let mut err = type_error_struct!( self.tcx().sess, field.span, - expr_t, + base_ty, E0610, - "`{expr_t}` is a primitive type and therefore doesn't have fields", + "`{base_ty}` is a primitive type and therefore doesn't have fields", ); - let is_valid_suffix = |field: String| { + let is_valid_suffix = |field: &str| { if field == "f32" || field == "f64" { return true; } @@ -2185,20 +2222,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suffix = chars.collect::(); suffix.is_empty() || suffix == "f32" || suffix == "f64" }; - if let ty::Infer(ty::IntVar(_)) = expr_t.kind() + let maybe_partial_suffix = |field: &str| -> Option<&str> { + let first_chars = ['f', 'l']; + if field.len() >= 1 + && field.to_lowercase().starts_with(first_chars) + && field[1..].chars().all(|c| c.is_ascii_digit()) + { + if field.to_lowercase().starts_with(['f']) { Some("f32") } else { Some("f64") } + } else { + None + } + }; + if let ty::Infer(ty::IntVar(_)) = base_ty.kind() && let ExprKind::Lit(Spanned { node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed), .. }) = base.kind && !base.span.from_expansion() - && is_valid_suffix(field_name) { - err.span_suggestion_verbose( - field.span.shrink_to_lo(), - "If the number is meant to be a floating point number, consider adding a `0` after the period", - '0', - Applicability::MaybeIncorrect, - ); + if is_valid_suffix(&field_name) { + err.span_suggestion_verbose( + field.span.shrink_to_lo(), + "if intended to be a floating point literal, consider adding a `0` after the period", + '0', + Applicability::MaybeIncorrect, + ); + } else if let Some(correct_suffix) = maybe_partial_suffix(&field_name) { + err.span_suggestion_verbose( + field.span, + format!("if intended to be a floating point literal, consider adding a `0` after the period and a `{correct_suffix}` suffix"), + format!("0{correct_suffix}"), + Applicability::MaybeIncorrect, + ); + } } err.emit(); } @@ -2206,35 +2262,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx().ty_error() } - fn check_call_constructor( - &self, - err: &mut DiagnosticBuilder<'_, G>, - base: &'tcx hir::Expr<'tcx>, - def_id: DefId, - ) { - if let Some(local_id) = def_id.as_local() { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id); - let node = self.tcx.hir().get(hir_id); - - if let Some(fields) = node.tuple_fields() { - let kind = match self.tcx.opt_def_kind(local_id) { - Some(DefKind::Ctor(of, _)) => of, - _ => return, - }; - - suggest_call_constructor(base.span, kind, fields.len(), err); - } - } else { - // The logic here isn't smart but `associated_item_def_ids` - // doesn't work nicely on local. - if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) { - let parent_def_id = self.tcx.parent(def_id); - let fields = self.tcx.associated_item_def_ids(parent_def_id); - suggest_call_constructor(base.span, of, fields.len(), err); - } - } - } - fn suggest_await_on_field_access( &self, err: &mut Diagnostic, @@ -2277,40 +2304,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn ban_nonexisting_field( &self, - field: Ident, + ident: Ident, base: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, - expr_t: Ty<'tcx>, + base_ty: Ty<'tcx>, ) { debug!( - "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", - field, base, expr, expr_t + "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}", + ident, base, expr, base_ty ); - let mut err = self.no_such_field_err(field, expr_t, base.hir_id); + let mut err = self.no_such_field_err(ident, base_ty, base.hir_id); - match *expr_t.peel_refs().kind() { + match *base_ty.peel_refs().kind() { ty::Array(_, len) => { - self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); + self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len); } ty::RawPtr(..) => { - self.suggest_first_deref_field(&mut err, expr, base, field); + self.suggest_first_deref_field(&mut err, expr, base, ident); } ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, def, field, expr.span); + self.suggest_fields_on_recordish(&mut err, def, ident, expr.span); } ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } ty::Opaque(_, _) => { - self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs()); - } - ty::FnDef(def_id, _) => { - self.check_call_constructor(&mut err, base, def_id); + self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs()); } _ => {} } - if field.name == kw::Await { + self.suggest_fn_call(&mut err, base, base_ty, |output_ty| { + if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() { + def.non_enum_variant().fields.iter().any(|field| { + field.ident(self.tcx) == ident + && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx) + }) + } else if let ty::Tuple(tys) = output_ty.kind() + && let Ok(idx) = ident.as_str().parse::() + { + idx < tys.len() + } else { + false + } + }); + + if ident.name == kw::Await { // We know by construction that `.await` is either on Rust 2015 // or results in `ExprKind::Await`. Suggest switching the edition to 2018. err.note("to `.await` a `Future`, switch to Rust 2018 or later"); @@ -2398,37 +2437,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr, Some(span), ); + } else if let ty::RawPtr(ty_and_mut) = expr_t.kind() + && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() + && let ExprKind::Field(base_expr, _) = expr.kind + && adt_def.variants().len() == 1 + && adt_def + .variants() + .iter() + .next() + .unwrap() + .fields + .iter() + .any(|f| f.ident(self.tcx) == field) + { + err.multipart_suggestion( + "to access the field, dereference first", + vec![ + (base_expr.span.shrink_to_lo(), "(*".to_string()), + (base_expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); } else { - let mut found = false; - - if let ty::RawPtr(ty_and_mut) = expr_t.kind() - && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() - { - if adt_def.variants().len() == 1 - && adt_def - .variants() - .iter() - .next() - .unwrap() - .fields - .iter() - .any(|f| f.ident(self.tcx) == field) - { - if let Some(dot_loc) = expr_snippet.rfind('.') { - found = true; - err.span_suggestion( - expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)), - "to access the field, dereference first", - format!("(*{})", &expr_snippet[0..dot_loc]), - Applicability::MaybeIncorrect, - ); - } - } - } - - if !found { - err.help("methods are immutable and cannot be assigned to"); - } + err.help("methods are immutable and cannot be assigned to"); } err.emit(); @@ -2535,54 +2566,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // try to add a suggestion in case the field is a nested field of a field of the Adt - if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { - for candidate_field in fields.iter() { - if let Some(mut field_path) = self.check_for_nested_field_satisfying( - span, - &|candidate_field, _| candidate_field.ident(self.tcx()) == field, - candidate_field, - substs, - vec![], - self.tcx.parent_module(id).to_def_id(), - ) { - // field_path includes `field` that we're looking for, so pop it. + let mod_id = self.tcx.parent_module(id).to_def_id(); + if let Some((fields, substs)) = + self.get_field_candidates_considering_privacy(span, expr_t, mod_id) + { + let candidate_fields: Vec<_> = fields + .filter_map(|candidate_field| { + self.check_for_nested_field_satisfying( + span, + &|candidate_field, _| candidate_field.ident(self.tcx()) == field, + candidate_field, + substs, + vec![], + mod_id, + ) + }) + .map(|mut field_path| { field_path.pop(); - - let field_path_str = field_path + field_path .iter() .map(|id| id.name.to_ident_string()) .collect::>() - .join("."); - debug!("field_path_str: {:?}", field_path_str); + .join(".") + }) + .collect::>(); - err.span_suggestion_verbose( - field.span.shrink_to_lo(), - "one of the expressions' fields has a field of the same name", - format!("{field_path_str}."), - Applicability::MaybeIncorrect, - ); - } + let len = candidate_fields.len(); + if len > 0 { + err.span_suggestions( + field.span.shrink_to_lo(), + format!( + "{} of the expressions' fields {} a field of the same name", + if len > 1 { "some" } else { "one" }, + if len > 1 { "have" } else { "has" }, + ), + candidate_fields.iter().map(|path| format!("{path}.")), + Applicability::MaybeIncorrect, + ); } } err } - pub(crate) fn get_field_candidates( + pub(crate) fn get_field_candidates_considering_privacy( &self, span: Span, - base_t: Ty<'tcx>, - ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> { - debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t); + base_ty: Ty<'tcx>, + mod_id: DefId, + ) -> Option<(impl Iterator + 'tcx, SubstsRef<'tcx>)> { + debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - for (base_t, _) in self.autoderef(span, base_t) { + for (base_t, _) in self.autoderef(span, base_ty) { match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { + let tcx = self.tcx; let fields = &base_def.non_enum_variant().fields; - // For compile-time reasons put a limit on number of fields we search - if fields.len() > 100 { - return None; + // Some struct, e.g. some that impl `Deref`, have all private fields + // because you're expected to deref them to access the _real_ fields. + // This, for example, will help us suggest accessing a field through a `Box`. + if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { + continue; } - return Some((fields, substs)); + return Some(( + fields + .iter() + .filter(move |field| field.vis.is_accessible_from(mod_id, tcx)) + // For compile-time reasons put a limit on number of fields we search + .take(100), + substs, + )); } _ => {} } @@ -2599,7 +2651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec, - id: DefId, + mod_id: DefId, ) -> Option> { debug!( "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2611,24 +2663,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // up to a depth of three None } else { - // recursively search fields of `candidate_field` if it's a ty::Adt field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); let field_ty = candidate_field.ty(self.tcx, subst); - if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { - for field in nested_fields.iter() { - if field.vis.is_accessible_from(id, self.tcx) { - if matches(candidate_field, field_ty) { - return Some(field_path); - } else if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - id, - ) { - return Some(field_path); - } + if matches(candidate_field, field_ty) { + return Some(field_path); + } else if let Some((nested_fields, subst)) = + self.get_field_candidates_considering_privacy(span, field_ty, mod_id) + { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + ) { + return Some(field_path); } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 3a8093345..a40478db9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) } - #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")] + #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)] pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( &self, mut ty: Ty<'tcx>, @@ -107,10 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(false, mutate_fulfillment_errors); - ty = self.resolve_vars_if_possible(ty); - - debug!(?ty); - ty + self.resolve_vars_if_possible(ty) } pub(in super::super) fn record_deferred_call_resolution( @@ -412,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))), - output_pred: None, + output_ty: None, }, ), self.param_env, @@ -498,13 +495,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); + let span = self.tcx.hir().span(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::WellFormed(None), - ); - c + self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); + self.normalize_associated_types_in(span, c) } pub fn const_arg_to_const( @@ -618,9 +612,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self); + let mut errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self); if !errors.is_empty() { + self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); self.report_fulfillment_errors(&errors, self.inh.body_id, false); } } @@ -634,6 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self); if !result.is_empty() { mutate_fulfillment_errors(&mut result); + self.adjust_fulfillment_errors_for_expr_obligation(&mut result); self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred); } } @@ -831,23 +827,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = item_ty.subst(self.tcx, substs); self.write_resolution(hir_id, Ok((def_kind, def_id))); - self.add_required_obligations_with_code( - span, - def_id, - &substs, - match lang_item { - hir::LangItem::IntoFutureIntoFuture => { - ObligationCauseCode::AwaitableExpr(expr_hir_id) - } - hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { - ObligationCauseCode::ForLoopIterator - } - hir::LangItem::TryTraitFromOutput - | hir::LangItem::TryTraitFromResidual - | hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark, - _ => traits::ItemObligation(def_id), - }, - ); + + let code = match lang_item { + hir::LangItem::IntoFutureIntoFuture => { + Some(ObligationCauseCode::AwaitableExpr(expr_hir_id)) + } + hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { + Some(ObligationCauseCode::ForLoopIterator) + } + hir::LangItem::TryTraitFromOutput + | hir::LangItem::TryTraitFromResidual + | hir::LangItem::TryTraitBranch => Some(ObligationCauseCode::QuestionMark), + _ => None, + }; + if let Some(code) = code { + self.add_required_obligations_with_code(span, def_id, substs, move |_, _| code.clone()); + } else { + self.add_required_obligations_for_hir(span, def_id, substs, hir_id); + } + (Res::Def(def_kind, def_id), ty) } @@ -986,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if found != self.tcx.types.unit { return; } - if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind { + if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind { if self .typeck_results .borrow() @@ -1359,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First, store the "user substs" for later. self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); - self.add_required_obligations(span, def_id, &substs); + self.add_required_obligations_for_hir(span, def_id, &substs, hir_id); // Substitute the values for the type parameters into the type of // the referenced item. @@ -1396,32 +1394,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Add all the obligations that are required, substituting and normalized appropriately. - pub(crate) fn add_required_obligations( + pub(crate) fn add_required_obligations_for_hir( &self, span: Span, def_id: DefId, - substs: &SubstsRef<'tcx>, + substs: SubstsRef<'tcx>, + hir_id: hir::HirId, ) { - self.add_required_obligations_with_code( - span, - def_id, - substs, - traits::ItemObligation(def_id), - ) + self.add_required_obligations_with_code(span, def_id, substs, |idx, span| { + if span.is_dummy() { + ObligationCauseCode::ExprItemObligation(def_id, hir_id, idx) + } else { + ObligationCauseCode::ExprBindingObligation(def_id, span, hir_id, idx) + } + }) } - #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))] + #[instrument(level = "debug", skip(self, code, span, def_id, substs))] fn add_required_obligations_with_code( &self, span: Span, def_id: DefId, - substs: &SubstsRef<'tcx>, - code: ObligationCauseCode<'tcx>, + substs: SubstsRef<'tcx>, + code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>, ) { let (bounds, _) = self.instantiate_bounds(span, def_id, &substs); for obligation in traits::predicates_for_generics( - traits::ObligationCause::new(span, self.body_id, code), + |idx, predicate_span| { + traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span)) + }, self.param_env, bounds, ) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index 7602f2550..fc83994ca 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -130,14 +130,17 @@ impl<'tcx> ArgMatrix<'tcx> { let ai = &self.expected_indices; let ii = &self.provided_indices; + // Issue: 100478, when we end the iteration, + // `next_unmatched_idx` will point to the index of the first unmatched + let mut next_unmatched_idx = 0; for i in 0..cmp::max(ai.len(), ii.len()) { - // If we eliminate the last row, any left-over inputs are considered missing + // If we eliminate the last row, any left-over arguments are considered missing if i >= mat.len() { - return Some(Issue::Missing(i)); + return Some(Issue::Missing(next_unmatched_idx)); } - // If we eliminate the last column, any left-over arguments are extra + // If we eliminate the last column, any left-over inputs are extra if mat[i].len() == 0 { - return Some(Issue::Extra(i)); + return Some(Issue::Extra(next_unmatched_idx)); } // Make sure we don't pass the bounds of our matrix @@ -145,6 +148,7 @@ impl<'tcx> ArgMatrix<'tcx> { let is_input = i < ii.len(); if is_arg && is_input && matches!(mat[i][i], Compatibility::Compatible) { // This is a satisfied input, so move along + next_unmatched_idx += 1; continue; } @@ -163,7 +167,7 @@ impl<'tcx> ArgMatrix<'tcx> { if is_input { for j in 0..ai.len() { // If we find at least one argument that could satisfy this input - // this argument isn't useless + // this input isn't useless if matches!(mat[i][j], Compatibility::Compatible) { useless = false; break; @@ -232,8 +236,8 @@ impl<'tcx> ArgMatrix<'tcx> { if matches!(c, Compatibility::Compatible) { Some(i) } else { None } }) .collect(); - if compat.len() != 1 { - // this could go into multiple slots, don't bother exploring both + if compat.len() < 1 { + // try to find a cycle even when this could go into multiple slots, see #101097 is_cycle = false; break; } @@ -309,7 +313,8 @@ impl<'tcx> ArgMatrix<'tcx> { } while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { - match self.find_issue() { + let res = self.find_issue(); + match res { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); let input_idx = self.provided_indices[idx]; @@ -364,7 +369,9 @@ impl<'tcx> ArgMatrix<'tcx> { None => { // We didn't find any issues, so we need to push the algorithm forward // First, eliminate any arguments that currently satisfy their inputs - for (inp, arg) in self.eliminate_satisfied() { + let eliminated = self.eliminate_satisfied(); + assert!(!eliminated.is_empty(), "didn't eliminated any indice in this round"); + for (inp, arg) in eliminated { matched_inputs[arg] = Some(inp); } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 660e7e4e3..311fcaada 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -15,6 +15,7 @@ use crate::check::{ use crate::structured_errors::StructuredDiagnostic; use rustc_ast as ast; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -27,13 +28,14 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; +use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; use rustc_session::Session; use rustc_span::symbol::Ident; -use rustc_span::{self, Span}; +use rustc_span::{self, sym, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; +use std::ops::ControlFlow; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -58,7 +60,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id); - InlineAsmCtxt::new_in_fn(self) + let get_operand_ty = |expr| { + let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); + let ty = self.resolve_vars_if_possible(ty); + if ty.has_infer_types_or_consts() { + assert!(self.is_tainted_by_errors()); + self.tcx.ty_error() + } else { + self.tcx.erase_regions(ty) + } + }; + InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) .check_asm(asm, self.tcx.hir().local_def_id_to_hir_id(enclosing_id)); } } @@ -141,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - // Conceptually, we've got some number of expected inputs, and some number of provided aguments + // Conceptually, we've got some number of expected inputs, and some number of provided arguments // and we can form a grid of whether each argument could satisfy a given input: // in1 | in2 | in3 | ... // arg1 ? | | | @@ -212,6 +224,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let minimum_input_count = expected_input_tys.len(); let provided_arg_count = provided_args.len(); + let is_const_eval_select = matches!(fn_def_id, Some(def_id) if + self.tcx.def_kind(def_id) == hir::def::DefKind::Fn + && self.tcx.is_intrinsic(def_id) + && self.tcx.item_name(def_id) == sym::const_eval_select); + // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types @@ -237,17 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Cause selection errors caused by resolving a single argument to point at the // argument and not the call. This lets us customize the span pointed to in the // fulfillment error to be more accurate. - let coerced_ty = - self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - call_expr, - call_span, - provided_args, - &expected_input_tys, - ); - }); + let coerced_ty = self.resolve_vars_with_obligations(coerced_ty); let coerce_error = self .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None) @@ -257,6 +264,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Compatibility::Incompatible(coerce_error); } + // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that + // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed + // in the function signature (`F: FnOnce`), so I did not bother to add another check here. + // + // This check is here because there is currently no way to express a trait bound for `FnDef` types only. + if is_const_eval_select && (1..=2).contains(&idx) { + if let ty::FnDef(def_id, _) = checked_ty.kind() { + if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) { + self.tcx + .sess + .struct_span_err(provided_arg.span, "this argument must be a `const fn`") + .help("consult the documentation on `const_eval_select` for more information") + .emit(); + } + } else { + self.tcx + .sess + .struct_span_err(provided_arg.span, "this argument must be a function item") + .note(format!("expected a function item, found {checked_ty}")) + .help( + "consult the documentation on `const_eval_select` for more information", + ) + .emit(); + } + } + // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks let supertype_error = self @@ -302,16 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // an "opportunistic" trait resolution of any trait bounds on // the call. This helps coercions. if check_closures { - self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - call_expr, - call_span, - &provided_args, - &expected_input_tys, - ); - }) + self.select_obligations_where_possible(false, |_| {}) } // Check each argument, to satisfy the input it was provided for @@ -440,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &hir::Expr<'tcx>, ) { // Next, let's construct the error - let (error_span, full_call_span, ctor_of) = match &call_expr.kind { + let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, _, @@ -448,22 +472,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Res::Def(DefKind::Ctor(of, _), _) = self.typeck_results.borrow().qpath_res(qpath, *hir_id) { - (call_span, *span, Some(of)) + (call_span, *span, Some(of), false) } else { - (call_span, *span, None) + (call_span, *span, None, false) } } - hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), - hir::ExprKind::MethodCall(path_segment, _, span) => { + hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), + hir::ExprKind::MethodCall(path_segment, _, _, span) => { let ident_span = path_segment.ident.span; let ident_span = if let Some(args) = path_segment.args { ident_span.with_hi(args.span_ext.hi()) } else { ident_span }; - ( - *span, ident_span, None, // methods are never ctors - ) + // methods are never ctors + (*span, ident_span, None, true) } k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), }; @@ -507,13 +530,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); let callee_expr = match &call_expr.peel_blocks().kind { hir::ExprKind::Call(callee, _) => Some(*callee), - hir::ExprKind::MethodCall(_, callee, _) => { + hir::ExprKind::MethodCall(_, receiver, ..) => { if let Some((DefKind::AssocFn, def_id)) = self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) && let Some(assoc) = tcx.opt_associated_item(def_id) && assoc.fn_has_self_parameter { - Some(&callee[0]) + Some(*receiver) } else { None } @@ -545,7 +568,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); let can_coerce = self.can_coerce(arg_ty, coerced_ty); if !can_coerce { - return Compatibility::Incompatible(None); + return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( + ty::error::ExpectedFound::new(true, coerced_ty, arg_ty), + ))); } // Using probe here, since we don't want this subtyping to affect inference. @@ -577,7 +602,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First, check if we just need to wrap some arguments in a tuple. if let Some((mismatch_idx, terr)) = compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { - if let Compatibility::Incompatible(Some(terr)) = c { Some((i, terr)) } else { None } + if let Compatibility::Incompatible(Some(terr)) = c { + Some((i, *terr)) + } else { + None + } }) { // Is the first bad expected argument a tuple? @@ -659,7 +688,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); }; - self.label_fn_like(&mut err, fn_def_id, callee_ty); + self.label_fn_like( + &mut err, + fn_def_id, + callee_ty, + Some(mismatch_idx), + is_method, + ); err.emit(); return; } @@ -701,16 +736,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } errors.drain_filter(|error| { - let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(error)) = error else { return false }; + let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let (expected_ty, _) = formal_and_expected_inputs[*expected_idx]; let cause = &self.misc(provided_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - if let Some(e) = error { - if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { - self.report_and_explain_type_error(trace, e).emit(); - return true; - } + if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { + self.report_and_explain_type_error(trace, *e).emit(); + return true; } false }); @@ -733,7 +766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let cause = &self.misc(provided_arg_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, err); + let mut err = self.report_and_explain_type_error(trace, *err); self.emit_coerce_suggestions( &mut err, &provided_args[*provided_idx], @@ -749,7 +782,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {} are incorrect", call_name), ); // Call out where the function is defined - self.label_fn_like(&mut err, fn_def_id, callee_ty); + self.label_fn_like( + &mut err, + fn_def_id, + callee_ty, + Some(expected_idx.as_usize()), + is_method, + ); err.emit(); return; } @@ -797,7 +836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Error::Invalid(provided_idx, expected_idx, compatibility) => { let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; - if let Compatibility::Incompatible(error) = &compatibility { + if let Compatibility::Incompatible(error) = compatibility { let cause = &self.misc(provided_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); if let Some(e) = error { @@ -1031,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - self.label_fn_like(&mut err, fn_def_id, callee_ty); + self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1048,11 +1087,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(suggestion_text) = suggestion_text { let source_map = self.sess().source_map(); - let mut suggestion = format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| fn_def_id - .map_or("".to_string(), |fn_def_id| tcx.item_name(fn_def_id).to_string())) - ); + let (mut suggestion, suggestion_span) = + if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { + ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) + } else { + ( + format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { + fn_def_id.map_or("".to_string(), |fn_def_id| { + tcx.item_name(fn_def_id).to_string() + }) + }) + ), + error_span, + ) + }; let mut needs_comma = false; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { if needs_comma { @@ -1062,8 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let suggestion_text = if let Some(provided_idx) = provided_idx && let (_, provided_span) = provided_arg_tys[*provided_idx] - && let Ok(arg_text) = - source_map.span_to_snippet(provided_span) + && let Ok(arg_text) = source_map.span_to_snippet(provided_span) { arg_text } else { @@ -1081,7 +1130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } suggestion += ")"; err.span_suggestion_verbose( - error_span, + suggestion_span, &suggestion_text, suggestion, Applicability::HasPlaceholders, @@ -1129,7 +1178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.ty_error(), + ast::LitKind::Err => tcx.ty_error(), } } @@ -1164,7 +1213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_user_type_annotation_from_substs(hir_id, did, substs, None); // Check bounds on type arguments used in the path. - self.add_required_obligations(path_span, did, substs); + self.add_required_obligations_for_hir(path_span, did, substs, hir_id); Some((variant, ty)) } else { @@ -1601,186 +1650,420 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk - /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s - /// reference a type argument. The reason to walk also the checked type is that the coerced type - /// can be not easily comparable with predicate type (because of coercion). If the types match - /// for either checked or coerced type, and there's only *one* argument that does, we point at - /// the corresponding argument's expression span instead of the `fn` call path span. - fn point_at_arg_instead_of_call_if_possible( + /// Given a vector of fulfillment errors, try to adjust the spans of the + /// errors to more accurately point at the cause of the failure. + /// + /// This applies to calls, methods, and struct expressions. This will also + /// try to deduplicate errors that are due to the same cause but might + /// have been created with different [`ObligationCause`][traits::ObligationCause]s. + pub(super) fn adjust_fulfillment_errors_for_expr_obligation( &self, errors: &mut Vec>, - expr: &'tcx hir::Expr<'tcx>, - call_sp: Span, - args: &'tcx [hir::Expr<'tcx>], - expected_tys: &[Ty<'tcx>], ) { - // We *do not* do this for desugared call spans to keep good diagnostics when involving - // the `?` operator. - if call_sp.desugaring_kind().is_some() { - return; - } - - 'outer: for error in errors { - // Only if the cause is somewhere inside the expression we want try to point at arg. - // Otherwise, it means that the cause is somewhere else and we should not change - // anything because we can break the correct span. - if !call_sp.contains(error.obligation.cause.span) { - continue; + // Store a mapping from `(Span, Predicate) -> ObligationCause`, so that + // other errors that have the same span and predicate can also get fixed, + // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind. + // This is important since if we adjust one span but not the other, then + // we will have "duplicated" the error on the UI side. + let mut remap_cause = FxHashSet::default(); + let mut not_adjusted = vec![]; + + for error in errors { + let before_span = error.obligation.cause.span; + if self.adjust_fulfillment_error_for_expr_obligation(error) + || before_span != error.obligation.cause.span + { + // Store both the predicate and the predicate *without constness* + // since sometimes we instantiate and check both of these in a + // method call, for example. + remap_cause.insert(( + before_span, + error.obligation.predicate, + error.obligation.cause.clone(), + )); + remap_cause.insert(( + before_span, + error.obligation.predicate.without_const(self.tcx), + error.obligation.cause.clone(), + )); + } else { + // If it failed to be adjusted once around, it may be adjusted + // via the "remap cause" mapping the second time... + not_adjusted.push(error); } + } - // Peel derived obligation, because it's the type that originally - // started this inference chain that matters, not the one we wound - // up with at the end. - fn unpeel_to_top<'a, 'tcx>( - mut code: &'a ObligationCauseCode<'tcx>, - ) -> &'a ObligationCauseCode<'tcx> { - let mut result_code = code; - loop { - let parent = match code { - ObligationCauseCode::ImplDerivedObligation(c) => &c.derived.parent_code, - ObligationCauseCode::BuiltinDerivedObligation(c) - | ObligationCauseCode::DerivedObligation(c) => &c.parent_code, - _ => break result_code, - }; - (result_code, code) = (code, parent); + for error in not_adjusted { + for (span, predicate, cause) in &remap_cause { + if *predicate == error.obligation.predicate + && span.contains(error.obligation.cause.span) + { + error.obligation.cause = cause.clone(); + continue; } } - let self_: ty::subst::GenericArg<'_> = - match unpeel_to_top(error.obligation.cause.code()) { - ObligationCauseCode::BuiltinDerivedObligation(code) - | ObligationCauseCode::DerivedObligation(code) => { - code.parent_trait_pred.self_ty().skip_binder().into() + } + } + + fn adjust_fulfillment_error_for_expr_obligation( + &self, + error: &mut traits::FulfillmentError<'tcx>, + ) -> bool { + let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx)) + = *error.obligation.cause.code().peel_derives() else { return false; }; + let hir = self.tcx.hir(); + let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; + + // Skip over mentioning async lang item + if Some(def_id) == self.tcx.lang_items().from_generator_fn() + && error.obligation.cause.span.desugaring_kind() + == Some(rustc_span::DesugaringKind::Async) + { + return false; + } + + let Some(unsubstituted_pred) = + self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) + else { return false; }; + + let generics = self.tcx.generics_of(def_id); + let predicate_substs = match unsubstituted_pred.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => pred.trait_ref.substs, + ty::PredicateKind::Projection(pred) => pred.projection_ty.substs, + _ => ty::List::empty(), + }; + + let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { + predicate_substs.types().find_map(|ty| { + ty.walk().find_map(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Param(param_ty) = ty.kind() + && matches(param_ty) + { + Some(arg) + } else { + None } - ObligationCauseCode::ImplDerivedObligation(code) => { - code.derived.parent_trait_pred.self_ty().skip_binder().into() + }) + }) + }; + + // Prefer generics that are local to the fn item, since these are likely + // to be the cause of the unsatisfied predicate. + let mut param_to_point_at = find_param_matching(&|param_ty| { + self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id + }); + // Fall back to generic that isn't local to the fn item. This will come + // from a trait or impl, for example. + let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { + self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id + && param_ty.name != rustc_span::symbol::kw::SelfUpper + }); + // Finally, the `Self` parameter is possibly the reason that the predicate + // is unsatisfied. This is less likely to be true for methods, because + // method probe means that we already kinda check that the predicates due + // to the `Self` type are true. + let mut self_param_to_point_at = + find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); + + // Finally, for ambiguity-related errors, we actually want to look + // for a parameter that is the source of the inference type left + // over in this predicate. + if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + fallback_param_to_point_at = None; + self_param_to_point_at = None; + param_to_point_at = + self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); + } + + if self.closure_span_overlaps_error(error, expr.span) { + return false; + } + + match &expr.kind { + hir::ExprKind::Path(qpath) => { + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Call(callee, args), + hir_id: call_hir_id, + span: call_span, + .. + }) = hir.get(hir.get_parent_node(expr.hir_id)) + && callee.hir_id == expr.hir_id + { + if self.closure_span_overlaps_error(error, *call_span) { + return false; } - _ if let ty::PredicateKind::Trait(predicate) = - error.obligation.predicate.kind().skip_binder() => + + for param in + [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() { - predicate.self_ty().into() + if self.point_at_arg_if_possible( + error, + def_id, + param, + *call_hir_id, + callee.span, + None, + args, + ) + { + return true; + } } - _ => continue, - }; - let self_ = self.resolve_vars_if_possible(self_); - let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_); - - let typeck_results = self.typeck_results.borrow(); - - for (idx, arg) in args.iter().enumerate() { - // Don't adjust the span if we already have a more precise span - // within one of the args. - if arg.span.contains(error.obligation.cause.span) { - let references_arg = - typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self) - || expected_tys.get(idx).copied().map_or(false, &ty_matches_self); - if references_arg && !arg.span.from_expansion() { - error.obligation.cause.map_code(|parent_code| { - ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: args[idx].hir_id, - call_hir_id: expr.hir_id, - parent_code, - } - }) + } + // Notably, we only point to params that are local to the + // item we're checking, since those are the ones we are able + // to look in the final `hir::PathSegment` for. Everything else + // would require a deeper search into the `qpath` than I think + // is worthwhile. + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) + { + return true; + } + } + hir::ExprKind::MethodCall(segment, receiver, args, ..) => { + for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() + { + if self.point_at_arg_if_possible( + error, + def_id, + param, + hir_id, + segment.ident.span, + Some(receiver), + args, + ) { + return true; + } + } + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment) + { + return true; + } + } + hir::ExprKind::Struct(qpath, fields, ..) => { + if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = + self.typeck_results.borrow().qpath_res(qpath, hir_id) + { + for param in + [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + { + if let Some(param) = param + && self.point_at_field_if_possible( + error, + def_id, + param, + variant_def_id, + fields, + ) + { + return true; + } } - continue 'outer; + } + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) + { + return true; } } + _ => {} + } - // Collect the argument position for all arguments that could have caused this - // `FulfillmentError`. - let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args) - .enumerate() - .flat_map(|(idx, (expected_ty, arg))| { - if let Some(arg_ty) = typeck_results.expr_ty_opt(arg) { - vec![(idx, arg_ty), (idx, *expected_ty)] - } else { - vec![] - } - }) - .filter_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(ty); - // We walk the argument type because the argument's type could have - // been `Option`, but the `FulfillmentError` references `T`. - if ty_matches_self(ty) { Some(i) } else { None } - }) - .collect(); + false + } + + fn closure_span_overlaps_error( + &self, + error: &traits::FulfillmentError<'tcx>, + span: Span, + ) -> bool { + if let traits::FulfillmentErrorCode::CodeSelectionError( + traits::SelectionError::OutputTypeParameterMismatch(_, expected, _), + ) = error.code + && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind() + && span.overlaps(self.tcx.def_span(*def_id)) + { + true + } else { + false + } + } + + fn point_at_arg_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + call_hir_id: hir::HirId, + callee_span: Span, + receiver: Option<&'tcx hir::Expr<'tcx>>, + args: &'tcx [hir::Expr<'tcx>], + ) -> bool { + let sig = self.tcx.fn_sig(def_id).skip_binder(); + let args_referencing_param: Vec<_> = sig + .inputs() + .iter() + .enumerate() + .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) + .collect(); + // If there's one field that references the given generic, great! + if let [(idx, _)] = args_referencing_param.as_slice() + && let Some(arg) = receiver + .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { + error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); + error.obligation.cause.map_code(|parent_code| { + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: arg.hir_id, + call_hir_id, + parent_code, + } + }); + return true; + } else if args_referencing_param.len() > 0 { + // If more than one argument applies, then point to the callee span at least... + // We have chance to fix this up further in `point_at_generics_if_possible` + error.obligation.cause.span = callee_span; + } - // Both checked and coerced types could have matched, thus we need to remove - // duplicates. + false + } - // We sort primitive type usize here and can use unstable sort - referenced_in.sort_unstable(); - referenced_in.dedup(); + fn point_at_field_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + variant_def_id: DefId, + expr_fields: &[hir::ExprField<'tcx>], + ) -> bool { + let def = self.tcx.adt_def(def_id); + + let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id); + let fields_referencing_param: Vec<_> = def + .variant_with_id(variant_def_id) + .fields + .iter() + .filter(|field| { + let field_ty = field.ty(self.tcx, identity_substs); + find_param_in_ty(field_ty, param_to_point_at) + }) + .collect(); - if let &[idx] = &referenced_in[..] { - // Do not point at the inside of a macro. - // That would often result in poor error messages. - if args[idx].span.from_expansion() { - continue; + if let [field] = fields_referencing_param.as_slice() { + for expr_field in expr_fields { + // Look for the ExprField that matches the field, using the + // same rules that check_expr_struct uses for macro hygiene. + if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx) + { + error.obligation.cause.span = expr_field + .expr + .span + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(expr_field.span); + return true; } - // We make sure that only *one* argument matches the obligation failure - // and we assign the obligation's span to its expression's. - error.obligation.cause.span = args[idx].span; - error.obligation.cause.map_code(|parent_code| { - ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: args[idx].hir_id, - call_hir_id: expr.hir_id, - parent_code, - } - }); - } else if error.obligation.cause.span == call_sp { - // Make function calls point at the callee, not the whole thing. - if let hir::ExprKind::Call(callee, _) = expr.kind { - error.obligation.cause.span = callee.span; + } + } + + false + } + + fn point_at_path_if_possible( + &self, + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param: ty::GenericArg<'tcx>, + qpath: &QPath<'tcx>, + ) -> bool { + match qpath { + hir::QPath::Resolved(_, path) => { + if let Some(segment) = path.segments.last() + && self.point_at_generic_if_possible(error, def_id, param, segment) + { + return true; } } + hir::QPath::TypeRelative(_, segment) => { + if self.point_at_generic_if_possible(error, def_id, param, segment) { + return true; + } + } + _ => {} } + + false } - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the - /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s - /// were caused by them. If they were, we point at the corresponding type argument's span - /// instead of the `fn` call path span. - fn point_at_type_arg_instead_of_call_if_possible( + fn point_at_generic_if_possible( &self, - errors: &mut Vec>, - call_expr: &'tcx hir::Expr<'tcx>, - ) { - if let hir::ExprKind::Call(path, _) = &call_expr.kind { - if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &path.kind { - for error in errors { - if let ty::PredicateKind::Trait(predicate) = - error.obligation.predicate.kind().skip_binder() - { - // If any of the type arguments in this path segment caused the - // `FulfillmentError`, point at its span (#61860). - for arg in path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .flat_map(|a| a.args.iter()) - { - if let hir::GenericArg::Type(hir_ty) = &arg - && let Some(ty) = - self.typeck_results.borrow().node_type_opt(hir_ty.hir_id) - && self.resolve_vars_if_possible(ty) == predicate.self_ty() - { - error.obligation.cause.span = hir_ty.span; - break; - } - } - } + error: &mut traits::FulfillmentError<'tcx>, + def_id: DefId, + param_to_point_at: ty::GenericArg<'tcx>, + segment: &hir::PathSegment<'tcx>, + ) -> bool { + let own_substs = self + .tcx + .generics_of(def_id) + .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); + let Some((index, _)) = own_substs + .iter() + .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) + .enumerate() + .find(|(_, arg)| **arg == param_to_point_at) else { return false }; + let Some(arg) = segment + .args() + .args + .iter() + .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) + .nth(index) else { return false; }; + error.obligation.cause.span = arg + .span() + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(arg.span()); + true + } + + fn find_ambiguous_parameter_in>( + &self, + item_def_id: DefId, + t: T, + ) -> Option> { + struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId); + impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> { + type BreakTy = ty::GenericArg<'tcx>; + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { + if let Some(origin) = self.0.type_var_origin(ty) + && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = + origin.kind + && let generics = self.0.tcx.generics_of(self.1) + && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) + && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) + .get(index as usize) + { + ControlFlow::Break(*subst) + } else { + ty.super_visit_with(self) } } } + t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value() } fn label_fn_like( &self, - err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, + err: &mut Diagnostic, callable_def_id: Option, callee_ty: Option>, + // A specific argument should be labeled, instead of all of them + expected_idx: Option, + is_method: bool, ) { let Some(mut def_id) = callable_def_id else { return; @@ -1838,14 +2121,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_def_id = self.probe(|_| { let trait_ref = ty::TraitRef::new( call_kind.to_def_id(self.tcx), - self.tcx.mk_substs([ - ty::GenericArg::from(callee_ty), - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: rustc_span::DUMMY_SP, - }) - .into(), - ].into_iter()), + self.tcx.mk_substs( + [ + ty::GenericArg::from(callee_ty), + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: rustc_span::DUMMY_SP, + }) + .into(), + ] + .into_iter(), + ), ); let obligation = traits::Obligation::new( traits::ObligationCause::dummy(), @@ -1860,7 +2146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { Some(impl_source.impl_def_id) } - _ => None + _ => None, } }); if let Some(new_def_id) = new_def_id { @@ -1881,14 +2167,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .get_if_local(def_id) .and_then(|node| node.body_id()) .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params); + .flat_map(|id| self.tcx.hir().body(id).params) + .skip(if is_method { 1 } else { 0 }); - for param in params { + for (_, param) in params + .into_iter() + .enumerate() + .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) + { spans.push_span_label(param.span, ""); } let def_kind = self.tcx.def_kind(def_id); err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) + && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind + { + let param = expected_idx + .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); + let (kind, span) = if let Some(param) = param { + ("closure parameter", param.span) + } else { + ("closure", self.tcx.def_span(def_id)) + }; + err.span_note(span, &format!("{} defined here", kind)); } else { let def_kind = self.tcx.def_kind(def_id); err.span_note( @@ -1898,3 +2200,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) -> bool { + let mut walk = ty.walk(); + while let Some(arg) = walk.next() { + if arg == param_to_point_at { + return true; + } else if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Projection(..) = ty.kind() + { + // This logic may seem a bit strange, but typically when + // we have a projection type in a function signature, the + // argument that's being passed into that signature is + // not actually constraining that projection's substs in + // a meaningful way. So we skip it, and see improvements + // in some UI tests. + walk.skip_current_subtree(); + } + } + false +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 05bcc710e..0e22971d3 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -26,6 +26,17 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use std::cell::{Cell, RefCell}; use std::ops::Deref; +/// The `FnCtxt` stores type-checking context needed to type-check bodies of +/// functions, closures, and `const`s, including performing type inference +/// with [`InferCtxt`]. +/// +/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures* +/// and thus does not perform type inference. +/// +/// See [`ItemCtxt`]'s docs for more. +/// +/// [`ItemCtxt`]: crate::collect::ItemCtxt +/// [`InferCtxt`]: infer::InferCtxt pub struct FnCtxt<'a, 'tcx> { pub(super) body_id: hir::HirId, @@ -57,8 +68,6 @@ pub struct FnCtxt<'a, 'tcx> { /// any). pub(super) ret_coercion: Option>>, - pub(super) ret_type_span: Option, - /// Used exclusively to reduce cost of advanced evaluation used for /// more helpful diagnostics. pub(super) in_tail_expr: bool, @@ -131,7 +140,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, - ret_type_span: None, in_tail_expr: false, ret_coercion_span: Cell::new(None), resume_yield_tys: None, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 57771e096..ee0ad7b5d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -2,6 +2,7 @@ use super::FnCtxt; use crate::astconv::AstConv; use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use hir::def_id::DefId; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -16,6 +17,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -61,70 +63,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pointing_at_return_type } - /// When encountering an fn-like ctor that needs to unify with a value, check whether calling - /// the ctor would successfully solve the type mismatch and if so, suggest it: + /// When encountering an fn-like type, try accessing the output of the type + /// // and suggesting calling it if it satisfies a predicate (i.e. if the + /// output has a method or a field): /// ```compile_fail,E0308 /// fn foo(x: usize) -> usize { x } /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` /// ``` - fn suggest_fn_call( + pub(crate) fn suggest_fn_call( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, - expected: Ty<'tcx>, found: Ty<'tcx>, + can_satisfy: impl FnOnce(Ty<'tcx>) -> bool, ) -> bool { - let (def_id, output, inputs) = match *found.kind() { - ty::FnDef(def_id, _) => { - let fn_sig = found.fn_sig(self.tcx); - (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len()) - } - ty::Closure(def_id, substs) => { - let fn_sig = substs.as_closure().sig(); - (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1) - } - ty::Opaque(def_id, substs) => { - let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder() - && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() - { - Some(( - pred.kind().rebind(proj.term.ty().unwrap()), - args.len(), - )) - } else { - None - } - }); - if let Some((output, inputs)) = sig { - (def_id, output, inputs) - } else { - return false; - } - } - _ => return false, - }; - - let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output); - let output = self.normalize_associated_types_in(expr.span, output); - if !output.is_ty_var() && self.can_coerce(output, expected) { - let (sugg_call, mut applicability) = match inputs { + let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found) + else { return false; }; + if can_satisfy(output) { + let (sugg_call, mut applicability) = match inputs.len() { 0 => ("".to_string(), Applicability::MachineApplicable), 1..=4 => ( - (0..inputs).map(|_| "_").collect::>().join(", "), - Applicability::MachineApplicable, + inputs + .iter() + .map(|ty| { + if ty.is_suggestable(self.tcx, false) { + format!("/* {ty} */") + } else { + "".to_string() + } + }) + .collect::>() + .join(", "), + Applicability::HasPlaceholders, ), - _ => ("...".to_string(), Applicability::HasPlaceholders), + _ => ("/* ... */".to_string(), Applicability::HasPlaceholders), }; - let msg = match self.tcx.def_kind(def_id) { - DefKind::Fn => "call this function", - DefKind::Closure | DefKind::OpaqueTy => "call this closure", - DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct", - DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant", - _ => "call this function", + let msg = match def_id_or_name { + DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) { + DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(), + DefKind::Ctor(CtorOf::Variant, _) => { + "instantiate this tuple variant".to_string() + } + kind => format!("call this {}", kind.descr(def_id)), + }, + DefIdOrName::Name(name) => format!("call this {name}"), }; let sugg = match expr.kind { @@ -161,6 +144,182 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// Extracts information about a callable type for diagnostics. This is a + /// heuristic -- it doesn't necessarily mean that a type is always callable, + /// because the callable type must also be well-formed to be called. + pub(in super::super) fn extract_callable_info( + &self, + expr: &Expr<'_>, + found: Ty<'tcx>, + ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)> { + // Autoderef is useful here because sometimes we box callables, etc. + let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| { + match *found.kind() { + ty::FnPtr(fn_sig) => + Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())), + ty::FnDef(def_id, _) => { + let fn_sig = found.fn_sig(self.tcx); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) + } + ty::Closure(def_id, substs) => { + let fn_sig = substs.as_closure().sig(); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) + } + ty::Opaque(def_id, substs) => { + self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { + if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder() + && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() + // args tuple will always be substs[1] + && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + { + Some(( + DefIdOrName::DefId(def_id), + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } + }) + } + ty::Dynamic(data, _, ty::Dyn) => { + data.iter().find_map(|pred| { + if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() + && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output() + // for existential projection, substs are shifted over by 1 + && let ty::Tuple(args) = proj.substs.type_at(0).kind() + { + Some(( + DefIdOrName::Name("trait object"), + pred.rebind(proj.term.ty().unwrap()), + pred.rebind(args.as_slice()), + )) + } else { + None + } + }) + } + ty::Param(param) => { + let def_id = self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx).def_id; + self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| { + if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder() + && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() + && proj.projection_ty.self_ty() == found + // args tuple will always be substs[1] + && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + { + Some(( + DefIdOrName::DefId(def_id), + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } + }) + } + _ => None, + } + }) else { return None; }; + + let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output); + let inputs = inputs + .skip_binder() + .iter() + .map(|ty| { + self.replace_bound_vars_with_fresh_vars( + expr.span, + infer::FnCall, + inputs.rebind(*ty), + ) + }) + .collect(); + + // We don't want to register any extra obligations, which should be + // implied by wf, but also because that would possibly result in + // erroneous errors later on. + let infer::InferOk { value: output, obligations: _ } = + self.normalize_associated_types_in_as_infer_ok(expr.span, output); + + if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } + } + + pub fn suggest_two_fn_call( + &self, + err: &mut Diagnostic, + lhs_expr: &'tcx hir::Expr<'tcx>, + lhs_ty: Ty<'tcx>, + rhs_expr: &'tcx hir::Expr<'tcx>, + rhs_ty: Ty<'tcx>, + can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool, + ) -> bool { + let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty) + else { return false; }; + let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty) + else { return false; }; + + if can_satisfy(lhs_output_ty, rhs_output_ty) { + let mut sugg = vec![]; + let mut applicability = Applicability::MachineApplicable; + + for (expr, inputs) in [(lhs_expr, lhs_inputs), (rhs_expr, rhs_inputs)] { + let (sugg_call, this_applicability) = match inputs.len() { + 0 => ("".to_string(), Applicability::MachineApplicable), + 1..=4 => ( + inputs + .iter() + .map(|ty| { + if ty.is_suggestable(self.tcx, false) { + format!("/* {ty} */") + } else { + "/* value */".to_string() + } + }) + .collect::>() + .join(", "), + Applicability::HasPlaceholders, + ), + _ => ("/* ... */".to_string(), Applicability::HasPlaceholders), + }; + + applicability = applicability.max(this_applicability); + + match expr.kind { + hir::ExprKind::Call(..) + | hir::ExprKind::Path(..) + | hir::ExprKind::Index(..) + | hir::ExprKind::Lit(..) => { + sugg.extend([(expr.span.shrink_to_hi(), format!("({sugg_call})"))]); + } + hir::ExprKind::Closure { .. } => { + // Might be `{ expr } || { bool }` + applicability = Applicability::MaybeIncorrect; + sugg.extend([ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!(")({sugg_call})")), + ]); + } + _ => { + sugg.extend([ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!(")({sugg_call})")), + ]); + } + } + } + + err.multipart_suggestion_verbose( + format!("use parentheses to call these"), + sugg, + applicability, + ); + + true + } else { + false + } + } + pub fn suggest_deref_ref_or_into( &self, err: &mut Diagnostic, @@ -178,12 +337,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_suggestion(sp, &msg, suggestion, applicability); } - } else if let (ty::FnDef(def_id, ..), true) = - (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) + } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) + && let ty::FnDef(def_id, ..) = &found.kind() + && let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - err.span_label(sp, format!("{found} defined here")); - } + err.span_label(sp, format!("{found} defined here")); } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); if !methods.is_empty() { @@ -506,30 +664,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()` or an impl). - match ( - &fn_decl.output, - found.is_suggestable(self.tcx, false), - can_suggest, - expected.is_unit(), - ) { - (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found }); - true - } - (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { - // FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest - // that. - err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span }); - true - } - (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { + match &fn_decl.output { + &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { // `fn main()` must return `()`, do not suggest changing return type err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span }); - true + return true; + } + &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { + if found.is_suggestable(self.tcx, false) { + err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + return true; + } else if let ty::Closure(_, substs) = found.kind() + // FIXME(compiler-errors): Get better at printing binders... + && let closure = substs.as_closure() + && closure.sig().is_suggestable(self.tcx, false) + { + err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); + return true; + } else { + // FIXME: if `found` could be `impl Iterator` we should suggest that. + err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span }); + return true + } } - // expectation was caused by something else, not the default return - (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, - (&hir::FnRetTy::Return(ref ty), _, _, _) => { + &hir::FnRetTy::Return(ref ty) => { // Only point to return type if the expected type is the return type, as if they // are not, the expectation must have been caused by something else. debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); @@ -546,9 +704,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_suggest_return_impl_trait(err, expected, ty, fn_id); return true; } - false } + _ => {} } + false } /// check whether the return type is a generic type with a trait bound @@ -770,6 +929,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn suggest_copied_or_cloned( + &self, + diag: &mut Diagnostic, + expr: &hir::Expr<'_>, + expr_ty: Ty<'tcx>, + expected_ty: Ty<'tcx>, + ) { + let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; }; + let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; }; + if adt_def != expected_adt_def { + return; + } + + let mut suggest_copied_or_cloned = || { + let expr_inner_ty = substs.type_at(0); + let expected_inner_ty = expected_substs.type_at(0); + if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() + && self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok() + { + let def_path = self.tcx.def_path_str(adt_def.did()); + if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { + diag.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{def_path}::copied` to copy the value inside the `{def_path}`" + ), + ".copied()", + Applicability::MachineApplicable, + ); + } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() + && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + self, + self.param_env, + *ty, + clone_did, + expr.span + ) + { + diag.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{def_path}::cloned` to clone the value inside the `{def_path}`" + ), + ".cloned()", + Applicability::MachineApplicable, + ); + } + } + }; + + if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result) + && adt_def.did() == result_did + // Check that the error types are equal + && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok() + { + suggest_copied_or_cloned(); + } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option) + && adt_def.did() == option_did + { + suggest_copied_or_cloned(); + } + } + /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( @@ -830,7 +1052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_ty: Ty<'tcx>, expr: &hir::Expr<'_>, ) { - let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; }; + let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; }; let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; }; let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return }; let results = self.typeck_results.borrow(); @@ -910,3 +1132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +pub enum DefIdOrName { + DefId(DefId), + Name(&'static str), +} diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index d4f800149..7ab6d9e2b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -17,7 +17,6 @@ use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; mod drop_ranges; @@ -409,8 +408,15 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { }) { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) } else { - debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id)); - match self.fcx.tcx.hir().find_parent_node(expr.hir_id) { + let parent_expr = self + .fcx + .tcx + .hir() + .parent_iter(expr.hir_id) + .find(|(_, node)| matches!(node, hir::Node::Expr(_))) + .map(|(id, _)| id); + debug!("parent_expr: {:?}", parent_expr); + match parent_expr { Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }), None => { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) @@ -457,7 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } #[derive(Default)] -pub struct SuspendCheckData<'a, 'tcx> { +struct SuspendCheckData<'a, 'tcx> { expr: Option<&'tcx Expr<'tcx>>, source_span: Span, yield_span: Span, @@ -472,7 +478,7 @@ pub struct SuspendCheckData<'a, 'tcx> { // // Note that this technique was chosen over things like a `Suspend` marker trait // as it is simpler and has precedent in the compiler -pub fn check_must_not_suspend_ty<'tcx>( +fn check_must_not_suspend_ty<'tcx>( fcx: &FnCtxt<'_, 'tcx>, ty: Ty<'tcx>, hir_id: HirId, @@ -489,6 +495,8 @@ pub fn check_must_not_suspend_ty<'tcx>( let plural_suffix = pluralize!(data.plural_len); + debug!("Checking must_not_suspend for {}", ty); + match *ty.kind() { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); @@ -519,7 +527,7 @@ pub fn check_must_not_suspend_ty<'tcx>( } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { @@ -580,6 +588,12 @@ pub fn check_must_not_suspend_ty<'tcx>( }, ) } + // If drop tracking is enabled, we want to look through references, since the referrent + // may not be considered live across the await point. + ty::Ref(_region, ty, _mutability) if fcx.sess().opts.unstable_opts.drop_tracking => { + let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty(fcx, ty, hir_id, SuspendCheckData { descr_pre, ..data }) + } _ => false, } } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index a2c23db16..016f4056b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -256,6 +256,8 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | hir::Node::TypeBinding(..) | hir::Node::TraitRef(..) | hir::Node::Pat(..) + | hir::Node::PatField(..) + | hir::Node::ExprField(..) | hir::Node::Arm(..) | hir::Node::Local(..) | hir::Node::Ctor(..) @@ -432,7 +434,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.handle_uninhabited_return(expr); } - ExprKind::MethodCall(_, exprs, _) => { + ExprKind::MethodCall(_, receiver, exprs, _) => { + self.visit_expr(receiver); for expr in exprs { self.visit_expr(expr); } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index ded0888c3..e22675e9d 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -159,8 +159,8 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { bk: rustc_middle::ty::BorrowKind, ) { debug!( - "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \ - borrow_kind={bk:?}" + "borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \ + borrow_kind={bk:#?}" ); self.borrow_place(place_with_id); diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index cd152eb97..37c830d4e 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,6 +1,7 @@ use super::callee::DeferredCallResolution; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; @@ -12,7 +13,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::{self, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _, +}; use std::cell::RefCell; use std::ops::Deref; @@ -37,6 +40,7 @@ pub struct Inherited<'a, 'tcx> { // Some additional `Sized` obligations badly affect type inference. // These obligations are added in a later stage of typeck. + // Removing these may also cause additional complications, see #101066. pub(super) deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, @@ -89,7 +93,29 @@ impl<'tcx> Inherited<'_, 'tcx> { infcx: tcx .infer_ctxt() .ignoring_regions() - .with_fresh_in_progress_typeck_results(hir_owner), + .with_fresh_in_progress_typeck_results(hir_owner) + .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| { + if fn_sig.has_escaping_bound_vars() { + return fn_sig; + } + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + let normalized_fn_sig = ocx.normalize( + ObligationCause::dummy(), + // FIXME(compiler-errors): This is probably not the right param-env... + infcx.tcx.param_env(def_id), + fn_sig, + ); + if ocx.select_all_or_error().is_empty() { + let normalized_fn_sig = + infcx.resolve_vars_if_possible(normalized_fn_sig); + if !normalized_fn_sig.needs_infer() { + return normalized_fn_sig; + } + } + fn_sig + }) + })), def_id, } } diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 3f2a0da8d..c7425ff78 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -69,6 +69,9 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { // to note that it's safe to call, since // safe extern fns are otherwise unprecedented. sym::abort + | sym::assert_inhabited + | sym::assert_zero_valid + | sym::assert_uninit_valid | sym::size_of | sym::min_align_of | sym::needs_drop @@ -92,8 +95,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { | sym::type_id | sym::likely | sym::unlikely - | sym::ptr_guaranteed_eq - | sym::ptr_guaranteed_ne + | sym::ptr_guaranteed_cmp | sym::minnumf32 | sym::minnumf64 | sym::maxnumf32 @@ -102,7 +104,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { | sym::type_name | sym::forget | sym::black_box - | sym::variant_count => hir::Unsafety::Normal, + | sym::variant_count + | sym::ptr_mask => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } @@ -200,6 +203,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), + sym::ptr_mask => ( + 1, + vec![ + tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + tcx.types.usize, + ], + tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + ), + sym::copy | sym::copy_nonoverlapping => ( 1, vec![ @@ -289,8 +301,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])) } - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) + sym::ptr_guaranteed_cmp => { + (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8) } sym::const_allocate => { @@ -465,7 +477,11 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), - sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)), + sym::simd_cast + | sym::simd_as + | sym::simd_cast_ptr + | sym::simd_expose_addr + | sym::simd_from_exposed_addr => (2, vec![param(0)], param(1)), sym::simd_bitmask => (2, vec![param(0)], param(1)), sym::simd_select | sym::simd_select_bitmask => { (2, vec![param(0), param(1), param(1)], param(1)) diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index df94abbaf..d8fe63dbf 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -9,7 +9,6 @@ use rustc_session::lint; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::{Pointer, VariantIdx}; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; -use rustc_trait_selection::infer::InferCtxtExt; use super::FnCtxt; @@ -98,12 +97,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); } +} + +pub struct InlineAsmCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + get_operand_ty: Box) -> Ty<'tcx> + 'a>, +} + +impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { + pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { + InlineAsmCtxt { + tcx, + param_env: ty::ParamEnv::empty(), + get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), + } + } + + pub fn new_in_fn( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, + ) -> Self { + InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) } + } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) { + if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -111,36 +134,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } false } -} - -pub struct InlineAsmCtxt<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - fcx: Option<&'a FnCtxt<'a, 'tcx>>, -} - -impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { - pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { - InlineAsmCtxt { tcx, fcx: None } - } - - pub fn new_in_fn(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { - InlineAsmCtxt { tcx: fcx.tcx, fcx: Some(fcx) } - } fn check_asm_operand_type( &self, idx: usize, reg: InlineAsmRegOrRegClass, - expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'tcx>, template: &[InlineAsmTemplatePiece], is_input: bool, - tied_input: Option<(&hir::Expr<'tcx>, Option)>, + tied_input: Option<(&'tcx hir::Expr<'tcx>, Option)>, target_features: &FxHashSet, ) -> Option { - let fcx = self.fcx.unwrap_or_else(|| span_bug!(expr.span, "asm operand for global asm")); - // Check the type against the allowed types for inline asm. - let ty = fcx.typeck_results.borrow().expr_ty_adjusted(expr); - let ty = fcx.resolve_vars_if_possible(ty); + let ty = (self.get_operand_ty)(expr); + if ty.has_infer_types_or_consts() { + bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); + } let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, @@ -148,12 +156,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { _ => unreachable!(), }; - // Expect types to be fully resolved, no const or type variables. - if ty.has_infer_types_or_consts() { - assert!(fcx.is_tainted_by_errors()); - return None; - } - let asm_ty = match *ty.kind() { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, @@ -167,7 +169,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), ty::FnPtr(_) => Some(asm_ty_isize), - ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if fcx.is_thin_ptr_ty(ty) => { + ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if self.is_thin_ptr_ty(ty) => { Some(asm_ty_isize) } ty::Adt(adt, substs) if adt.repr().simd() => { @@ -219,7 +221,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, ty, DUMMY_SP) { + if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) { let msg = "arguments for inline assembly must be copyable"; let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!("`{ty}` does not implement the Copy trait")); @@ -240,8 +242,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let msg = "incompatible types for asm inout argument"; let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); - let in_expr_ty = fcx.typeck_results.borrow().expr_ty_adjusted(in_expr); - let in_expr_ty = fcx.resolve_vars_if_possible(in_expr_ty); + let in_expr_ty = (self.get_operand_ty)(in_expr); err.span_label(in_expr.span, &format!("type `{in_expr_ty}`")); err.span_label(expr.span, &format!("type `{ty}`")); err.note( @@ -332,10 +333,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let mut err = lint.build(msg); err.span_label(expr.span, "for this argument"); err.help(&format!( - "use the `{suggested_modifier}` modifier to have the register formatted as `{suggested_result}`", + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", )); err.help(&format!( - "or use the `{default_modifier}` modifier to keep the default formatting of `{default_result}`", + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", )); err.emit(); }, diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 2c89b63ae..59fd5c315 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -491,7 +491,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // so we just call `predicates_for_generics` directly to avoid redoing work. // `self.add_required_obligations(self.span, def_id, &all_substs);` for obligation in traits::predicates_for_generics( - traits::ObligationCause::new(self.span, self.body_id, traits::ItemObligation(def_id)), + |idx, span| { + let code = if span.is_dummy() { + ObligationCauseCode::ExprItemObligation(def_id, self.call_expr.hir_id, idx) + } else { + ObligationCauseCode::ExprBindingObligation( + def_id, + span, + self.call_expr.hir_id, + idx, + ) + }; + traits::ObligationCause::new(self.span, self.body_id, code) + }, self.param_env, method_predicates, ) { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 0e678c41f..249e9c66b 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -20,10 +20,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{ - self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term, - ToPredicate, Ty, TypeVisitable, -}; +use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -168,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `call_expr`: the complete method call: (`foo.bar::(...)`) /// * `self_expr`: the self expression (`foo`) /// * `args`: the expressions of the arguments (`a, b + 1, ...`) - #[instrument(level = "debug", skip(self, call_expr, self_expr))] + #[instrument(level = "debug", skip(self))] pub fn lookup_method( &self, self_ty: Ty<'tcx>, @@ -178,11 +175,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) -> Result, MethodError<'tcx>> { - debug!( - "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", - segment.ident, self_ty, call_expr, self_expr - ); - let pick = self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; @@ -342,22 +334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Construct an obligation let poly_trait_ref = ty::Binder::dummy(trait_ref); - let opt_output_ty = - expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); - let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind( - self.tcx, - Ident::from_str("Output"), - AssocKind::Type, - trait_def_id, - ); - let output_pred = - opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| { - ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate { - projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id }, - term: Term::Ty(output_ty), - })) - .to_predicate(self.tcx) - }); + let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); ( traits::Obligation::new( @@ -368,7 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_pred, + output_ty, }, ), self.param_env, @@ -383,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// In particular, it doesn't really do any probing: it simply constructs /// an obligation for a particular trait with the given self type and checks /// whether that trait is implemented. - #[instrument(level = "debug", skip(self, span, opt_input_types))] + #[instrument(level = "debug", skip(self, span))] pub(super) fn lookup_method_in_trait( &self, span: Span, @@ -392,11 +369,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option>> { - debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", - self_ty, m_name, trait_def_id, opt_input_types - ); - let (obligation, substs) = self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); self.construct_obligation_for_trait( @@ -528,13 +500,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_pred: None, + output_ty: None, }, ) } else { traits::ObligationCause::misc(span, self.body_id) }; - obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, bounds)); + let predicates_cause = cause.clone(); + obligations.extend(traits::predicates_for_generics( + move |_, _| predicates_cause.clone(), + self.param_env, + bounds, + )); // Also add an obligation for the method type being well-formed. let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig)); @@ -571,7 +548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_ty`: the type to search within (`Foo`) /// * `self_ty_span` the span for the type being searched within (span of `Foo`) /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn resolve_fully_qualified_call( &self, span: Span, @@ -580,11 +557,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty_span: Span, expr_id: hir::HirId, ) -> Result<(DefKind, DefId), MethodError<'tcx>> { - debug!( - "resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}", - method_name, self_ty, expr_id, - ); - let tcx = self.tcx; // Check if we have an enum variant. @@ -628,21 +600,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &pick, ); - debug!("resolve_fully_qualified_call: pick={:?}", pick); + debug!(?pick); { let mut typeck_results = self.typeck_results.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); for import_id in pick.import_ids { - debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id); + debug!(used_trait_import=?import_id); used_trait_imports.insert(import_id); } } let def_kind = pick.item.kind.as_def_kind(); - debug!( - "resolve_fully_qualified_call: def_kind={:?}, def_id={:?}", - def_kind, pick.item.def_id - ); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); Ok((def_kind, pick.item.def_id)) } diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index 7c68d9304..392695cca 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -160,7 +160,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if precise { let args = args .iter() - .skip(1) .map(|arg| { let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); format!( diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index efe15fec7..e9f55ab34 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -253,7 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would result in an error (basically, the same criteria we /// would use to decide if a method is a plausible fit for /// ambiguity purposes). - #[instrument(level = "debug", skip(self, scope_expr_id))] + #[instrument(level = "debug", skip(self))] pub fn probe_for_return_type( &self, span: Span, @@ -262,10 +262,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, scope_expr_id: hir::HirId, ) -> Vec { - debug!( - "probe(self_ty={:?}, return_type={}, scope_expr_id={})", - self_ty, return_type, scope_expr_id - ); let method_names = self .probe_op( span, @@ -299,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect() } - #[instrument(level = "debug", skip(self, scope_expr_id))] + #[instrument(level = "debug", skip(self))] pub fn probe_for_name( &self, span: Span, @@ -310,10 +306,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope_expr_id: hir::HirId, scope: ProbeScope, ) -> PickResult<'tcx> { - debug!( - "probe(self_ty={:?}, item_name={}, scope_expr_id={})", - self_ty, item_name, scope_expr_id - ); self.probe_op( span, mode, @@ -1514,8 +1506,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds); // Convert the bounds into obligations. - let impl_obligations = - traits::predicates_for_generics(cause, self.param_env, impl_bounds); + let impl_obligations = traits::predicates_for_generics( + move |_, _| cause.clone(), + self.param_env, + impl_bounds, + ); let candidate_obligations = impl_obligations .chain(norm_obligations.into_iter()) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index c92b93cbc..2d459b2cc 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -16,8 +16,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span}; @@ -30,8 +30,8 @@ use rustc_trait_selection::traits::{ use std::cmp::Ordering; use std::iter; -use super::probe::{Mode, ProbeScope}; -use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData}; +use super::probe::{IsSuggestion, Mode, ProbeScope}; +use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { @@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, + args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, ) -> Option> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { @@ -363,44 +363,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if self.is_fn_ty(rcvr_ty, span) { - if let SelfSource::MethodCall(expr) = source { - let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() { - if let Some(local_id) = def_id.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(local_id); - let node = tcx.hir().get(hir_id); - let fields = node.tuple_fields(); - if let Some(fields) = fields - && let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) { - Some((fields.len(), of)) - } else { - None - } - } else { - // The logic here isn't smart but `associated_item_def_ids` - // doesn't work nicely on local. - if let DefKind::Ctor(of, _) = tcx.def_kind(def_id) { - let parent_def_id = tcx.parent(*def_id); - Some((tcx.associated_item_def_ids(parent_def_id).len(), of)) - } else { - None - } - } - } else { - None - }; - - // If the function is a tuple constructor, we recommend that they call it - if let Some((fields, kind)) = suggest { - suggest_call_constructor(expr.span, kind, fields, &mut err); - } else { - // General case - err.span_label( - expr.span, - "this is a function, perhaps you wish to call it", - ); - } - } + if let SelfSource::MethodCall(rcvr_expr) = source { + self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { + let call_expr = self + .tcx + .hir() + .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id)); + let probe = self.lookup_probe( + span, + item_name, + output_ty, + call_expr, + ProbeScope::AllTraits, + ); + probe.is_ok() + }); } let mut custom_span_label = false; @@ -560,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_spans.push((self.tcx.def_span(def.did()), msg)) } // Point at the trait object that couldn't satisfy the bound. - ty::Dynamic(preds, _) => { + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => bound_spans @@ -904,7 +881,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| { + let label_span_not_found = |err: &mut Diagnostic| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match actual.kind() { @@ -1000,7 +977,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(&mut err); } - self.check_for_field_method(&mut err, source, span, actual, item_name); + // Don't suggest (for example) `expr.field.method()` if `expr.method()` + // doesn't exist due to unsatisfied predicates. + if unsatisfied_predicates.is_empty() { + self.check_for_field_method(&mut err, source, span, actual, item_name); + } self.check_for_unwrap_self(&mut err, source, span, actual, item_name); @@ -1017,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_ty, item_name, - args.map(|args| args.len()), + args.map(|(_, args)| args.len() + 1), source, out_of_scope_traits, &unsatisfied_predicates, @@ -1062,19 +1043,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() { let def_kind = lev_candidate.kind.as_def_kind(); - err.span_suggestion( - span, - &format!( - "there is {} {} with a similar name", - def_kind.article(), - def_kind.descr(lev_candidate.def_id), - ), - lev_candidate.name, - Applicability::MaybeIncorrect, - ); + // Methods are defined within the context of a struct and their first parameter is always self, + // which represents the instance of the struct the method is being called on + // Associated functions don’t take self as a parameter and + // they are not methods because they don’t have an instance of the struct to work with. + if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter { + err.span_suggestion( + span, + &format!("there is a method with a similar name",), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion( + span, + &format!( + "there is {} {} with a similar name", + def_kind.article(), + def_kind.descr(lev_candidate.def_id), + ), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } } } + self.check_for_deref_method(&mut err, source, rcvr_ty, item_name); + return Some(err); } @@ -1150,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, expr: &hir::Expr<'_>, item_name: Ident, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, ) -> bool { let tcx = self.tcx; let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { @@ -1165,7 +1161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }); if let Some((field, field_ty)) = field_receiver { - let scope = tcx.parent_module(self.body_id).to_def_id(); + let scope = tcx.parent_module(self.body_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); if is_accessible { @@ -1282,7 +1278,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // local binding if let hir::def::Res::Local(hir_id) = path.res { let span = tcx.hir().span(hir_id); - let snippet = tcx.sess.source_map().span_to_snippet(span); let filename = tcx.sess.source_map().span_to_filename(span); let parent_node = @@ -1292,7 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { concrete_type, ); - match (filename, parent_node, snippet) { + match (filename, parent_node) { ( FileName::Real(_), Node::Local(hir::Local { @@ -1300,14 +1295,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty, .. }), - Ok(ref snippet), ) => { + let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi()); err.span_suggestion( // account for `let x: _ = 42;` - // ^^^^ - span.to(ty.as_ref().map(|ty| ty.span).unwrap_or(span)), + // ^^^ + type_span, &msg, - format!("{}: {}", snippet, concrete_type), + format!(": {concrete_type}"), Applicability::MaybeIncorrect, ); } @@ -1327,55 +1322,82 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_for_field_method( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, item_name: Ident, ) { if let SelfSource::MethodCall(expr) = source - && let Some((fields, substs)) = self.get_field_candidates(span, actual) + && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() + && let Some((fields, substs)) = + self.get_field_candidates_considering_privacy(span, actual, mod_id) { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); - for candidate_field in fields.iter() { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - &|_, field_ty| { - self.lookup_probe( - span, - item_name, - field_ty, - call_expr, - ProbeScope::AllTraits, - ) - .is_ok() - }, - candidate_field, - substs, - vec![], - self.tcx.parent_module(expr.hir_id).to_def_id(), - ) { - let field_path_str = field_path + + let lang_items = self.tcx.lang_items(); + let never_mention_traits = [ + lang_items.clone_trait(), + lang_items.deref_trait(), + lang_items.deref_mut_trait(), + self.tcx.get_diagnostic_item(sym::AsRef), + self.tcx.get_diagnostic_item(sym::AsMut), + self.tcx.get_diagnostic_item(sym::Borrow), + self.tcx.get_diagnostic_item(sym::BorrowMut), + ]; + let candidate_fields: Vec<_> = fields + .filter_map(|candidate_field| { + self.check_for_nested_field_satisfying( + span, + &|_, field_ty| { + self.lookup_probe( + span, + item_name, + field_ty, + call_expr, + ProbeScope::TraitsInScope, + ) + .map_or(false, |pick| { + !never_mention_traits + .iter() + .flatten() + .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id) + }) + }, + candidate_field, + substs, + vec![], + mod_id, + ) + }) + .map(|field_path| { + field_path .iter() .map(|id| id.name.to_ident_string()) .collect::>() - .join("."); - debug!("field_path_str: {:?}", field_path_str); - - err.span_suggestion_verbose( - item_name.span.shrink_to_lo(), - "one of the expressions' fields has a method of the same name", - format!("{field_path_str}."), - Applicability::MaybeIncorrect, - ); - } + .join(".") + }) + .collect(); + + let len = candidate_fields.len(); + if len > 0 { + err.span_suggestions( + item_name.span.shrink_to_lo(), + format!( + "{} of the expressions' fields {} a method of the same name", + if len > 1 { "some" } else { "one" }, + if len > 1 { "have" } else { "has" }, + ), + candidate_fields.iter().map(|path| format!("{path}.")), + Applicability::MaybeIncorrect, + ); } } } fn check_for_unwrap_self( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, @@ -1631,6 +1653,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_for_deref_method( + &self, + err: &mut Diagnostic, + self_source: SelfSource<'tcx>, + rcvr_ty: Ty<'tcx>, + item_name: Ident, + ) { + let SelfSource::QPath(ty) = self_source else { return; }; + for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) { + if let Ok(pick) = self.probe_for_name( + ty.span, + Mode::Path, + item_name, + IsSuggestion(true), + deref_ty, + ty.hir_id, + ProbeScope::TraitsInScope, + ) { + if deref_ty.is_suggestable(self.tcx, true) + // If this method receives `&self`, then the provided + // argument _should_ coerce, so it's valid to suggest + // just changing the path. + && pick.item.fn_has_self_parameter + && let Some(self_ty) = + self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0) + && self_ty.is_ref() + { + let suggested_path = match deref_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Str + | ty::Projection(_) + | ty::Param(_) => format!("{deref_ty}"), + _ => format!("<{deref_ty}>"), + }; + err.span_suggestion_verbose( + ty.span, + format!("the function `{item_name}` is implemented on `{deref_ty}`"), + suggested_path, + Applicability::MaybeIncorrect, + ); + } else { + err.span_note( + ty.span, + format!("the function `{item_name}` is implemented on `{deref_ty}`"), + ); + } + return; + } + } + } + /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { match ty.kind() { @@ -2232,7 +2310,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec { fn print_disambiguation_help<'tcx>( item_name: Ident, - args: Option<&'tcx [hir::Expr<'tcx>]>, + args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, @@ -2244,7 +2322,7 @@ fn print_disambiguation_help<'tcx>( fn_has_self_parameter: bool, ) { let mut applicability = Applicability::MachineApplicable; - let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { + let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) { let args = format!( "({}{})", if rcvr_ty.is_region_ptr() { @@ -2252,7 +2330,8 @@ fn print_disambiguation_help<'tcx>( } else { "" }, - args.iter() + std::iter::once(receiver) + .chain(args.iter()) .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { applicability = Applicability::HasPlaceholders; "_".to_owned() diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 17c2e4868..cfae63e4a 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -87,7 +87,6 @@ mod op; mod pat; mod place_op; mod region; -pub mod regionck; pub mod rvalue_scopes; mod upvar; pub mod wfcheck; @@ -97,14 +96,13 @@ use check::{check_abi, check_fn, check_mod_item_types}; pub use diverges::Diverges; pub use expectation::Expectation; pub use fn_ctxt::*; -use hir::def::CtorOf; pub use inherited::{Inherited, InheritedBuilder}; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan, + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::Res; @@ -112,7 +110,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; @@ -122,18 +119,20 @@ use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{self, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use std::cell::RefCell; +use std::num::NonZeroU32; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; use self::coercion::DynamicCoerceMany; +use self::compare_method::collect_trait_impl_trait_tys; use self::region::region_scope_tree; pub use self::Expectation::*; @@ -251,6 +250,7 @@ pub fn provide(providers: &mut Providers) { used_trait_imports, check_mod_item_types, region_scope_tree, + collect_trait_impl_trait_tys, ..*providers }; } @@ -343,7 +343,6 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T typeck_with_fallback(tcx, def_id, fallback) } -#[instrument(skip(tcx, fallback))] fn typeck_with_fallback<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, @@ -548,13 +547,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { // For the wasm32 target statics with `#[link_section]` are placed into custom // sections of the final output file, but this isn't link custom sections of // other executable formats. Namely we can only embed a list of bytes, - // nothing with pointers to anything else or relocations. If any relocation - // show up, reject them here. + // nothing with provenance (pointers to anything else). If any provenance + // show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) - && alloc.inner().relocations().len() != 0 + && alloc.inner().provenance().len() != 0 { let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ @@ -662,6 +661,37 @@ fn missing_items_must_implement_one_of_err( err.emit(); } +fn default_body_is_unstable( + tcx: TyCtxt<'_>, + impl_span: Span, + item_did: DefId, + feature: Symbol, + reason: Option, + issue: Option, +) { + let missing_item_name = &tcx.associated_item(item_did).name; + let use_of_unstable_library_feature_note = match reason { + Some(r) => format!("use of unstable library feature '{feature}': {r}"), + None => format!("use of unstable library feature '{feature}'"), + }; + + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0046, + "not all trait items implemented, missing: `{missing_item_name}`", + ); + err.note(format!("default implementation of `{missing_item_name}` is unstable")); + err.note(use_of_unstable_library_feature_note); + rustc_session::parse::add_feature_diagnostics_for_issue( + &mut err, + &tcx.sess.parse_sess, + feature, + rustc_feature::GateIssue::Library(issue), + ); + err.emit(); +} + /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, @@ -935,36 +965,3 @@ fn has_expected_num_generic_args<'tcx>( generics.count() == expected + if generics.has_self { 1 } else { 0 } }) } - -/// Suggests calling the constructor of a tuple struct or enum variant -/// -/// * `snippet` - The snippet of code that references the constructor -/// * `span` - The span of the snippet -/// * `params` - The number of parameters the constructor accepts -/// * `err` - A mutable diagnostic builder to add the suggestion to -fn suggest_call_constructor( - span: Span, - kind: CtorOf, - params: usize, - err: &mut DiagnosticBuilder<'_, G>, -) { - // Note: tuple-structs don't have named fields, so just use placeholders - let args = vec!["_"; params].join(", "); - let applicable = if params > 0 { - Applicability::HasPlaceholders - } else { - // When n = 0, it's an empty-tuple struct/enum variant - // so we trivially know how to construct it - Applicability::MachineApplicable - }; - let kind = match kind { - CtorOf::Struct => "a struct", - CtorOf::Variant => "an enum variant", - }; - err.span_label(span, &format!("this is the constructor of {kind}")); - err.multipart_suggestion( - "call the constructor", - vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))], - applicable, - ); -} diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 920b3e688..4754717c2 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -11,9 +11,8 @@ use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -22,8 +21,6 @@ use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; use rustc_type_ir::sty::TyKind::*; -use std::ops::ControlFlow; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` pub fn check_binop_assign( @@ -57,9 +54,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .is_ok() { - // Suppress this error, since we already emitted - // a deref suggestion in check_overloaded_binop - err.delay_as_bug(); + // If LHS += RHS is an error, but *LHS += RHS is successful, then we will have + // emitted a better suggestion during error handling in check_overloaded_binop. + if self + .lookup_op_method( + lhs_ty, + Some(rhs_ty), + Some(rhs), + Op::Binary(op, IsAssign::Yes), + expected, + ) + .is_err() + { + err.downgrade_to_delayed_bug(); + } else { + // Otherwise, it's valid to suggest dereferencing the LHS here. + err.span_suggestion_verbose( + lhs.span.shrink_to_lo(), + "consider dereferencing the left-hand side of this operation", + "*", + Applicability::MaybeIncorrect, + ); + } } } }); @@ -294,8 +310,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // error types are considered "builtin" Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { - let source_map = self.tcx.sess.source_map(); - let (mut err, missing_trait, use_output) = match is_assign { + let (_, trait_def_id) = + lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span); + let missing_trait = trait_def_id + .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id))); + let (mut err, output_def_id) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -309,130 +328,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), ); - let missing_trait = match op.node { - hir::BinOpKind::Add => Some("std::ops::AddAssign"), - hir::BinOpKind::Sub => Some("std::ops::SubAssign"), - hir::BinOpKind::Mul => Some("std::ops::MulAssign"), - hir::BinOpKind::Div => Some("std::ops::DivAssign"), - hir::BinOpKind::Rem => Some("std::ops::RemAssign"), - hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"), - hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"), - hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"), - hir::BinOpKind::Shl => Some("std::ops::ShlAssign"), - hir::BinOpKind::Shr => Some("std::ops::ShrAssign"), - _ => None, - }; self.note_unmet_impls_on_type(&mut err, errors); - (err, missing_trait, false) + (err, None) } IsAssign::No => { - let (message, missing_trait, use_output) = match op.node { - hir::BinOpKind::Add => ( - format!("cannot add `{rhs_ty}` to `{lhs_ty}`"), - Some("std::ops::Add"), - true, - ), - hir::BinOpKind::Sub => ( - format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`"), - Some("std::ops::Sub"), - true, - ), - hir::BinOpKind::Mul => ( - format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Mul"), - true, - ), - hir::BinOpKind::Div => ( - format!("cannot divide `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Div"), - true, - ), - hir::BinOpKind::Rem => ( - format!("cannot mod `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Rem"), - true, - ), - hir::BinOpKind::BitAnd => ( - format!("no implementation for `{lhs_ty} & {rhs_ty}`"), - Some("std::ops::BitAnd"), - true, - ), - hir::BinOpKind::BitXor => ( - format!("no implementation for `{lhs_ty} ^ {rhs_ty}`"), - Some("std::ops::BitXor"), - true, - ), - hir::BinOpKind::BitOr => ( - format!("no implementation for `{lhs_ty} | {rhs_ty}`"), - Some("std::ops::BitOr"), - true, - ), - hir::BinOpKind::Shl => ( - format!("no implementation for `{lhs_ty} << {rhs_ty}`"), - Some("std::ops::Shl"), - true, - ), - hir::BinOpKind::Shr => ( - format!("no implementation for `{lhs_ty} >> {rhs_ty}`"), - Some("std::ops::Shr"), - true, - ), - hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - Some("std::cmp::PartialEq"), - false, - ), - hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Gt - | hir::BinOpKind::Ge => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - Some("std::cmp::PartialOrd"), - false, - ), - _ => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - None, - false, + let message = match op.node { + hir::BinOpKind::Add => { + format!("cannot add `{rhs_ty}` to `{lhs_ty}`") + } + hir::BinOpKind::Sub => { + format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`") + } + hir::BinOpKind::Mul => { + format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::Div => { + format!("cannot divide `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::Rem => { + format!("cannot mod `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::BitAnd => { + format!("no implementation for `{lhs_ty} & {rhs_ty}`") + } + hir::BinOpKind::BitXor => { + format!("no implementation for `{lhs_ty} ^ {rhs_ty}`") + } + hir::BinOpKind::BitOr => { + format!("no implementation for `{lhs_ty} | {rhs_ty}`") + } + hir::BinOpKind::Shl => { + format!("no implementation for `{lhs_ty} << {rhs_ty}`") + } + hir::BinOpKind::Shr => { + format!("no implementation for `{lhs_ty} >> {rhs_ty}`") + } + _ => format!( + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty ), }; + let output_def_id = trait_def_id.and_then(|def_id| { + self.tcx + .associated_item_def_ids(def_id) + .iter() + .find(|item_def_id| { + self.tcx.associated_item(*item_def_id).name == sym::Output + }) + .cloned() + }); let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { - self.add_type_neq_err_label( - &mut err, - lhs_expr.span, - lhs_ty, - rhs_ty, - rhs_expr, - op, - is_assign, - expected, - ); - self.add_type_neq_err_label( - &mut err, - rhs_expr.span, - rhs_ty, - lhs_ty, - lhs_expr, - op, - is_assign, - expected, - ); + err.span_label(lhs_expr.span, lhs_ty.to_string()); + err.span_label(rhs_expr.span, rhs_ty.to_string()); } self.note_unmet_impls_on_type(&mut err, errors); - (err, missing_trait, use_output) + (err, output_def_id) } }; @@ -447,42 +399,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .is_ok() { - if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) { - let msg = &format!( - "`{}{}` can be used on `{}`, you can dereference `{}`", - op.node.as_str(), - match is_assign { - IsAssign::Yes => "=", - IsAssign::No => "", - }, - lhs_deref_ty.peel_refs(), - lstring, - ); - err.span_suggestion_verbose( - lhs_expr.span.shrink_to_lo(), - msg, - "*", - rustc_errors::Applicability::MachineApplicable, - ); - } + let msg = &format!( + "`{}{}` can be used on `{}` if you dereference the left-hand side", + op.node.as_str(), + match is_assign { + IsAssign::Yes => "=", + IsAssign::No => "", + }, + lhs_deref_ty, + ); + err.span_suggestion_verbose( + lhs_expr.span.shrink_to_lo(), + msg, + "*", + rustc_errors::Applicability::MachineApplicable, + ); } }; + let is_compatible = |lhs_ty, rhs_ty| { + self.lookup_op_method( + lhs_ty, + Some(rhs_ty), + Some(rhs_expr), + Op::Binary(op, is_assign), + expected, + ) + .is_ok() + }; + // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest // `a += b` => `*a += b` if a is a mut ref. - if is_assign == IsAssign::Yes - && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { - suggest_deref_binop(lhs_deref_ty); + if !op.span.can_be_used_for_suggestions() { + // Suppress suggestions when lhs and rhs are not in the same span as the error + } else if is_assign == IsAssign::Yes + && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) + { + suggest_deref_binop(lhs_deref_ty); } else if is_assign == IsAssign::No - && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() { - if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) { + && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() + { + if self.type_is_copy_modulo_regions( + self.param_env, + *lhs_deref_ty, + lhs_expr.span, + ) { suggest_deref_binop(*lhs_deref_ty); } + } else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| { + is_compatible(lhs_ty, rhs_ty) + }) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| { + is_compatible(lhs_ty, rhs_ty) + }) || self.suggest_two_fn_call( + &mut err, + rhs_expr, + rhs_ty, + lhs_expr, + lhs_ty, + |lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty), + ) { + // Cool } - if let Some(missing_trait) = missing_trait { - let mut visitor = TypeParamVisitor(vec![]); - visitor.visit_ty(lhs_ty); + if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && self.check_str_addition( lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op, @@ -491,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted - } else if let [ty] = &visitor.0[..] { + } else if lhs_ty.has_param_types_or_consts() { // Look for a TraitPredicate in the Fulfillment errors, // and use it to generate a suggestion. // @@ -513,12 +492,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(trait_pred) = error.obligation.predicate.to_opt_poly_trait_pred() { - let proj_pred = match error.obligation.cause.code() { + let output_associated_item = match error.obligation.cause.code() + { ObligationCauseCode::BinOp { - output_pred: Some(output_pred), + output_ty: Some(output_ty), .. - } if use_output => { - output_pred.to_opt_poly_projection_pred() + } => { + // Make sure that we're attaching `Output = ..` to the right trait predicate + if let Some(output_def_id) = output_def_id + && let Some(trait_def_id) = trait_def_id + && self.tcx.parent(output_def_id) == trait_def_id + { + Some(("Output", *output_ty)) + } else { + None + } } _ => None, }; @@ -526,12 +514,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_restricting_param_bound( &mut err, trait_pred, - proj_pred, + output_associated_item, self.body_id, ); } } - } else if *ty != lhs_ty { + } else { // When we know that a missing bound is responsible, we don't show // this note as it is redundant. err.note(&format!( @@ -548,69 +536,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (lhs_ty, rhs_ty, return_ty) } - /// If one of the types is an uncalled function and calling it would yield the other type, - /// suggest calling the function. Returns `true` if suggestion would apply (even if not given). - fn add_type_neq_err_label( - &self, - err: &mut Diagnostic, - span: Span, - ty: Ty<'tcx>, - other_ty: Ty<'tcx>, - other_expr: &'tcx hir::Expr<'tcx>, - op: hir::BinOp, - is_assign: IsAssign, - expected: Expectation<'tcx>, - ) -> bool /* did we suggest to call a function because of missing parentheses? */ { - err.span_label(span, ty.to_string()); - if let FnDef(def_id, _) = *ty.kind() { - if !self.tcx.has_typeck_results(def_id) { - return false; - } - // FIXME: Instead of exiting early when encountering bound vars in - // the function signature, consider keeping the binder here and - // propagating it downwards. - let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else { - return false; - }; - - let other_ty = if let FnDef(def_id, _) = *other_ty.kind() { - if !self.tcx.has_typeck_results(def_id) { - return false; - } - // We're emitting a suggestion, so we can just ignore regions - self.tcx.fn_sig(def_id).skip_binder().output() - } else { - other_ty - }; - - if self - .lookup_op_method( - fn_sig.output(), - Some(other_ty), - Some(other_expr), - Op::Binary(op, is_assign), - expected, - ) - .is_ok() - { - let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { - ("( /* arguments */ )", Applicability::HasPlaceholders) - } else { - ("()", Applicability::MaybeIncorrect) - }; - - err.span_suggestion_verbose( - span.shrink_to_hi(), - "you might have forgotten to call this function", - variable_snippet, - applicability, - ); - return true; - } - } - false - } - /// Provide actionable suggestions when trying to add two strings with incorrect types, /// like `&str + &str`, `String + String` and `&str + &String`. /// @@ -731,14 +656,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("cannot apply unary operator `{}`", op.as_str()), ); - let mut visitor = TypeParamVisitor(vec![]); - visitor.visit_ty(operand_ty); - if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() { - let predicates = errors - .iter() - .filter_map(|error| { - error.obligation.predicate.to_opt_poly_trait_pred() - }); + if operand_ty.has_param_types_or_consts() { + let predicates = errors.iter().filter_map(|error| { + error.obligation.predicate.to_opt_poly_trait_pred() + }); for pred in predicates { self.suggest_restricting_param_bound( &mut err, @@ -806,64 +727,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: Op, expected: Expectation<'tcx>, ) -> Result, Vec>> { - let lang = self.tcx.lang_items(); - let span = match op { Op::Binary(op, _) => op.span, Op::Unary(_, span) => span, }; - let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { - match op.node { - hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), - hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), - hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()), - hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()), - hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()), - hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()), - hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()), - hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()), - hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()), - hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()), - hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Ge - | hir::BinOpKind::Gt - | hir::BinOpKind::Eq - | hir::BinOpKind::Ne - | hir::BinOpKind::And - | hir::BinOpKind::Or => { - span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) - } - } - } else if let Op::Binary(op, IsAssign::No) = op { - match op.node { - hir::BinOpKind::Add => (sym::add, lang.add_trait()), - hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()), - hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()), - hir::BinOpKind::Div => (sym::div, lang.div_trait()), - hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()), - hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()), - hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()), - hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()), - hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()), - hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()), - hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()), - hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()), - hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()), - hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()), - hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()), - hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()), - hir::BinOpKind::And | hir::BinOpKind::Or => { - span_bug!(span, "&& and || are not overloadable") - } - } - } else if let Op::Unary(hir::UnOp::Not, _) = op { - (sym::not, lang.not_trait()) - } else if let Op::Unary(hir::UnOp::Neg, _) = op { - (sym::neg, lang.neg_trait()) - } else { - bug!("lookup_op_method: op not supported: {:?}", op) - }; + let (opname, trait_did) = lang_item_for_op(self.tcx, op, span); debug!( "lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", @@ -924,6 +792,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +fn lang_item_for_op( + tcx: TyCtxt<'_>, + op: Op, + span: Span, +) -> (rustc_span::Symbol, Option) { + let lang = tcx.lang_items(); + if let Op::Binary(op, IsAssign::Yes) = op { + match op.node { + hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), + hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), + hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()), + hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()), + hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()), + hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()), + hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()), + hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()), + hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()), + hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()), + hir::BinOpKind::Lt + | hir::BinOpKind::Le + | hir::BinOpKind::Ge + | hir::BinOpKind::Gt + | hir::BinOpKind::Eq + | hir::BinOpKind::Ne + | hir::BinOpKind::And + | hir::BinOpKind::Or => { + span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) + } + } + } else if let Op::Binary(op, IsAssign::No) = op { + match op.node { + hir::BinOpKind::Add => (sym::add, lang.add_trait()), + hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()), + hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()), + hir::BinOpKind::Div => (sym::div, lang.div_trait()), + hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()), + hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()), + hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()), + hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()), + hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()), + hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()), + hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()), + hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()), + hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()), + hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()), + hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()), + hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()), + hir::BinOpKind::And | hir::BinOpKind::Or => { + span_bug!(span, "&& and || are not overloadable") + } + } + } else if let Op::Unary(hir::UnOp::Not, _) = op { + (sym::not, lang.not_trait()) + } else if let Op::Unary(hir::UnOp::Neg, _) = op { + (sym::neg, lang.neg_trait()) + } else { + bug!("lookup_op_method: op not supported: {:?}", op) + } +} + // Binary operator categories. These categories summarize the behavior // with respect to the builtin operations supported. enum BinOpCategory { @@ -1046,17 +974,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool } } -struct TypeParamVisitor<'tcx>(Vec>); - -impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if let ty::Param(_) = ty.kind() { - self.0.push(ty); - } - ty.super_visit_with(self) - } -} - struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span); impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 837c32355..8906b622b 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { // Determine the binding mode... let bm = match ba { - hir::BindingAnnotation::Unannotated => def_bm, + hir::BindingAnnotation::NONE => def_bm, _ => BindingMode::convert(ba), }; // ...and store it in a side table: @@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { - self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti); + self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti); } if let Some(p) = sub { @@ -610,7 +610,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { local_ty } - fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) { + fn check_binding_alt_eq_ty( + &self, + ba: hir::BindingAnnotation, + span: Span, + var_id: HirId, + ty: Ty<'tcx>, + ti: TopInfo<'tcx>, + ) { let var_ty = self.local_ty(span, var_id).decl_ty; if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); @@ -628,12 +635,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let pre = if in_match { "in the same arm, " } else { "" }; err.note(&format!("{}a binding must have the same type in all alternatives", pre)); - // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing - // `ref` or `&` to the pattern. + self.suggest_adding_missing_ref_or_removing_ref( + &mut err, + span, + var_ty, + self.resolve_vars_with_obligations(ty), + ba, + ); err.emit(); } } + fn suggest_adding_missing_ref_or_removing_ref( + &self, + err: &mut Diagnostic, + span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ba: hir::BindingAnnotation, + ) { + match (expected.kind(), actual.kind(), ba) { + (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE) + if self.can_eq(self.param_env, *inner_ty, actual).is_ok() => + { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider adding `ref`", + "ref ", + Applicability::MaybeIncorrect, + ); + } + (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF) + if self.can_eq(self.param_env, expected, *inner_ty).is_ok() => + { + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(4)), + "consider removing `ref`", + "", + Applicability::MaybeIncorrect, + ); + } + _ => (), + } + } + // Precondition: pat is a Ref(_) pattern fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { let tcx = self.tcx; @@ -882,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); match self.tcx.hir().get(self.tcx.hir().get_parent_node(pat.hir_id)) { - hir::Node::Pat(Pat { kind: hir::PatKind::Struct(..), .. }) => { + hir::Node::PatField(..) => { e.span_suggestion_verbose( ident.span.shrink_to_hi(), "bind the struct field to a different name instead", @@ -936,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, qpath: &'tcx hir::QPath<'tcx>, subpats: &'tcx [Pat<'tcx>], - ddpos: Option, + ddpos: hir::DotDotPos, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, @@ -1021,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check subpatterns. if subpats.len() == variant.fields.len() - || subpats.len() < variant.fields.len() && ddpos.is_some() + || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some() { let ty::Adt(_, substs) = pat_ty.kind() else { bug!("unexpected pattern type {:?}", pat_ty); @@ -1209,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, elements: &'tcx [Pat<'tcx>], - ddpos: Option, + ddpos: hir::DotDotPos, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); - if ddpos.is_some() { + if ddpos.as_opt_usize().is_some() { // Require known type only when `..` is present. if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); @@ -1352,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .copied() .filter(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx) && !matches!( tcx.eval_stability(field.did, None, DUMMY_SP, None), EvalResult::Deny { .. } diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 0081e9049..b89db79be 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -126,6 +126,29 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h for (i, statement) in blk.stmts.iter().enumerate() { match statement.kind { + hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => { + // Let-else has a special lexical structure for variables. + // First we take a checkpoint of the current scope context here. + let mut prev_cx = visitor.cx; + + visitor.enter_scope(Scope { + id: blk.hir_id.local_id, + data: ScopeData::Remainder(FirstStatementIndex::new(i)), + }); + visitor.cx.var_parent = visitor.cx.parent; + visitor.visit_stmt(statement); + // We need to back out temporarily to the last enclosing scope + // for the `else` block, so that even the temporaries receiving + // extended lifetime will be dropped inside this block. + // We are visiting the `else` block in this order so that + // the sequence of visits agree with the order in the default + // `hir::intravisit` visitor. + mem::swap(&mut prev_cx, &mut visitor.cx); + visitor.terminating_scopes.insert(els.hir_id.local_id); + visitor.visit_block(els); + // From now on, we continue normally. + visitor.cx = prev_cx; + } hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => { // Each declaration introduces a subscope for bindings // introduced by the declaration; this subscope covers a @@ -138,10 +161,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; + visitor.visit_stmt(statement) } - hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } - visitor.visit_stmt(statement) } walk_list!(visitor, visit_expr, &blk.expr); } @@ -460,7 +483,6 @@ fn resolve_local<'tcx>( visitor: &mut RegionResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, - els: Option<&'tcx hir::Block<'tcx>>, ) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); @@ -547,9 +569,6 @@ fn resolve_local<'tcx>( if let Some(pat) = pat { visitor.visit_pat(pat); } - if let Some(els) = els { - visitor.visit_block(els); - } /// Returns `true` if `pat` match the `P&` non-terminal. /// @@ -587,8 +606,7 @@ fn resolve_local<'tcx>( // & expression, and its lifetime would be extended to the end of the block (due // to a different rule, not the below code). match pat.kind { - PatKind::Binding(hir::BindingAnnotation::Ref, ..) - | PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true, + PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true, PatKind::Struct(_, ref field_pats, _) => { field_pats.iter().any(|fp| is_binding_pat(&fp.pat)) @@ -607,10 +625,7 @@ fn resolve_local<'tcx>( PatKind::Box(ref subpat) => is_binding_pat(&subpat), PatKind::Ref(_, _) - | PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - .., - ) + | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) | PatKind::Wild | PatKind::Path(_) | PatKind::Lit(_) @@ -770,7 +785,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // (i.e., `'static`), which means that after `g` returns, it drops, // and all the associated destruction scope rules apply. self.cx.var_parent = None; - resolve_local(self, None, Some(&body.value), None); + resolve_local(self, None, Some(&body.value)); } if body.generator_kind.is_some() { @@ -797,7 +812,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_expr(self, ex); } fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init, l.els) + resolve_local(self, Some(&l.pat), l.init) } } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs deleted file mode 100644 index d49a6138f..000000000 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::outlives::outlives_bounds::InferCtxtExt as _; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::Ty; - -pub(crate) trait OutlivesEnvironmentExt<'tcx> { - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - fn_sig_tys: FxHashSet>, - body_id: hir::HirId, - ); -} - -impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` - #[instrument(level = "debug", skip(self, infcx))] - fn add_implied_bounds<'a>( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: FxHashSet>, - body_id: hir::HirId, - ) { - for ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } -} diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index dd8f943b9..0b207a6c0 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1217,7 +1217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Combine all the reasons of why the root variable should be captured as a result of // auto trait implementation issues - auto_trait_migration_reasons.extend(capture_trait_reasons.clone()); + auto_trait_migration_reasons.extend(capture_trait_reasons.iter().copied()); diagnostics_info.push(MigrationLintNote { captures_info, @@ -2024,6 +2024,10 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, ) -> bool { + if tcx.sess.rust_2021() { + return false; + } + let (level, _) = tcx.lint_level_at_node(lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_id); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index d0334cd0d..27b3da8ab 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,5 +1,5 @@ -use crate::check::regionck::OutlivesEnvironmentExt; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; +use hir::def::DefKind; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -10,7 +10,7 @@ use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::Normalized; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -23,9 +23,8 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::query::normalize::AtExt; -use rustc_trait_selection::traits::query::NoSolution; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; @@ -72,9 +71,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { ) { let cause = traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)); + // for a type to be WF, we do not need to check if const trait predicates satisfy. + let param_env = self.param_env.without_const(); self.ocx.register_obligation(traits::Obligation::new( cause, - self.param_env, + param_env, ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()), )); } @@ -86,26 +87,31 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( body_def_id: LocalDefId, f: F, ) where - F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> FxHashSet>, + F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), { let param_env = tcx.param_env(body_def_id); let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id); tcx.infer_ctxt().enter(|ref infcx| { let ocx = ObligationCtxt::new(infcx); + + let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id); + let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; if !tcx.features().trivial_bounds { wfcx.check_false_global_bounds() } - let wf_tys = f(&mut wfcx); + f(&mut wfcx); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); return; } - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(infcx, wf_tys, body_id); + let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); }) } @@ -383,7 +389,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe tcx, param_env, item_hir_id, - sig.output(), + sig.inputs_and_output, // We also assume that all of the function signature's parameter types // are well formed. &sig.inputs().iter().copied().collect(), @@ -658,7 +664,7 @@ fn ty_known_to_outlive<'tcx>( resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| { let origin = infer::RelateParamBound(DUMMY_SP, ty, None); let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env); - outlives.type_must_outlive(origin, ty, region); + outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation); }) } @@ -676,7 +682,12 @@ fn region_known_to_outlive<'tcx>( use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; let origin = infer::RelateRegionParamBound(DUMMY_SP); // `region_a: region_b` -> `region_b <= region_a` - infcx.push_sub_region_constraint(origin, region_b, region_a); + infcx.push_sub_region_constraint( + origin, + region_b, + region_a, + ConstraintCategory::BoringNoLocation, + ); }) } @@ -694,8 +705,11 @@ fn resolve_regions_with_wf_tys<'tcx>( // region constraints get added and solved there and we need to test each // call individually. tcx.infer_ctxt().enter(|infcx| { - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id); + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), + ); let region_bound_pairs = outlives_environment.region_bound_pairs(); add_constraints(&infcx, region_bound_pairs); @@ -761,7 +775,7 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { match ty.kind { hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { - [s] => s.res.and_then(|r| r.opt_def_id()) == Some(trait_def_id.to_def_id()), + [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), _ => false, }, _ => false, @@ -965,7 +979,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } -#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))] +#[instrument(level = "debug", skip(tcx, span, sig_if_method))] fn check_associated_item( tcx: TyCtxt<'_>, item_id: LocalDefId, @@ -976,15 +990,9 @@ fn check_associated_item( enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { let item = tcx.associated_item(item_id); - let (mut implied_bounds, self_ty) = match item.container { - ty::TraitContainer => (FxHashSet::default(), tcx.types.self_param), - ty::ImplContainer => { - let def_id = item.container_id(tcx); - ( - impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span), - tcx.type_of(def_id), - ) - } + let self_ty = match item.container { + ty::TraitContainer => tcx.types.self_param, + ty::ImplContainer => tcx.type_of(item.container_id(tcx)), }; match item.kind { @@ -1002,7 +1010,6 @@ fn check_associated_item( sig, hir_sig.decl, item.def_id.expect_local(), - &mut implied_bounds, ); check_method_receiver(wfcx, hir_sig, item, self_ty); } @@ -1017,8 +1024,6 @@ fn check_associated_item( } } } - - implied_bounds }) } @@ -1118,9 +1123,6 @@ fn check_type_defn<'tcx, F>( } check_where_clauses(wfcx, item.span, item.def_id); - - // No implied bounds in a struct definition. - FxHashSet::default() }); } @@ -1144,9 +1146,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { - check_where_clauses(wfcx, item.span, item.def_id); - - FxHashSet::default() + check_where_clauses(wfcx, item.span, item.def_id) }); // Only check traits, don't check trait aliases @@ -1186,9 +1186,7 @@ fn check_item_fn( ) { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id); - let mut implied_bounds = FxHashSet::default(); - check_fn_or_method(wfcx, ident.span, sig, decl, def_id, &mut implied_bounds); - implied_bounds + check_fn_or_method(wfcx, ident.span, sig, decl, def_id); }) } @@ -1231,13 +1229,10 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo tcx.require_lang_item(LangItem::Sync, Some(ty_span)), ); } - - // No implied bounds in a const, etc. - FxHashSet::default() }); } -#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] +#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, @@ -1274,7 +1269,11 @@ fn check_impl<'tcx>( } None => { let self_ty = tcx.type_of(item.def_id); - let self_ty = wfcx.normalize(item.span, None, self_ty); + let self_ty = wfcx.normalize( + item.span, + Some(WellFormedLoc::Ty(item.hir_id().expect_owner())), + self_ty, + ); wfcx.register_wf_obligation( ast_self_ty.span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner())), @@ -1284,8 +1283,6 @@ fn check_impl<'tcx>( } check_where_clauses(wfcx, item.span, item.def_id); - - impl_implied_bounds(tcx, wfcx.param_env, item.def_id, item.span) }); } @@ -1321,7 +1318,11 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { - wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into()); + wfcx.register_wf_obligation( + tcx.def_span(param.def_id), + Some(WellFormedLoc::Ty(param.def_id.expect_local())), + ty.into(), + ); } } } @@ -1465,21 +1466,26 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { - traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp) + traits::wf::predicate_obligations( + infcx, + wfcx.param_env.without_const(), + wfcx.body_id, + p, + sp, + ) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); } -#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))] +#[instrument(level = "debug", skip(wfcx, span, hir_decl))] fn check_fn_or_method<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: LocalDefId, - implied_bounds: &mut FxHashSet>, ) { let tcx = wfcx.tcx(); let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); @@ -1521,23 +1527,66 @@ fn check_fn_or_method<'tcx>( ); } - implied_bounds.extend(sig.inputs()); - - wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into()); + wfcx.register_wf_obligation( + hir_decl.output.span(), + Some(WellFormedLoc::Param { + function: def_id, + param_idx: sig.inputs().len().try_into().unwrap(), + }), + sig.output().into(), + ); - // FIXME(#27579) return types should not be implied bounds - implied_bounds.insert(sig.output()); + check_where_clauses(wfcx, span, def_id); - debug!(?implied_bounds); + check_return_position_impl_trait_in_trait_bounds( + tcx, + wfcx, + def_id, + sig.output(), + hir_decl.output.span(), + ); +} - check_where_clauses(wfcx, span, def_id); +/// Basically `check_associated_type_bounds`, but separated for now and should be +/// deduplicated when RPITITs get lowered into real associated items. +fn check_return_position_impl_trait_in_trait_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + wfcx: &WfCheckingCtxt<'_, 'tcx>, + fn_def_id: LocalDefId, + fn_output: Ty<'tcx>, + span: Span, +) { + if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) + && assoc_item.container == ty::AssocItemContainer::TraitContainer + { + for arg in fn_output.walk() { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Projection(proj) = ty.kind() + && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder + && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id() + { + let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id); + let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let normalized_bound = wfcx.normalize(span, None, bound); + traits::wf::predicate_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, + normalized_bound, + bound_span, + ) + }); + wfcx.register_obligations(wf_obligations); + } + } + } } const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ `self: Rc`, `self: Arc`, or `self: Pin

{ cross_thread: bool, marker: PhantomData

, @@ -167,7 +198,7 @@ where run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { - if self.cross_thread { + if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { >::new().run_bridge_and_client( dispatcher, input, @@ -190,6 +221,8 @@ impl ExecutionStrategy for SameThread { run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { + let _guard = RunningSameThreadGuard::new(); + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client(BridgeConfig { diff --git a/library/proc_macro/src/diagnostic.rs b/library/proc_macro/src/diagnostic.rs index 6e46dc036..5a209f7c7 100644 --- a/library/proc_macro/src/diagnostic.rs +++ b/library/proc_macro/src/diagnostic.rs @@ -161,22 +161,15 @@ impl Diagnostic { /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn emit(self) { - fn to_internal(spans: Vec) -> crate::bridge::client::MultiSpan { - let mut multi_span = crate::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); + fn to_internal(diag: Diagnostic) -> crate::bridge::Diagnostic { + crate::bridge::Diagnostic { + level: diag.level, + message: diag.message, + spans: diag.spans.into_iter().map(|s| s.0).collect(), + children: diag.children.into_iter().map(to_internal).collect(), } - multi_span } - let mut diag = crate::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); + crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self)); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 8e478cd7b..495c1c5ae 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1353,12 +1353,7 @@ impl Literal { /// Byte string literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn byte_string(bytes: &[u8]) -> Literal { - let string = bytes - .iter() - .cloned() - .flat_map(std::ascii::escape_default) - .map(Into::::into) - .collect::(); + let string = bytes.escape_ascii().to_string(); Literal::new(bridge::LitKind::ByteStr, &string, None) } diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index c6a4548ec..1df0c8970 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -35,6 +35,16 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } +// Frame unwind info registration +// +// Each module's image contains a frame unwind info section (usually +// ".eh_frame"). When a module is loaded/unloaded into the process, the +// unwinder must be informed about the location of this section in memory. The +// methods of achieving that vary by the platform. On some (e.g., Linux), the +// unwinder can discover unwind info sections on its own (by dynamically +// enumerating currently loaded modules via the dl_iterate_phdr() API and +// finding their ".eh_frame" sections); Others, like Windows, require modules +// to actively register their unwind info sections via unwinder API. #[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] pub mod eh_frames { #[no_mangle] @@ -62,20 +72,19 @@ pub mod eh_frames { } // Unwind info registration/deregistration routines. - // See the docs of libpanic_unwind. extern "C" { - fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8); - fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8); + fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8); + fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8); } unsafe extern "C" fn init() { // register unwind info on module startup - rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); + __register_frame_info(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); } unsafe extern "C" fn uninit() { // unregister on shutdown - rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); + __deregister_frame_info(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); } // MinGW-specific init/uninit routine registration diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 229e546e0..324ecc804 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -39,10 +39,10 @@ rand = "0.7" dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] -fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } +fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] } [target.'cfg(target_os = "hermit")'.dependencies] -hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index a05e0db3a..61c1ff578 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -68,7 +68,10 @@ pub use alloc_crate::alloc::*; /// The default memory allocator provided by the operating system. /// /// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, -/// plus related functions. +/// plus related functions. However, it is not valid to mix use of the backing +/// system allocator with `System`, as this implementation may include extra +/// work, such as to serve alignment requests greater than the alignment +/// provided directly by the backing system allocator. /// /// This type implements the `GlobalAlloc` trait and Rust programs by default /// work as if they had this definition: diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 05e9b2eb6..5cf6ec817 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -9,12 +9,6 @@ //! implementing `std::error::Error`) to get a causal chain of where an error //! was generated. //! -//! > **Note**: this module is unstable and is designed in [RFC 2504], and you -//! > can learn more about its status in the [tracking issue]. -//! -//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md -//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487 -//! //! ## Accuracy //! //! Backtraces are attempted to be as accurate as possible, but no guarantees @@ -64,7 +58,7 @@ //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change //! how backtraces are captured. -#![unstable(feature = "backtrace", issue = "53487")] +#![stable(feature = "backtrace", since = "1.65.0")] #[cfg(test)] mod tests; @@ -110,6 +104,7 @@ use crate::vec::Vec; /// previous point in time. In some instances the `Backtrace` type may /// internally be empty due to configuration. For more information see /// `Backtrace::capture`. +#[stable(feature = "backtrace", since = "1.65.0")] #[must_use] pub struct Backtrace { inner: Inner, @@ -117,17 +112,21 @@ pub struct Backtrace { /// The current status of a backtrace, indicating whether it was captured or /// whether it is empty for some other reason. +#[stable(feature = "backtrace", since = "1.65.0")] #[non_exhaustive] #[derive(Debug, PartialEq, Eq)] pub enum BacktraceStatus { /// Capturing a backtrace is not supported, likely because it's not /// implemented for the current platform. + #[stable(feature = "backtrace", since = "1.65.0")] Unsupported, /// Capturing a backtrace has been disabled through either the /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. + #[stable(feature = "backtrace", since = "1.65.0")] Disabled, /// A backtrace has been captured and the `Backtrace` should print /// reasonable information when rendered. + #[stable(feature = "backtrace", since = "1.65.0")] Captured, } @@ -174,6 +173,7 @@ enum BytesOrWide { Wide(Vec), } +#[stable(feature = "backtrace", since = "1.65.0")] impl fmt::Debug for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let capture = match &self.inner { @@ -200,6 +200,7 @@ impl fmt::Debug for Backtrace { } } +#[unstable(feature = "backtrace_frames", issue = "79676")] impl fmt::Debug for BacktraceFrame { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut dbg = fmt.debug_list(); @@ -288,6 +289,7 @@ impl Backtrace { /// /// To forcibly capture a backtrace regardless of environment variables, use /// the `Backtrace::force_capture` function. + #[stable(feature = "backtrace", since = "1.65.0")] #[inline(never)] // want to make sure there's a frame here to remove pub fn capture() -> Backtrace { if !Backtrace::enabled() { @@ -306,6 +308,7 @@ impl Backtrace { /// Note that capturing a backtrace can be an expensive operation on some /// platforms, so this should be used with caution in performance-sensitive /// parts of code. + #[stable(feature = "backtrace", since = "1.65.0")] #[inline(never)] // want to make sure there's a frame here to remove pub fn force_capture() -> Backtrace { Backtrace::create(Backtrace::force_capture as usize) @@ -313,6 +316,8 @@ impl Backtrace { /// Forcibly captures a disabled backtrace, regardless of environment /// variable configuration. + #[stable(feature = "backtrace", since = "1.65.0")] + #[rustc_const_stable(feature = "backtrace", since = "1.65.0")] pub const fn disabled() -> Backtrace { Backtrace { inner: Inner::Disabled } } @@ -356,6 +361,7 @@ impl Backtrace { /// Returns the status of this backtrace, indicating whether this backtrace /// request was unsupported, disabled, or a stack trace was actually /// captured. + #[stable(feature = "backtrace", since = "1.65.0")] #[must_use] pub fn status(&self) -> BacktraceStatus { match self.inner { @@ -375,6 +381,7 @@ impl<'a> Backtrace { } } +#[stable(feature = "backtrace", since = "1.65.0")] impl fmt::Display for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let capture = match &self.inner { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index db811343f..9845d1faf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -9,6 +9,8 @@ use crate::borrow::Borrow; use crate::cell::Cell; use crate::collections::TryReserveError; use crate::collections::TryReserveErrorKind; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -2158,6 +2160,15 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> { + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 7ebc41588..cb3032719 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -268,10 +268,13 @@ fn test_lots_of_insertions() { // Try this a few times to make sure we never screw up the hashmap's // internal state. - for _ in 0..10 { + let loops = if cfg!(miri) { 2 } else { 10 }; + for _ in 0..loops { assert!(m.is_empty()); - for i in 1..1001 { + let count = if cfg!(miri) { 101 } else { 1001 }; + + for i in 1..count { assert!(m.insert(i, i).is_none()); for j in 1..=i { @@ -279,42 +282,42 @@ fn test_lots_of_insertions() { assert_eq!(r, Some(&j)); } - for j in i + 1..1001 { + for j in i + 1..count { let r = m.get(&j); assert_eq!(r, None); } } - for i in 1001..2001 { + for i in count..(2 * count) { assert!(!m.contains_key(&i)); } // remove forwards - for i in 1..1001 { + for i in 1..count { assert!(m.remove(&i).is_some()); for j in 1..=i { assert!(!m.contains_key(&j)); } - for j in i + 1..1001 { + for j in i + 1..count { assert!(m.contains_key(&j)); } } - for i in 1..1001 { + for i in 1..count { assert!(!m.contains_key(&i)); } - for i in 1..1001 { + for i in 1..count { assert!(m.insert(i, i).is_none()); } // remove backwards - for i in (1..1001).rev() { + for i in (1..count).rev() { assert!(m.remove(&i).is_some()); - for j in i..1001 { + for j in i..count { assert!(!m.contains_key(&j)); } @@ -817,6 +820,7 @@ fn test_retain() { } #[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc fn test_try_reserve() { let mut empty_bytes: HashMap = HashMap::new(); diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index abff82788..5b6a415fa 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -239,7 +239,7 @@ impl HashSet { /// /// If the returned iterator is dropped before being fully consumed, it /// drops the remaining elements. The returned iterator keeps a mutable - /// borrow on the vector to optimize its implementation. + /// borrow on the set to optimize its implementation. /// /// # Examples /// diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 722df119d..e45059595 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1,175 +1,51 @@ -//! Interfaces for working with Errors. -//! -//! # Error Handling In Rust -//! -//! The Rust language provides two complementary systems for constructing / -//! representing, reporting, propagating, reacting to, and discarding errors. -//! These responsibilities are collectively known as "error handling." The -//! components of the first system, the panic runtime and interfaces, are most -//! commonly used to represent bugs that have been detected in your program. The -//! components of the second system, `Result`, the error traits, and user -//! defined types, are used to represent anticipated runtime failure modes of -//! your program. -//! -//! ## The Panic Interfaces -//! -//! The following are the primary interfaces of the panic system and the -//! responsibilities they cover: -//! -//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) -//! * [`PanicInfo`] (Reporting) -//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) -//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) -//! -//! The following are the primary interfaces of the error system and the -//! responsibilities they cover: -//! -//! * [`Result`] (Propagating, Reacting) -//! * The [`Error`] trait (Reporting) -//! * User defined types (Constructing / Representing) -//! * [`match`] and [`downcast`] (Reacting) -//! * The question mark operator ([`?`]) (Propagating) -//! * The partially stable [`Try`] traits (Propagating, Constructing) -//! * [`Termination`] (Reporting) -//! -//! ## Converting Errors into Panics -//! -//! The panic and error systems are not entirely distinct. Often times errors -//! that are anticipated runtime failures in an API might instead represent bugs -//! to a caller. For these situations the standard library provides APIs for -//! constructing panics with an `Error` as it's source. -//! -//! * [`Result::unwrap`] -//! * [`Result::expect`] -//! -//! These functions are equivalent, they either return the inner value if the -//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error -//! as the source. The only difference between them is that with `expect` you -//! provide a panic error message to be printed alongside the source, whereas -//! `unwrap` has a default message indicating only that you unwraped an `Err`. -//! -//! Of the two, `expect` is generally preferred since its `msg` field allows you -//! to convey your intent and assumptions which makes tracking down the source -//! of a panic easier. `unwrap` on the other hand can still be a good fit in -//! situations where you can trivially show that a piece of code will never -//! panic, such as `"127.0.0.1".parse::().unwrap()` or early -//! prototyping. -//! -//! # Common Message Styles -//! -//! There are two common styles for how people word `expect` messages. Using -//! the message to present information to users encountering a panic -//! ("expect as error message") or using the message to present information -//! to developers debugging the panic ("expect as precondition"). -//! -//! In the former case the expect message is used to describe the error that -//! has occurred which is considered a bug. Consider the following example: -//! -//! ```should_panic -//! // Read environment variable, panic if it is not present -//! let path = std::env::var("IMPORTANT_PATH").unwrap(); -//! ``` -//! -//! In the "expect as error message" style we would use expect to describe -//! that the environment variable was not set when it should have been: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` is not set"); -//! ``` -//! -//! In the "expect as precondition" style, we would instead describe the -//! reason we _expect_ the `Result` should be `Ok`. With this style we would -//! prefer to write: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); -//! ``` -//! -//! The "expect as error message" style does not work as well with the -//! default output of the std panic hooks, and often ends up repeating -//! information that is already communicated by the source error being -//! unwrapped: -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we end up mentioning that an env variable is not set, -//! followed by our source message that says the env is not present, the -//! only additional information we're communicating is the name of the -//! environment variable being checked. -//! -//! The "expect as precondition" style instead focuses on source code -//! readability, making it easier to understand what must have gone wrong in -//! situations where panics are being used to represent bugs exclusively. -//! Also, by framing our expect in terms of what "SHOULD" have happened to -//! prevent the source error, we end up introducing new information that is -//! independent from our source error. -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we are communicating not only the name of the -//! environment variable that should have been set, but also an explanation -//! for why it should have been set, and we let the source error display as -//! a clear contradiction to our expectation. -//! -//! **Hint**: If you're having trouble remembering how to phrase -//! expect-as-precondition style error messages remember to focus on the word -//! "should" as in "env variable should be set by blah" or "the given binary -//! should be available and executable by the current user". -//! -//! [`panic_any`]: crate::panic::panic_any -//! [`PanicInfo`]: crate::panic::PanicInfo -//! [`catch_unwind`]: crate::panic::catch_unwind -//! [`resume_unwind`]: crate::panic::resume_unwind -//! [`downcast`]: crate::error::Error -//! [`Termination`]: crate::process::Termination -//! [`Try`]: crate::ops::Try -//! [panic hook]: crate::panic::set_hook -//! [`set_hook`]: crate::panic::set_hook -//! [`take_hook`]: crate::panic::take_hook -//! [panic-handler]: -//! [`match`]: ../../std/keyword.match.html -//! [`?`]: ../../std/result/index.html#the-question-mark-operator- - +#![doc = include_str!("../../core/src/error.md")] #![stable(feature = "rust1", since = "1.0.0")] -// A note about crates and the facade: -// -// Originally, the `Error` trait was defined in libcore, and the impls -// were scattered about. However, coherence objected to this -// arrangement, because to create the blanket impls for `Box` required -// knowing that `&str: !Error`, and we have no means to deal with that -// sort of conflict just now. Therefore, for the time being, we have -// moved the `Error` trait into libstd. As we evolve a sol'n to the -// coherence challenge (e.g., specialization, neg impls, etc) we can -// reconsider what crate these items belong in. - #[cfg(test)] mod tests; +#[cfg(bootstrap)] use core::array; +#[cfg(bootstrap)] use core::convert::Infallible; +#[cfg(bootstrap)] use crate::alloc::{AllocError, LayoutError}; -use crate::any::{Demand, Provider, TypeId}; +#[cfg(bootstrap)] +use crate::any::Demand; +#[cfg(bootstrap)] +use crate::any::{Provider, TypeId}; use crate::backtrace::Backtrace; +#[cfg(bootstrap)] use crate::borrow::Cow; +#[cfg(bootstrap)] use crate::cell; +#[cfg(bootstrap)] use crate::char; -use crate::fmt::{self, Debug, Display, Write}; +#[cfg(bootstrap)] +use crate::fmt::Debug; +#[cfg(bootstrap)] +use crate::fmt::Display; +use crate::fmt::{self, Write}; +#[cfg(bootstrap)] use crate::io; +#[cfg(bootstrap)] use crate::mem::transmute; +#[cfg(bootstrap)] use crate::num; +#[cfg(bootstrap)] use crate::str; +#[cfg(bootstrap)] use crate::string; +#[cfg(bootstrap)] use crate::sync::Arc; +#[cfg(bootstrap)] use crate::time; +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::error::Error; + /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. /// @@ -182,14 +58,15 @@ use crate::time; /// assert_eq!(err.to_string(), "invalid digit found in string"); /// ``` /// -/// Errors may provide cause chain information. [`Error::source()`] is generally +/// Errors may provide cause information. [`Error::source()`] is generally /// used when errors cross "abstraction boundaries". If one module must report /// an error that is caused by an error from a lower-level module, it can allow /// accessing that error via [`Error::source()`]. This makes it possible for the /// high-level module to provide its own errors while also revealing some of the -/// implementation for debugging via `source` chains. +/// implementation for debugging. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[cfg(bootstrap)] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// @@ -333,8 +210,8 @@ pub trait Error: Debug + Display { /// } /// /// impl std::error::Error for Error { - /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { - /// req + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand /// .provide_ref::(&self.backtrace) /// .provide_ref::(&self.source); /// } @@ -352,13 +229,14 @@ pub trait Error: Debug + Display { /// ``` #[unstable(feature = "error_generic_member_access", issue = "99301")] #[allow(unused_variables)] - fn provide<'a>(&'a self, req: &mut Demand<'a>) {} + fn provide<'a>(&'a self, demand: &mut Demand<'a>) {} } +#[cfg(bootstrap)] #[unstable(feature = "error_generic_member_access", issue = "99301")] impl<'b> Provider for dyn Error + 'b { - fn provide<'a>(&'a self, req: &mut Demand<'a>) { - self.provide(req) + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.provide(demand) } } @@ -370,6 +248,7 @@ mod private { pub struct Internal; } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. @@ -402,6 +281,7 @@ impl<'a, E: Error + 'a> From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From for Box { /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of @@ -440,6 +320,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -483,6 +364,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. @@ -504,6 +386,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -527,6 +410,7 @@ impl<'a> From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. @@ -548,6 +432,7 @@ impl From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -569,6 +454,7 @@ impl<'a, 'b> From> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. @@ -589,9 +475,11 @@ impl<'a> From> for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "never_type", issue = "35121")] impl Error for ! {} +#[cfg(bootstrap)] #[unstable( feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", @@ -599,9 +487,11 @@ impl Error for ! {} )] impl Error for AllocError {} +#[cfg(bootstrap)] #[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { #[allow(deprecated)] @@ -610,6 +500,7 @@ impl Error for str::ParseBoolError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::Utf8Error { #[allow(deprecated)] @@ -618,6 +509,7 @@ impl Error for str::Utf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseIntError { #[allow(deprecated)] @@ -626,6 +518,7 @@ impl Error for num::ParseIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for num::TryFromIntError { #[allow(deprecated)] @@ -634,6 +527,7 @@ impl Error for num::TryFromIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for array::TryFromSliceError { #[allow(deprecated)] @@ -642,6 +536,7 @@ impl Error for array::TryFromSliceError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseFloatError { #[allow(deprecated)] @@ -650,6 +545,7 @@ impl Error for num::ParseFloatError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf8Error { #[allow(deprecated)] @@ -658,6 +554,7 @@ impl Error for string::FromUtf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf16Error { #[allow(deprecated)] @@ -666,6 +563,7 @@ impl Error for string::FromUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "str_parse_error2", since = "1.8.0")] impl Error for Infallible { fn description(&self) -> &str { @@ -673,6 +571,7 @@ impl Error for Infallible { } } +#[cfg(bootstrap)] #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { #[allow(deprecated)] @@ -681,9 +580,11 @@ impl Error for char::DecodeUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "u8_from_char", since = "1.59.0")] impl Error for char::TryFromCharError {} +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug + Ord, V: Debug> Error for crate::collections::btree_map::OccupiedError<'a, K, V> @@ -694,6 +595,7 @@ impl<'a, K: Debug + Ord, V: Debug> Error } } +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> { #[allow(deprecated)] @@ -702,6 +604,7 @@ impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedErr } } +#[cfg(bootstrap)] #[stable(feature = "box_error", since = "1.8.0")] impl Error for Box { #[allow(deprecated, deprecated_in_future)] @@ -719,6 +622,7 @@ impl Error for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "thin_box", issue = "92791")] impl crate::error::Error for crate::boxed::ThinBox { fn source(&self) -> Option<&(dyn crate::error::Error + 'static)> { @@ -727,6 +631,7 @@ impl crate::error::Error for crate::boxed::Thin } } +#[cfg(bootstrap)] #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { #[allow(deprecated, deprecated_in_future)] @@ -743,11 +648,12 @@ impl<'a, T: Error + ?Sized> Error for &'a T { Error::source(&**self) } - fn provide<'b>(&'b self, req: &mut Demand<'b>) { - Error::provide(&**self, req); + fn provide<'b>(&'b self, demand: &mut Demand<'b>) { + Error::provide(&**self, demand); } } +#[cfg(bootstrap)] #[stable(feature = "arc_error", since = "1.52.0")] impl Error for Arc { #[allow(deprecated, deprecated_in_future)] @@ -764,11 +670,12 @@ impl Error for Arc { Error::source(&**self) } - fn provide<'a>(&'a self, req: &mut Demand<'a>) { - Error::provide(&**self, req); + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + Error::provide(&**self, demand); } } +#[cfg(bootstrap)] #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] @@ -777,6 +684,7 @@ impl Error for fmt::Error { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowError { #[allow(deprecated)] @@ -785,6 +693,7 @@ impl Error for cell::BorrowError { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowMutError { #[allow(deprecated)] @@ -793,6 +702,7 @@ impl Error for cell::BorrowMutError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for char::CharTryFromError { #[allow(deprecated)] @@ -801,6 +711,7 @@ impl Error for char::CharTryFromError { } } +#[cfg(bootstrap)] #[stable(feature = "char_from_str", since = "1.20.0")] impl Error for char::ParseCharError { #[allow(deprecated)] @@ -809,12 +720,15 @@ impl Error for char::ParseCharError { } } +#[cfg(bootstrap)] #[stable(feature = "try_reserve", since = "1.57.0")] impl Error for alloc::collections::TryReserveError {} +#[cfg(bootstrap)] #[unstable(feature = "duration_checked_float", issue = "83400")] impl Error for time::FromFloatSecsError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for alloc::ffi::NulError { #[allow(deprecated)] @@ -823,6 +737,7 @@ impl Error for alloc::ffi::NulError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl From for io::Error { /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`]. @@ -831,6 +746,7 @@ impl From for io::Error { } } +#[cfg(bootstrap)] #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for core::ffi::FromBytesWithNulError { #[allow(deprecated)] @@ -839,12 +755,15 @@ impl Error for core::ffi::FromBytesWithNulError { } } +#[cfg(bootstrap)] #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] impl Error for core::ffi::FromBytesUntilNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl Error for alloc::ffi::FromVecWithNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_into", since = "1.7.0")] impl Error for alloc::ffi::IntoStringError { #[allow(deprecated)] @@ -857,6 +776,7 @@ impl Error for alloc::ffi::IntoStringError { } } +#[cfg(bootstrap)] impl<'a> dyn Error + 'a { /// Request a reference of type `T` as context about this error. #[unstable(feature = "error_generic_member_access", issue = "99301")] @@ -872,6 +792,7 @@ impl<'a> dyn Error + 'a { } // Copied from `any.rs`. +#[cfg(bootstrap)] impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -912,6 +833,7 @@ impl dyn Error + 'static { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -947,6 +869,7 @@ impl dyn Error + 'static + Send { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -982,6 +905,7 @@ impl dyn Error + 'static + Send + Sync { } } +#[cfg(bootstrap)] impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1041,7 +965,7 @@ impl dyn Error { /// // let err : Box = b.into(); // or /// let err = &b as &(dyn Error); /// - /// let mut iter = err.chain(); + /// let mut iter = err.sources(); /// /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); @@ -1050,8 +974,19 @@ impl dyn Error { /// ``` #[unstable(feature = "error_iter", issue = "58520")] #[inline] - pub fn chain(&self) -> Chain<'_> { - Chain { current: Some(self) } + pub fn sources(&self) -> Sources<'_> { + // You may think this method would be better in the Error trait, and you'd be right. + // Unfortunately that doesn't work, not because of the object safety rules but because we + // save a reference to self in Sources below as a trait object. If this method was + // declared in Error, then self would have the type &T where T is some concrete type which + // implements Error. We would need to coerce self to have type &dyn Error, but that requires + // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error + // since that would forbid Error trait objects, and we can't put that bound on the method + // because that means the method can't be called on trait objects (we'd also need the + // 'static bound, but that isn't allowed because methods with bounds on Self other than + // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible. + + Sources { current: Some(self) } } } @@ -1061,12 +996,14 @@ impl dyn Error { /// its sources, use `skip(1)`. #[unstable(feature = "error_iter", issue = "58520")] #[derive(Clone, Debug)] -pub struct Chain<'a> { +#[cfg(bootstrap)] +pub struct Sources<'a> { current: Option<&'a (dyn Error + 'static)>, } +#[cfg(bootstrap)] #[unstable(feature = "error_iter", issue = "58520")] -impl<'a> Iterator for Chain<'a> { +impl<'a> Iterator for Sources<'a> { type Item = &'a (dyn Error + 'static); fn next(&mut self) -> Option { @@ -1076,6 +1013,7 @@ impl<'a> Iterator for Chain<'a> { } } +#[cfg(bootstrap)] impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1089,6 +1027,7 @@ impl dyn Error + Send { } } +#[cfg(bootstrap)] impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1104,8 +1043,8 @@ impl dyn Error + Send + Sync { /// An error reporter that prints an error and its sources. /// -/// Report also exposes configuration options for formatting the error chain, either entirely on a -/// single line, or in multi-line format with each cause in the error chain on a new line. +/// Report also exposes configuration options for formatting the error sources, either entirely on a +/// single line, or in multi-line format with each source on a new line. /// /// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the /// wrapped error be `Send`, `Sync`, or `'static`. @@ -1246,7 +1185,7 @@ impl dyn Error + Send + Sync { /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn main() -> Result<(), Report> { /// get_super_error()?; /// Ok(()) /// } @@ -1293,7 +1232,7 @@ impl dyn Error + Send + Sync { /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn main() -> Result<(), Report> { /// get_super_error() /// .map_err(Report::from) /// .map_err(|r| r.pretty(true).show_backtrace(true))?; @@ -1450,11 +1389,10 @@ impl Report { /// /// **Note**: Report will search for the first `Backtrace` it can find starting from the /// outermost error. In this example it will display the backtrace from the second error in the - /// chain, `SuperErrorSideKick`. + /// sources, `SuperErrorSideKick`. /// /// ```rust /// #![feature(error_reporter)] - /// #![feature(backtrace)] /// #![feature(provide_any)] /// #![feature(error_generic_member_access)] /// # use std::error::Error; @@ -1489,9 +1427,8 @@ impl Report { /// } /// /// impl Error for SuperErrorSideKick { - /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { - /// req - /// .provide_ref::(&self.backtrace); + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand.provide_ref::(&self.backtrace); /// } /// } /// @@ -1548,7 +1485,7 @@ where let backtrace = backtrace.or_else(|| { self.error .source() - .map(|source| source.chain().find_map(|source| source.request_ref())) + .map(|source| source.sources().find_map(|source| source.request_ref())) .flatten() }); backtrace @@ -1559,7 +1496,7 @@ where fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.error)?; - let sources = self.error.source().into_iter().flat_map(::chain); + let sources = self.error.source().into_iter().flat_map(::sources); for cause in sources { write!(f, ": {cause}")?; @@ -1580,73 +1517,7 @@ where let multiple = cause.source().is_some(); - for (ind, error) in cause.chain().enumerate() { - writeln!(f)?; - let mut indented = Indented { inner: f }; - if multiple { - write!(indented, "{ind: >4}: {error}")?; - } else { - write!(indented, " {error}")?; - } - } - } - - if self.show_backtrace { - let backtrace = self.backtrace(); - - if let Some(backtrace) = backtrace { - let backtrace = backtrace.to_string(); - - f.write_str("\n\nStack backtrace:\n")?; - f.write_str(backtrace.trim_end())?; - } - } - - Ok(()) - } -} - -impl Report> { - fn backtrace(&self) -> Option<&Backtrace> { - // have to grab the backtrace on the first error directly since that error may not be - // 'static - let backtrace = self.error.request_ref(); - let backtrace = backtrace.or_else(|| { - self.error - .source() - .map(|source| source.chain().find_map(|source| source.request_ref())) - .flatten() - }); - backtrace - } - - /// Format the report as a single line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.error)?; - - let sources = self.error.source().into_iter().flat_map(::chain); - - for cause in sources { - write!(f, ": {cause}")?; - } - - Ok(()) - } - - /// Format the report as multiple lines, with each error cause on its own line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error = &self.error; - - write!(f, "{error}")?; - - if let Some(cause) = error.source() { - write!(f, "\n\nCaused by:")?; - - let multiple = cause.source().is_some(); - - for (ind, error) in cause.chain().enumerate() { + for (ind, error) in cause.sources().enumerate() { writeln!(f)?; let mut indented = Indented { inner: f }; if multiple { @@ -1682,17 +1553,6 @@ where } } -#[unstable(feature = "error_reporter", issue = "90172")] -impl<'a, E> From for Report> -where - E: Error + 'a, -{ - fn from(error: E) -> Self { - let error = box error; - Report { error, show_backtrace: false, pretty: false } - } -} - #[unstable(feature = "error_reporter", issue = "90172")] impl fmt::Display for Report where @@ -1703,13 +1563,6 @@ where } } -#[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Display for Report> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } - } -} - // This type intentionally outputs the same format for `Display` and `Debug`for // situations where you unwrap a `Report` or return it from main. #[unstable(feature = "error_reporter", issue = "90172")] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 933b52b4d..3dd5b1250 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f32` single-precision floating point type. +//! Constants for the `f32` single-precision floating point type. //! //! *[See also the `f32` primitive type](primitive@f32).* //! diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 69fa203ff..4ec16c84a 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -299,6 +299,84 @@ fn test_is_sign_negative() { assert!((-f32::NAN).is_sign_negative()); } +#[allow(unused_macros)] +macro_rules! assert_f32_biteq { + ($left : expr, $right : expr) => { + let l: &f32 = &$left; + let r: &f32 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {} ({:#x}) is not equal to {} ({:#x})", *l, lb, *r, rb); + }; +} + +// Ignore test on x87 floating point, these platforms do not guarantee NaN +// payloads are preserved and flush denormals to zero, failing the tests. +#[cfg(not(target_arch = "x86"))] +#[test] +fn test_next_up() { + let tiny = f32::from_bits(1); + let tiny_up = f32::from_bits(2); + let max_down = f32::from_bits(0x7f7f_fffe); + let largest_subnormal = f32::from_bits(0x007f_ffff); + let smallest_normal = f32::from_bits(0x0080_0000); + assert_f32_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN); + assert_f32_biteq!(f32::MIN.next_up(), -max_down); + assert_f32_biteq!((-1.0 - f32::EPSILON).next_up(), -1.0); + assert_f32_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f32_biteq!((-tiny_up).next_up(), -tiny); + assert_f32_biteq!((-tiny).next_up(), -0.0f32); + assert_f32_biteq!((-0.0f32).next_up(), tiny); + assert_f32_biteq!(0.0f32.next_up(), tiny); + assert_f32_biteq!(tiny.next_up(), tiny_up); + assert_f32_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f32_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON); + assert_f32_biteq!(f32::MAX.next_up(), f32::INFINITY); + assert_f32_biteq!(f32::INFINITY.next_up(), f32::INFINITY); + + // Check that NaNs roundtrip. + let nan0 = f32::NAN; + let nan1 = f32::from_bits(f32::NAN.to_bits() ^ 0x002a_aaaa); + let nan2 = f32::from_bits(f32::NAN.to_bits() ^ 0x0055_5555); + assert_f32_biteq!(nan0.next_up(), nan0); + assert_f32_biteq!(nan1.next_up(), nan1); + assert_f32_biteq!(nan2.next_up(), nan2); +} + +// Ignore test on x87 floating point, these platforms do not guarantee NaN +// payloads are preserved and flush denormals to zero, failing the tests. +#[cfg(not(target_arch = "x86"))] +#[test] +fn test_next_down() { + let tiny = f32::from_bits(1); + let tiny_up = f32::from_bits(2); + let max_down = f32::from_bits(0x7f7f_fffe); + let largest_subnormal = f32::from_bits(0x007f_ffff); + let smallest_normal = f32::from_bits(0x0080_0000); + assert_f32_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY); + assert_f32_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY); + assert_f32_biteq!((-max_down).next_down(), f32::MIN); + assert_f32_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON); + assert_f32_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f32_biteq!((-tiny).next_down(), -tiny_up); + assert_f32_biteq!((-0.0f32).next_down(), -tiny); + assert_f32_biteq!((0.0f32).next_down(), -tiny); + assert_f32_biteq!(tiny.next_down(), 0.0f32); + assert_f32_biteq!(tiny_up.next_down(), tiny); + assert_f32_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f32_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32); + assert_f32_biteq!(f32::MAX.next_down(), max_down); + assert_f32_biteq!(f32::INFINITY.next_down(), f32::MAX); + + // Check that NaNs roundtrip. + let nan0 = f32::NAN; + let nan1 = f32::from_bits(f32::NAN.to_bits() ^ 0x002a_aaaa); + let nan2 = f32::from_bits(f32::NAN.to_bits() ^ 0x0055_5555); + assert_f32_biteq!(nan0.next_down(), nan0); + assert_f32_biteq!(nan1.next_down(), nan1); + assert_f32_biteq!(nan2.next_down(), nan2); +} + #[test] fn test_mul_add() { let nan: f32 = f32::NAN; diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index a9aa84f70..31351a879 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f64` double-precision floating point type. +//! Constants for the `f64` double-precision floating point type. //! //! *[See also the `f64` primitive type](primitive@f64).* //! diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 5c163cfe9..12baa68f4 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -289,6 +289,82 @@ fn test_is_sign_negative() { assert!((-f64::NAN).is_sign_negative()); } +#[allow(unused_macros)] +macro_rules! assert_f64_biteq { + ($left : expr, $right : expr) => { + let l: &f64 = &$left; + let r: &f64 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {} ({:#x}) is not equal to {} ({:#x})", *l, lb, *r, rb); + }; +} + +// Ignore test on x87 floating point, these platforms do not guarantee NaN +// payloads are preserved and flush denormals to zero, failing the tests. +#[cfg(not(target_arch = "x86"))] +#[test] +fn test_next_up() { + let tiny = f64::from_bits(1); + let tiny_up = f64::from_bits(2); + let max_down = f64::from_bits(0x7fef_ffff_ffff_fffe); + let largest_subnormal = f64::from_bits(0x000f_ffff_ffff_ffff); + let smallest_normal = f64::from_bits(0x0010_0000_0000_0000); + assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN); + assert_f64_biteq!(f64::MIN.next_up(), -max_down); + assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0); + assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f64_biteq!((-tiny_up).next_up(), -tiny); + assert_f64_biteq!((-tiny).next_up(), -0.0f64); + assert_f64_biteq!((-0.0f64).next_up(), tiny); + assert_f64_biteq!(0.0f64.next_up(), tiny); + assert_f64_biteq!(tiny.next_up(), tiny_up); + assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON); + assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY); + assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY); + + let nan0 = f64::NAN; + let nan1 = f64::from_bits(f64::NAN.to_bits() ^ 0x000a_aaaa_aaaa_aaaa); + let nan2 = f64::from_bits(f64::NAN.to_bits() ^ 0x0005_5555_5555_5555); + assert_f64_biteq!(nan0.next_up(), nan0); + assert_f64_biteq!(nan1.next_up(), nan1); + assert_f64_biteq!(nan2.next_up(), nan2); +} + +// Ignore test on x87 floating point, these platforms do not guarantee NaN +// payloads are preserved and flush denormals to zero, failing the tests. +#[cfg(not(target_arch = "x86"))] +#[test] +fn test_next_down() { + let tiny = f64::from_bits(1); + let tiny_up = f64::from_bits(2); + let max_down = f64::from_bits(0x7fef_ffff_ffff_fffe); + let largest_subnormal = f64::from_bits(0x000f_ffff_ffff_ffff); + let smallest_normal = f64::from_bits(0x0010_0000_0000_0000); + assert_f64_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY); + assert_f64_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY); + assert_f64_biteq!((-max_down).next_down(), f64::MIN); + assert_f64_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON); + assert_f64_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f64_biteq!((-tiny).next_down(), -tiny_up); + assert_f64_biteq!((-0.0f64).next_down(), -tiny); + assert_f64_biteq!((0.0f64).next_down(), -tiny); + assert_f64_biteq!(tiny.next_down(), 0.0f64); + assert_f64_biteq!(tiny_up.next_down(), tiny); + assert_f64_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f64_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64); + assert_f64_biteq!(f64::MAX.next_down(), max_down); + assert_f64_biteq!(f64::INFINITY.next_down(), f64::MAX); + + let nan0 = f64::NAN; + let nan1 = f64::from_bits(f64::NAN.to_bits() ^ 0x000a_aaaa_aaaa_aaaa); + let nan2 = f64::from_bits(f64::NAN.to_bits() ^ 0x0005_5555_5555_5555); + assert_f64_biteq!(nan0.next_down(), nan0); + assert_f64_biteq!(nan1.next_down(), nan1); + assert_f64_biteq!(nan2.next_down(), nan2); +} + #[test] fn test_mul_add() { let nan: f64 = f64::NAN; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index a0a5c003d..80ed34157 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -290,7 +290,8 @@ impl OsString { /// in the given `OsString`. The string may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. - /// Does nothing if capacity is already sufficient. + /// Does nothing if capacity is already sufficient. This method preserves + /// the contents even if an error occurs. /// /// See the main `OsString` documentation information about encoding and capacity units. /// diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c8e131b6e..c6c78dc39 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -13,13 +13,13 @@ mod tests; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; -/// A reference to an open file on the filesystem. +/// An object providing access to an open file on the filesystem. /// /// An instance of a `File` can be read and/or written depending on what options /// it was opened with. Files also implement [`Seek`] to alter the logical cursor @@ -377,6 +377,35 @@ impl File { OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) } + /// Creates a new file in read-write mode; error if the file exists. + /// + /// This function will create a file if it does not exist, or return an error if it does. This + /// way, if the call succeeds, the file returned is guaranteed to be new. + /// + /// This option is useful because it is atomic. Otherwise between checking whether a file + /// exists and creating a new one, the file may have been created by another process (a TOCTOU + /// race condition / attack). + /// + /// This can also be written using + /// `File::options().read(true).write(true).create_new(true).open(...)`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_create_new)] + /// + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create_new("foo.txt")?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_create_new", issue = "none")] + pub fn create_new>(path: P) -> io::Result { + OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref()) + } + /// Returns a new OpenOptions object. /// /// This function returns a new OpenOptions object that you can use to @@ -703,8 +732,8 @@ impl Read for File { self.inner.read_vectored(bufs) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - self.inner.read_buf(buf) + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(cursor) } #[inline] @@ -755,8 +784,8 @@ impl Read for &File { self.inner.read(buf) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - self.inner.read_buf(buf) + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(cursor) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index f7fbaa9c2..4f339a18a 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -2,7 +2,7 @@ mod buffer; use crate::fmt; use crate::io::{ - self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, + self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, }; use buffer::Buffer; @@ -224,6 +224,14 @@ impl BufReader { } } +// This is only used by a test which asserts that the initialization-tracking is correct. +#[cfg(test)] +impl BufReader { + pub fn initialized(&self) -> usize { + self.buf.initialized() + } +} + impl BufReader { /// Seeks relative to the current position. If the new position lies within the buffer, /// the buffer will not be flushed, allowing for more efficient seeks. @@ -266,21 +274,21 @@ impl Read for BufReader { Ok(nread) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer // entirely. - if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() { + if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() { self.discard_buffer(); - return self.inner.read_buf(buf); + return self.inner.read_buf(cursor); } - let prev = buf.filled_len(); + let prev = cursor.written(); let mut rem = self.fill_buf()?; - rem.read_buf(buf)?; + rem.read_buf(cursor.reborrow())?; - self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf + self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf Ok(()) } diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 8ae01f3b0..e9e29d60c 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -9,7 +9,7 @@ /// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so /// without encountering any runtime bounds checks. use crate::cmp; -use crate::io::{self, Read, ReadBuf}; +use crate::io::{self, BorrowedBuf, Read}; use crate::mem::MaybeUninit; pub struct Buffer { @@ -20,13 +20,19 @@ pub struct Buffer { // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are // initialized with bytes from a read. filled: usize, + // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we + // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its + // defensive initialization as possible. Note that while this often the same as `filled`, it + // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and + // omitting this is a huge perf regression for `Read` impls that do not. + initialized: usize, } impl Buffer { #[inline] pub fn with_capacity(capacity: usize) -> Self { let buf = Box::new_uninit_slice(capacity); - Self { buf, pos: 0, filled: 0 } + Self { buf, pos: 0, filled: 0, initialized: 0 } } #[inline] @@ -51,6 +57,12 @@ impl Buffer { self.pos } + // This is only used by a test which asserts that the initialization-tracking is correct. + #[cfg(test)] + pub fn initialized(&self) -> usize { + self.initialized + } + #[inline] pub fn discard_buffer(&mut self) { self.pos = 0; @@ -93,12 +105,17 @@ impl Buffer { if self.pos >= self.filled { debug_assert!(self.pos == self.filled); - let mut readbuf = ReadBuf::uninit(&mut self.buf); + let mut buf = BorrowedBuf::from(&mut *self.buf); + // SAFETY: `self.filled` bytes will always have been initialized. + unsafe { + buf.set_init(self.initialized); + } - reader.read_buf(&mut readbuf)?; + reader.read_buf(buf.unfilled())?; - self.filled = readbuf.filled_len(); self.pos = 0; + self.filled = buf.len(); + self.initialized = buf.init_len(); } Ok(self.buffer()) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index fe45b1326..f4e688eb9 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1,5 +1,7 @@ use crate::io::prelude::*; -use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom}; +use crate::io::{ + self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom, +}; use crate::mem::MaybeUninit; use crate::panic; use crate::sync::atomic::{AtomicUsize, Ordering}; @@ -61,48 +63,48 @@ fn test_buffered_reader_read_buf() { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let mut reader = BufReader::with_capacity(2, inner); - let mut buf = [MaybeUninit::uninit(); 3]; - let mut buf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3]; + let mut buf: BorrowedBuf<'_> = buf.into(); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), [5, 6, 7]); assert_eq!(reader.buffer(), []); - let mut buf = [MaybeUninit::uninit(); 2]; - let mut buf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 2]; + let mut buf: BorrowedBuf<'_> = buf.into(); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), [0, 1]); assert_eq!(reader.buffer(), []); - let mut buf = [MaybeUninit::uninit(); 1]; - let mut buf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1]; + let mut buf: BorrowedBuf<'_> = buf.into(); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), [2]); assert_eq!(reader.buffer(), [3]); - let mut buf = [MaybeUninit::uninit(); 3]; - let mut buf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3]; + let mut buf: BorrowedBuf<'_> = buf.into(); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), [3]); assert_eq!(reader.buffer(), []); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), [3, 4]); assert_eq!(reader.buffer(), []); buf.clear(); - reader.read_buf(&mut buf).unwrap(); + reader.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled_len(), 0); + assert!(buf.filled().is_empty()); } #[test] @@ -1037,3 +1039,27 @@ fn single_formatted_write() { writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap(); assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); } + +#[test] +fn bufreader_full_initialize() { + struct OneByteReader; + impl Read for OneByteReader { + fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { + if buf.len() > 0 { + buf[0] = 0; + Ok(1) + } else { + Ok(0) + } + } + } + let mut reader = BufReader::new(OneByteReader); + // Nothing is initialized yet. + assert_eq!(reader.initialized(), 0); + + let buf = reader.fill_buf().unwrap(); + // We read one byte... + assert_eq!(buf.len(), 1); + // But we initialized the whole buffer! + assert_eq!(reader.initialized(), reader.capacity()); +} diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 1a10245e4..38b98afff 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,4 @@ -use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE}; +use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; use crate::mem::MaybeUninit; /// Copies the entire contents of a reader into a writer. @@ -97,37 +97,39 @@ impl BufferedCopySpec for BufWriter { loop { let buf = writer.buffer_mut(); - let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut()); + let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); - // SAFETY: init is either 0 or the initialized_len of the previous iteration unsafe { - read_buf.assume_init(init); + // SAFETY: init is either 0 or the init_len from the previous iteration. + read_buf.set_init(init); } if read_buf.capacity() >= DEFAULT_BUF_SIZE { - match reader.read_buf(&mut read_buf) { + let mut cursor = read_buf.unfilled(); + match reader.read_buf(cursor.reborrow()) { Ok(()) => { - let bytes_read = read_buf.filled_len(); + let bytes_read = cursor.written(); if bytes_read == 0 { return Ok(len); } - init = read_buf.initialized_len() - bytes_read; + init = read_buf.init_len() - bytes_read; + len += bytes_read as u64; - // SAFETY: ReadBuf guarantees all of its filled bytes are init + // SAFETY: BorrowedBuf guarantees all of its filled bytes are init unsafe { buf.set_len(buf.len() + bytes_read) }; - len += bytes_read as u64; + // Read again if the buffer still has enough capacity, as BufWriter itself would do // This will occur if the reader returns short reads - continue; } - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => return Err(e), } + } else { + writer.flush_buf()?; + init = 0; } - - writer.flush_buf()?; } } } @@ -136,13 +138,13 @@ fn stack_buffer_copy( reader: &mut R, writer: &mut W, ) -> Result { - let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE]; - let mut buf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE]; + let mut buf: BorrowedBuf<'_> = buf.into(); let mut len = 0; loop { - match reader.read_buf(&mut buf) { + match reader.read_buf(buf.unfilled()) { Ok(()) => {} Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index f3fbfc447..d98ab021c 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -5,7 +5,7 @@ use crate::io::prelude::*; use crate::alloc::Allocator; use crate::cmp; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; +use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; /// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. @@ -323,12 +323,12 @@ where Ok(n) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - let prev_filled = buf.filled_len(); + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + let prev_written = cursor.written(); - Read::read_buf(&mut self.fill_buf()?, buf)?; + Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?; - self.pos += (buf.filled_len() - prev_filled) as u64; + self.pos += (cursor.written() - prev_written) as u64; Ok(()) } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index ff7fdcae1..29b09fcc5 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -76,6 +76,15 @@ impl fmt::Debug for Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Error { + /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. + fn from(_: alloc::ffi::NulError) -> Error { + const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + } +} + // Only derive debug in tests, to make sure it // doesn't accidentally get printed. #[cfg_attr(test, derive(Debug))] @@ -564,6 +573,8 @@ impl Error { /// println!("last OS error: {os_error:?}"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "GetLastError")] + #[doc(alias = "errno")] #[must_use] #[inline] pub fn last_os_error() -> Error { diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 292bf4826..781ae03ad 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -269,10 +269,10 @@ where } TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()), TAG_CUSTOM => { - // It would be correct for us to use `ptr::sub` here (see the + // It would be correct for us to use `ptr::byte_sub` here (see the // comment above the `wrapping_add` call in `new_custom` for why), // but it isn't clear that it makes a difference, so we don't. - let custom = ptr.as_ptr().cast::().wrapping_sub(TAG_CUSTOM).cast::(); + let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::(); ErrorData::Custom(make_custom(custom)) } _ => { diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 950725473..e5048dcc8 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -6,7 +6,7 @@ use crate::cmp; use crate::collections::VecDeque; use crate::fmt; use crate::io::{ - self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write, + self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write, }; use crate::mem; @@ -21,8 +21,8 @@ impl Read for &mut R { } #[inline] - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - (**self).read_buf(buf) + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(cursor) } #[inline] @@ -125,8 +125,8 @@ impl Read for Box { } #[inline] - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - (**self).read_buf(buf) + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(cursor) } #[inline] @@ -249,11 +249,11 @@ impl Read for &[u8] { } #[inline] - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - let amt = cmp::min(buf.remaining(), self.len()); + fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + let amt = cmp::min(cursor.capacity(), self.len()); let (a, b) = self.split_at(amt); - buf.append(a); + cursor.append(a); *self = b; Ok(()) @@ -427,10 +427,10 @@ impl Read for VecDeque { } #[inline] - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { let (ref mut front, _) = self.as_slices(); - let n = cmp::min(buf.remaining(), front.len()); - Read::read_buf(front, buf)?; + let n = cmp::min(cursor.capacity(), front.len()); + Read::read_buf(front, cursor)?; self.drain(..n); Ok(()) } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 96addbd1a..eeace2c43 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -278,7 +278,7 @@ pub use self::{ }; #[unstable(feature = "read_buf", issue = "78485")] -pub use self::readbuf::ReadBuf; +pub use self::readbuf::{BorrowedBuf, BorrowedCursor}; pub(crate) use error::const_io_error; mod buffered; @@ -362,29 +362,30 @@ pub(crate) fn default_read_to_end(r: &mut R, buf: &mut Vec buf.reserve(32); // buf is full, need more space } - let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut()); + let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); // SAFETY: These bytes were initialized but not filled in the previous loop unsafe { - read_buf.assume_init(initialized); + read_buf.set_init(initialized); } - match r.read_buf(&mut read_buf) { + let mut cursor = read_buf.unfilled(); + match r.read_buf(cursor.reborrow()) { Ok(()) => {} Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), } - if read_buf.filled_len() == 0 { + if cursor.written() == 0 { return Ok(buf.len() - start_len); } // store how much was initialized but not filled - initialized = read_buf.initialized_len() - read_buf.filled_len(); - let new_len = read_buf.filled_len() + buf.len(); + initialized = cursor.init_ref().len(); - // SAFETY: ReadBuf's invariants mean this much memory is init + // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. unsafe { + let new_len = read_buf.filled().len() + buf.len(); buf.set_len(new_len); } @@ -461,12 +462,15 @@ pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [ } } -pub(crate) fn default_read_buf(read: F, buf: &mut ReadBuf<'_>) -> Result<()> +pub(crate) fn default_read_buf(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()> where F: FnOnce(&mut [u8]) -> Result, { - let n = read(buf.initialize_unfilled())?; - buf.add_filled(n); + let n = read(cursor.ensure_init().init_mut())?; + unsafe { + // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to. + cursor.advance(n); + } Ok(()) } @@ -803,30 +807,30 @@ pub trait Read { /// Pull some bytes from this source into the specified buffer. /// - /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use + /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`. /// /// The default implementation delegates to `read`. #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { default_read_buf(|b| self.read(b), buf) } - /// Read the exact number of bytes required to fill `buf`. + /// Read the exact number of bytes required to fill `cursor`. /// - /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to + /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to /// allow use with uninitialized buffers. #[unstable(feature = "read_buf", issue = "78485")] - fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { - while buf.remaining() > 0 { - let prev_filled = buf.filled().len(); - match self.read_buf(buf) { + fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> { + while cursor.capacity() > 0 { + let prev_written = cursor.written(); + match self.read_buf(cursor.reborrow()) { Ok(()) => {} Err(e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), } - if buf.filled().len() == prev_filled { + if cursor.written() == prev_written { return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer")); } } @@ -883,6 +887,10 @@ pub trait Read { /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] /// otherwise. EOF is mapped to returning [`None`] from this iterator. /// + /// The default implementation calls `read` for each byte, + /// which can be very inefficient for data that's not in memory, + /// such as [`File`]. Consider using a [`BufReader`] in such cases. + /// /// # Examples /// /// [`File`]s implement `Read`: @@ -895,10 +903,11 @@ pub trait Read { /// ```no_run /// use std::io; /// use std::io::prelude::*; + /// use std::io::BufReader; /// use std::fs::File; /// /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let f = BufReader::new(File::open("foo.txt")?); /// /// for byte in f.bytes() { /// println!("{}", byte.unwrap()); @@ -1028,8 +1037,6 @@ pub trait Read { /// # Examples /// /// ```no_run -/// #![feature(io_read_to_string)] -/// /// # use std::io; /// fn main() -> io::Result<()> { /// let stdin = io::read_to_string(io::stdin())?; @@ -1038,7 +1045,7 @@ pub trait Read { /// Ok(()) /// } /// ``` -#[unstable(feature = "io_read_to_string", issue = "80218")] +#[stable(feature = "io_read_to_string", since = "1.65.0")] pub fn read_to_string(mut reader: R) -> Result { let mut buf = String::new(); reader.read_to_string(&mut buf)?; @@ -2582,50 +2589,48 @@ impl Read for Take { Ok(n) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> { + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { // Don't call into inner reader at all at EOF because it may still block if self.limit == 0 { return Ok(()); } - let prev_filled = buf.filled_len(); - - if self.limit <= buf.remaining() as u64 { + if self.limit <= buf.capacity() as u64 { // if we just use an as cast to convert, limit may wrap around on a 32 bit target let limit = cmp::min(self.limit, usize::MAX as u64) as usize; - let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len()); + let extra_init = cmp::min(limit as usize, buf.init_ref().len()); // SAFETY: no uninit data is written to ibuf - let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] }; + let ibuf = unsafe { &mut buf.as_mut()[..limit] }; - let mut sliced_buf = ReadBuf::uninit(ibuf); + let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); // SAFETY: extra_init bytes of ibuf are known to be initialized unsafe { - sliced_buf.assume_init(extra_init); + sliced_buf.set_init(extra_init); } - self.inner.read_buf(&mut sliced_buf)?; + let mut cursor = sliced_buf.unfilled(); + self.inner.read_buf(cursor.reborrow())?; - let new_init = sliced_buf.initialized_len(); - let filled = sliced_buf.filled_len(); + let new_init = cursor.init_ref().len(); + let filled = sliced_buf.len(); - // sliced_buf / ibuf must drop here + // cursor / sliced_buf / ibuf must drop here - // SAFETY: new_init bytes of buf's unfilled buffer have been initialized unsafe { - buf.assume_init(new_init); + // SAFETY: filled bytes have been filled and therefore initialized + buf.advance(filled); + // SAFETY: new_init bytes of buf's unfilled buffer have been initialized + buf.set_init(new_init); } - buf.add_filled(filled); - self.limit -= filled as u64; } else { - self.inner.read_buf(buf)?; - - //inner may unfill - self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64; + let written = buf.written(); + self.inner.read_buf(buf.reborrow())?; + self.limit -= (buf.written() - written) as u64; } Ok(()) diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs index 78d1113f8..b1a84095f 100644 --- a/library/std/src/io/readbuf.rs +++ b/library/std/src/io/readbuf.rs @@ -5,9 +5,10 @@ mod tests; use crate::cmp; use crate::fmt::{self, Debug, Formatter}; -use crate::mem::MaybeUninit; +use crate::io::{Result, Write}; +use crate::mem::{self, MaybeUninit}; -/// A wrapper around a byte buffer that is incrementally filled and initialized. +/// A borrowed byte buffer which is incrementally filled and initialized. /// /// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the /// buffer that has been logically filled with data, a region that has been initialized at some point but not yet @@ -20,230 +21,286 @@ use crate::mem::MaybeUninit; /// [ filled | unfilled ] /// [ initialized | uninitialized ] /// ``` -pub struct ReadBuf<'a> { - buf: &'a mut [MaybeUninit], +/// +/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference +/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be +/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor +/// has write-only access to the unfilled portion of the buffer (you can think of it as a +/// write-only iterator). +/// +/// The lifetime `'data` is a bound on the lifetime of the underlying data. +pub struct BorrowedBuf<'data> { + /// The buffer's underlying data. + buf: &'data mut [MaybeUninit], + /// The length of `self.buf` which is known to be filled. filled: usize, - initialized: usize, + /// The length of `self.buf` which is known to be initialized. + init: usize, } -impl Debug for ReadBuf<'_> { +impl Debug for BorrowedBuf<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("ReadBuf") - .field("init", &self.initialized()) + f.debug_struct("BorrowedBuf") + .field("init", &self.init) .field("filled", &self.filled) .field("capacity", &self.capacity()) .finish() } } -impl<'a> ReadBuf<'a> { - /// Creates a new `ReadBuf` from a fully initialized buffer. +/// Create a new `BorrowedBuf` from a fully initialized slice. +impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { #[inline] - pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> { - let len = buf.len(); + fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { + let len = slice.len(); - ReadBuf { - //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf - buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() }, + BorrowedBuf { + // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf + buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() }, filled: 0, - initialized: len, + init: len, } } +} - /// Creates a new `ReadBuf` from a fully uninitialized buffer. - /// - /// Use `assume_init` if part of the buffer is known to be already initialized. +/// Create a new `BorrowedBuf` from an uninitialized buffer. +/// +/// Use `set_init` if part of the buffer is known to be already initialized. +impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { #[inline] - pub fn uninit(buf: &'a mut [MaybeUninit]) -> ReadBuf<'a> { - ReadBuf { buf, filled: 0, initialized: 0 } + fn from(buf: &'data mut [MaybeUninit]) -> BorrowedBuf<'data> { + BorrowedBuf { buf, filled: 0, init: 0 } } +} +impl<'data> BorrowedBuf<'data> { /// Returns the total capacity of the buffer. #[inline] pub fn capacity(&self) -> usize { self.buf.len() } + /// Returns the length of the filled part of the buffer. + #[inline] + pub fn len(&self) -> usize { + self.filled + } + + /// Returns the length of the initialized part of the buffer. + #[inline] + pub fn init_len(&self) -> usize { + self.init + } + /// Returns a shared reference to the filled portion of the buffer. #[inline] pub fn filled(&self) -> &[u8] { - //SAFETY: We only slice the filled part of the buffer, which is always valid + // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) } } - /// Returns a mutable reference to the filled portion of the buffer. + /// Returns a cursor over the unfilled part of the buffer. #[inline] - pub fn filled_mut(&mut self) -> &mut [u8] { - //SAFETY: We only slice the filled part of the buffer, which is always valid - unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) } + pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { + BorrowedCursor { + start: self.filled, + // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its + // lifetime covariantly is safe. + buf: unsafe { + mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self) + }, + } } - /// Returns a shared reference to the initialized portion of the buffer. + /// Clears the buffer, resetting the filled region to empty. /// - /// This includes the filled portion. + /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. #[inline] - pub fn initialized(&self) -> &[u8] { - //SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) } + pub fn clear(&mut self) -> &mut Self { + self.filled = 0; + self } - /// Returns a mutable reference to the initialized portion of the buffer. + /// Asserts that the first `n` bytes of the buffer are initialized. /// - /// This includes the filled portion. - #[inline] - pub fn initialized_mut(&mut self) -> &mut [u8] { - //SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) } - } - - /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully - /// initialized. + /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer + /// bytes than are already known to be initialized. /// /// # Safety /// - /// The caller must not de-initialize portions of the buffer that have already been initialized. + /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. #[inline] - pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit] { - &mut self.buf[self.filled..] + pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { + self.init = cmp::max(self.init, n); + self } +} - /// Returns a mutable reference to the uninitialized part of the buffer. +/// A writeable view of the unfilled portion of a [`BorrowedBuf`](BorrowedBuf). +/// +/// Provides access to the initialized and uninitialized parts of the underlying `BorrowedBuf`. +/// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or +/// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the +/// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform +/// the cursor how many bytes have been written. +/// +/// Once data is written to the cursor, it becomes part of the filled portion of the underlying +/// `BorrowedBuf` and can no longer be accessed or re-written by the cursor. I.e., the cursor tracks +/// the unfilled part of the underlying `BorrowedBuf`. +/// +/// The lifetime `'a` is a bound on the lifetime of the underlying buffer (which means it is a bound +/// on the data in that buffer by transitivity). +#[derive(Debug)] +pub struct BorrowedCursor<'a> { + /// The underlying buffer. + // Safety invariant: we treat the type of buf as covariant in the lifetime of `BorrowedBuf` when + // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into + // it, so don't do that! + buf: &'a mut BorrowedBuf<'a>, + /// The length of the filled portion of the underlying buffer at the time of the cursor's + /// creation. + start: usize, +} + +impl<'a> BorrowedCursor<'a> { + /// Reborrow this cursor by cloning it with a smaller lifetime. /// - /// It is safe to uninitialize any of these bytes. + /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is + /// not accessible while the new cursor exists. #[inline] - pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit] { - &mut self.buf[self.initialized..] + pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> { + BorrowedCursor { + // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its + // lifetime covariantly is safe. + buf: unsafe { + mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>( + self.buf, + ) + }, + start: self.start, + } } - /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized. - /// - /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after - /// the first use. + /// Returns the available space in the cursor. #[inline] - pub fn initialize_unfilled(&mut self) -> &mut [u8] { - // should optimize out the assertion - self.initialize_unfilled_to(self.remaining()) + pub fn capacity(&self) -> usize { + self.buf.capacity() - self.buf.filled } - /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is - /// fully initialized. - /// - /// # Panics + /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. /// - /// Panics if `self.remaining()` is less than `n`. + /// Note that if this cursor is a reborrowed clone of another, then the count returned is the + /// count written via either cursor, not the count since the cursor was reborrowed. #[inline] - pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] { - assert!(self.remaining() >= n); - - let extra_init = self.initialized - self.filled; - // If we don't have enough initialized, do zeroing - if n > extra_init { - let uninit = n - extra_init; - let unfilled = &mut self.uninitialized_mut()[0..uninit]; - - for byte in unfilled.iter_mut() { - byte.write(0); - } - - // SAFETY: we just initialized uninit bytes, and the previous bytes were already init - unsafe { - self.assume_init(n); - } - } - - let filled = self.filled; + pub fn written(&self) -> usize { + self.buf.filled - self.start + } - &mut self.initialized_mut()[filled..filled + n] + /// Returns a shared reference to the initialized portion of the cursor. + #[inline] + pub fn init_ref(&self) -> &[u8] { + // SAFETY: We only slice the initialized part of the buffer, which is always valid + unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) } } - /// Returns the number of bytes at the end of the slice that have not yet been filled. + /// Returns a mutable reference to the initialized portion of the cursor. #[inline] - pub fn remaining(&self) -> usize { - self.capacity() - self.filled + pub fn init_mut(&mut self) -> &mut [u8] { + // SAFETY: We only slice the initialized part of the buffer, which is always valid + unsafe { + MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init]) + } } - /// Clears the buffer, resetting the filled region to empty. + /// Returns a mutable reference to the uninitialized part of the cursor. /// - /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. + /// It is safe to uninitialize any of these bytes. #[inline] - pub fn clear(&mut self) -> &mut Self { - self.set_filled(0) // The assertion in `set_filled` is optimized out + pub fn uninit_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buf.buf[self.buf.init..] } - /// Increases the size of the filled region of the buffer. - /// - /// The number of initialized bytes is not changed. + /// Returns a mutable reference to the whole cursor. /// - /// # Panics + /// # Safety /// - /// Panics if the filled region of the buffer would become larger than the initialized region. + /// The caller must not uninitialize any bytes in the initialized portion of the cursor. #[inline] - pub fn add_filled(&mut self, n: usize) -> &mut Self { - self.set_filled(self.filled + n) + pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buf.buf[self.buf.filled..] } - /// Sets the size of the filled region of the buffer. + /// Advance the cursor by asserting that `n` bytes have been filled. /// - /// The number of initialized bytes is not changed. + /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be + /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements + /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements. /// - /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for - /// example, by a `Read` implementation that compresses data in-place). - /// - /// # Panics + /// # Safety /// - /// Panics if the filled region of the buffer would become larger than the initialized region. + /// The caller must ensure that the first `n` bytes of the cursor have been properly + /// initialised. + #[inline] + pub unsafe fn advance(&mut self, n: usize) -> &mut Self { + self.buf.filled += n; + self.buf.init = cmp::max(self.buf.init, self.buf.filled); + self + } + + /// Initializes all bytes in the cursor. #[inline] - pub fn set_filled(&mut self, n: usize) -> &mut Self { - assert!(n <= self.initialized); + pub fn ensure_init(&mut self) -> &mut Self { + for byte in self.uninit_mut() { + byte.write(0); + } + self.buf.init = self.buf.capacity(); - self.filled = n; self } - /// Asserts that the first `n` unfilled bytes of the buffer are initialized. + /// Asserts that the first `n` unfilled bytes of the cursor are initialized. /// - /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer - /// bytes than are already known to be initialized. + /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when + /// called with fewer bytes than are already known to be initialized. /// /// # Safety /// - /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. + /// The caller must ensure that the first `n` bytes of the buffer have already been initialized. #[inline] - pub unsafe fn assume_init(&mut self, n: usize) -> &mut Self { - self.initialized = cmp::max(self.initialized, self.filled + n); + pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { + self.buf.init = cmp::max(self.buf.init, self.buf.filled + n); self } - /// Appends data to the buffer, advancing the written position and possibly also the initialized position. + /// Appends data to the cursor, advancing position within its buffer. /// /// # Panics /// - /// Panics if `self.remaining()` is less than `buf.len()`. + /// Panics if `self.capacity()` is less than `buf.len()`. #[inline] pub fn append(&mut self, buf: &[u8]) { - assert!(self.remaining() >= buf.len()); + assert!(self.capacity() >= buf.len()); // SAFETY: we do not de-initialize any of the elements of the slice unsafe { - MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf); + MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf); } // SAFETY: We just added the entire contents of buf to the filled section. unsafe { - self.assume_init(buf.len()); + self.set_init(buf.len()); } - self.add_filled(buf.len()); + self.buf.filled += buf.len(); } +} - /// Returns the amount of bytes that have been filled. - #[inline] - pub fn filled_len(&self) -> usize { - self.filled +impl<'a> Write for BorrowedCursor<'a> { + fn write(&mut self, buf: &[u8]) -> Result { + self.append(buf); + Ok(buf.len()) } - /// Returns the amount of bytes that have been initialized. - #[inline] - pub fn initialized_len(&self) -> usize { - self.initialized + fn flush(&mut self) -> Result<()> { + Ok(()) } } diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs index 3b7a5a56d..cc1b423f2 100644 --- a/library/std/src/io/readbuf/tests.rs +++ b/library/std/src/io/readbuf/tests.rs @@ -1,181 +1,175 @@ -use super::ReadBuf; +use super::BorrowedBuf; use crate::mem::MaybeUninit; -/// Test that ReadBuf has the correct numbers when created with new +/// Test that BorrowedBuf has the correct numbers when created with new #[test] fn new() { - let mut buf = [0; 16]; - let rbuf = ReadBuf::new(&mut buf); + let buf: &mut [_] = &mut [0; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - assert_eq!(rbuf.filled_len(), 0); - assert_eq!(rbuf.initialized_len(), 16); + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 16); assert_eq!(rbuf.capacity(), 16); - assert_eq!(rbuf.remaining(), 16); + assert_eq!(rbuf.unfilled().capacity(), 16); } -/// Test that ReadBuf has the correct numbers when created with uninit +/// Test that BorrowedBuf has the correct numbers when created with uninit #[test] fn uninit() { - let mut buf = [MaybeUninit::uninit(); 16]; - let rbuf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - assert_eq!(rbuf.filled_len(), 0); - assert_eq!(rbuf.initialized_len(), 0); + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 0); assert_eq!(rbuf.capacity(), 16); - assert_eq!(rbuf.remaining(), 16); + assert_eq!(rbuf.unfilled().capacity(), 16); } #[test] fn initialize_unfilled() { - let mut buf = [MaybeUninit::uninit(); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.initialize_unfilled(); + rbuf.unfilled().ensure_init(); - assert_eq!(rbuf.initialized_len(), 16); + assert_eq!(rbuf.init_len(), 16); } #[test] -fn initialize_unfilled_to() { - let mut buf = [MaybeUninit::uninit(); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); +fn addvance_filled() { + let buf: &mut [_] = &mut [0; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.initialize_unfilled_to(8); - - assert_eq!(rbuf.initialized_len(), 8); - - rbuf.initialize_unfilled_to(4); - - assert_eq!(rbuf.initialized_len(), 8); - - rbuf.set_filled(8); - - rbuf.initialize_unfilled_to(6); - - assert_eq!(rbuf.initialized_len(), 14); - - rbuf.initialize_unfilled_to(8); - - assert_eq!(rbuf.initialized_len(), 16); -} - -#[test] -fn add_filled() { - let mut buf = [0; 16]; - let mut rbuf = ReadBuf::new(&mut buf); - - rbuf.add_filled(1); - - assert_eq!(rbuf.filled_len(), 1); - assert_eq!(rbuf.remaining(), 15); -} - -#[test] -#[should_panic] -fn add_filled_panic() { - let mut buf = [MaybeUninit::uninit(); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); - - rbuf.add_filled(1); -} - -#[test] -fn set_filled() { - let mut buf = [0; 16]; - let mut rbuf = ReadBuf::new(&mut buf); - - rbuf.set_filled(16); - - assert_eq!(rbuf.filled_len(), 16); - assert_eq!(rbuf.remaining(), 0); - - rbuf.set_filled(6); - - assert_eq!(rbuf.filled_len(), 6); - assert_eq!(rbuf.remaining(), 10); -} - -#[test] -#[should_panic] -fn set_filled_panic() { - let mut buf = [MaybeUninit::uninit(); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); + unsafe { + rbuf.unfilled().advance(1); + } - rbuf.set_filled(16); + assert_eq!(rbuf.filled().len(), 1); + assert_eq!(rbuf.unfilled().capacity(), 15); } #[test] fn clear() { - let mut buf = [255; 16]; - let mut rbuf = ReadBuf::new(&mut buf); + let buf: &mut [_] = &mut [255; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.set_filled(16); + unsafe { + rbuf.unfilled().advance(16); + } - assert_eq!(rbuf.filled_len(), 16); - assert_eq!(rbuf.remaining(), 0); + assert_eq!(rbuf.filled().len(), 16); + assert_eq!(rbuf.unfilled().capacity(), 0); rbuf.clear(); - assert_eq!(rbuf.filled_len(), 0); - assert_eq!(rbuf.remaining(), 16); + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.initialized(), [255; 16]); + assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); } #[test] -fn assume_init() { - let mut buf = [MaybeUninit::uninit(); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); +fn set_init() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); unsafe { - rbuf.assume_init(8); + rbuf.set_init(8); } - assert_eq!(rbuf.initialized_len(), 8); + assert_eq!(rbuf.init_len(), 8); - rbuf.add_filled(4); + unsafe { + rbuf.unfilled().advance(4); + } unsafe { - rbuf.assume_init(2); + rbuf.set_init(2); } - assert_eq!(rbuf.initialized_len(), 8); + assert_eq!(rbuf.init_len(), 8); unsafe { - rbuf.assume_init(8); + rbuf.set_init(8); } - assert_eq!(rbuf.initialized_len(), 12); + assert_eq!(rbuf.init_len(), 8); } #[test] fn append() { - let mut buf = [MaybeUninit::new(255); 16]; - let mut rbuf = ReadBuf::uninit(&mut buf); + let buf: &mut [_] = &mut [MaybeUninit::new(255); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); - rbuf.append(&[0; 8]); + rbuf.unfilled().append(&[0; 8]); - assert_eq!(rbuf.initialized_len(), 8); - assert_eq!(rbuf.filled_len(), 8); + assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.filled().len(), 8); assert_eq!(rbuf.filled(), [0; 8]); rbuf.clear(); - rbuf.append(&[1; 16]); + rbuf.unfilled().append(&[1; 16]); - assert_eq!(rbuf.initialized_len(), 16); - assert_eq!(rbuf.filled_len(), 16); + assert_eq!(rbuf.init_len(), 16); + assert_eq!(rbuf.filled().len(), 16); assert_eq!(rbuf.filled(), [1; 16]); } #[test] -fn filled_mut() { - let mut buf = [0; 16]; - let mut rbuf = ReadBuf::new(&mut buf); +fn reborrow_written() { + let buf: &mut [_] = &mut [MaybeUninit::new(0); 32]; + let mut buf: BorrowedBuf<'_> = buf.into(); + + let mut cursor = buf.unfilled(); + cursor.append(&[1; 16]); + + let mut cursor2 = cursor.reborrow(); + cursor2.append(&[2; 16]); + + assert_eq!(cursor2.written(), 32); + assert_eq!(cursor.written(), 32); + + assert_eq!(buf.unfilled().written(), 0); + assert_eq!(buf.init_len(), 32); + assert_eq!(buf.filled().len(), 32); + let filled = buf.filled(); + assert_eq!(&filled[..16], [1; 16]); + assert_eq!(&filled[16..], [2; 16]); +} + +#[test] +fn cursor_set_init() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + unsafe { + rbuf.unfilled().set_init(8); + } - rbuf.add_filled(8); + assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.unfilled().init_ref().len(), 8); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); + assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16); + + unsafe { + rbuf.unfilled().advance(4); + } - let filled = rbuf.filled().to_vec(); + unsafe { + rbuf.unfilled().set_init(2); + } + + assert_eq!(rbuf.init_len(), 8); + + unsafe { + rbuf.unfilled().set_init(8); + } - assert_eq!(&*filled, &*rbuf.filled_mut()); + assert_eq!(rbuf.init_len(), 12); + assert_eq!(rbuf.unfilled().init_ref().len(), 8); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); + assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 12); } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4d3736f79..2dc12a18a 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,6 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock}; use crate::sys::stdio; @@ -526,7 +525,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Pin<&'static ReentrantMutex>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the [`Stdout`] handle. @@ -603,22 +602,27 @@ static STDOUT: OnceLock>>> = OnceLo #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { Stdout { - inner: Pin::static_ref(&STDOUT).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) }, - |mutex| unsafe { mutex.init() }, - ), + inner: STDOUT + .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))), } } +// Flush the data and disable buffering during shutdown +// by replacing the line writer by one with zero +// buffering capacity. pub fn cleanup() { - if let Some(instance) = STDOUT.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. + let mut initialized = false; + let stdout = STDOUT.get_or_init(|| { + initialized = true; + ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) + }); + + if !initialized { + // The buffer was previously initialized, overwrite it here. // We use try_lock() instead of lock(), because someone // might have leaked a StdoutLock, which would // otherwise cause a deadlock here. - if let Some(lock) = Pin::static_ref(instance).try_lock() { + if let Some(lock) = stdout.try_lock() { *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); } } @@ -761,7 +765,7 @@ impl fmt::Debug for StdoutLock<'_> { /// standard library or via raw Windows API calls, will fail. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: Pin<&'static ReentrantMutex>>, + inner: &'static ReentrantMutex>, } /// A locked reference to the [`Stderr`] handle. @@ -834,16 +838,12 @@ pub struct StderrLock<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { // Note that unlike `stdout()` we don't use `at_exit` here to register a - // destructor. Stderr is not buffered , so there's no need to run a + // destructor. Stderr is not buffered, so there's no need to run a // destructor for flushing the buffer - static INSTANCE: OnceLock>> = OnceLock::new(); + static INSTANCE: ReentrantMutex> = + ReentrantMutex::new(RefCell::new(stderr_raw())); - Stderr { - inner: Pin::static_ref(&INSTANCE).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }, - |mutex| unsafe { mutex.init() }, - ), - } + Stderr { inner: &INSTANCE } } impl Stderr { @@ -986,12 +986,15 @@ pub fn set_output_capture(sink: Option) -> Option { /// otherwise. `label` identifies the stream in a panic message. /// /// This function is used to print error messages, so it takes extra -/// care to avoid causing a panic when `local_s` is unusable. -/// For instance, if the TLS key for the local stream is -/// already destroyed, or if the local stream is locked by another -/// thread, it will just fall back to the global stream. +/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable. +/// For instance, if the TLS key for output capturing is already destroyed, or +/// if the local stream is in use by another thread, it will just fall back to +/// the global stream. /// /// However, if the actual I/O causes an error, this function does panic. +/// +/// Writing to non-blocking stdout/stderr can cause an error, which will lead +/// this function to panic. fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) where T: Write, diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f357f33ec..f4a886d88 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,4 +1,4 @@ -use super::{repeat, Cursor, ReadBuf, SeekFrom}; +use super::{repeat, BorrowedBuf, Cursor, SeekFrom}; use crate::cmp::{self, min}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::io::{BufRead, BufReader, Read, Seek, Write}; @@ -94,7 +94,7 @@ fn read_to_end() { assert_eq!(c.read_to_end(&mut v).unwrap(), 1); assert_eq!(v, b"1"); - let cap = 1024 * 1024; + let cap = if cfg!(miri) { 1024 } else { 1024 * 1024 }; let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); let mut v = Vec::new(); let (a, b) = data.split_at(data.len() / 2); @@ -159,24 +159,24 @@ fn read_exact_slice() { #[test] fn read_buf_exact() { - let mut buf = [0; 4]; - let mut buf = ReadBuf::new(&mut buf); + let buf: &mut [_] = &mut [0; 4]; + let mut buf: BorrowedBuf<'_> = buf.into(); let mut c = Cursor::new(&b""[..]); - assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); let mut c = Cursor::new(&b"123456789"[..]); - c.read_buf_exact(&mut buf).unwrap(); + c.read_buf_exact(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), b"1234"); buf.clear(); - c.read_buf_exact(&mut buf).unwrap(); + c.read_buf_exact(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), b"5678"); buf.clear(); - assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + assert_eq!(c.read_buf_exact(buf.unfilled()).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); } #[test] @@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() { #[bench] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); @@ -614,10 +615,10 @@ fn bench_take_read(b: &mut test::Bencher) { #[bench] fn bench_take_read_buf(b: &mut test::Bencher) { b.iter(|| { - let mut buf = [MaybeUninit::uninit(); 64]; + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 64]; - let mut rbuf = ReadBuf::uninit(&mut buf); + let mut buf: BorrowedBuf<'_> = buf.into(); - [255; 128].take(64).read_buf(&mut rbuf).unwrap(); + [255; 128].take(64).read_buf(buf.unfilled()).unwrap(); }); } diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index c1300cd67..f076ee092 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -5,7 +5,7 @@ mod tests; use crate::fmt; use crate::io::{ - self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write, + self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, }; /// A reader which is always at EOF. @@ -47,7 +47,7 @@ impl Read for Empty { } #[inline] - fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> { + fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { Ok(()) } } @@ -130,21 +130,19 @@ impl Read for Repeat { Ok(buf.len()) } - fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: No uninit bytes are being written - for slot in unsafe { buf.unfilled_mut() } { + for slot in unsafe { buf.as_mut() } { slot.write(self.byte); } - let remaining = buf.remaining(); + let remaining = buf.capacity(); // SAFETY: the entire unfilled portion of buf has been initialized unsafe { - buf.assume_init(remaining); + buf.advance(remaining); } - buf.add_filled(remaining); - Ok(()) } diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index 08972a59a..ce5e2c9da 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -1,7 +1,7 @@ use crate::cmp::{max, min}; use crate::io::prelude::*; use crate::io::{ - copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink, + copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, DEFAULT_BUF_SIZE, }; @@ -79,29 +79,29 @@ fn empty_reads() { assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); - let mut buf = []; - let mut buf = ReadBuf::uninit(&mut buf); - e.read_buf(&mut buf).unwrap(); - assert_eq!(buf.filled_len(), 0); - assert_eq!(buf.initialized_len(), 0); - - let mut buf = [MaybeUninit::uninit()]; - let mut buf = ReadBuf::uninit(&mut buf); - e.read_buf(&mut buf).unwrap(); - assert_eq!(buf.filled_len(), 0); - assert_eq!(buf.initialized_len(), 0); - - let mut buf = [MaybeUninit::uninit(); 1024]; - let mut buf = ReadBuf::uninit(&mut buf); - e.read_buf(&mut buf).unwrap(); - assert_eq!(buf.filled_len(), 0); - assert_eq!(buf.initialized_len(), 0); - - let mut buf = [MaybeUninit::uninit(); 1024]; - let mut buf = ReadBuf::uninit(&mut buf); - e.by_ref().read_buf(&mut buf).unwrap(); - assert_eq!(buf.filled_len(), 0); - assert_eq!(buf.initialized_len(), 0); + let buf: &mut [MaybeUninit<_>] = &mut []; + let mut buf: BorrowedBuf<'_> = buf.into(); + e.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit()]; + let mut buf: BorrowedBuf<'_> = buf.into(); + e.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; + let mut buf: BorrowedBuf<'_> = buf.into(); + e.read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; + let mut buf: BorrowedBuf<'_> = buf.into(); + e.by_ref().read_buf(buf.unfilled()).unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); } #[test] diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 7157b5af0..a4b0522b0 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1921,7 +1921,7 @@ mod type_keyword {} /// and [proposal]s exist to use `unsafe {}` blocks inside such functions when /// making `unsafe` operations. /// -/// See the [Rustnomicon] and the [Reference] for more informations. +/// See the [Rustnomicon] and the [Reference] for more information. /// /// # Examples /// @@ -2113,7 +2113,7 @@ mod use_keyword {} /// Add constraints that must be upheld to use an item. /// /// `where` allows specifying constraints on lifetime and generic parameters. -/// The [RFC] introducing `where` contains detailed informations about the +/// The [RFC] introducing `where` contains detailed information about the /// keyword. /// /// # Examples @@ -2355,7 +2355,7 @@ mod dyn_keyword {} /// println!("f = {f} and i = {i}"); /// ``` /// -/// See the [Reference][union] for more informations on `union`s. +/// See the [Reference][union] for more information on `union`s. /// /// [`struct`]: keyword.struct.html /// [union]: ../reference/items/unions.html diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 20d25a608..bc4f1b27c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -187,6 +187,7 @@ //! [rust-discord]: https://discord.gg/rust-lang //! [array]: prim@array //! [slice]: prim@slice + #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( @@ -201,25 +202,35 @@ no_global_oom_handling, not(no_global_oom_handling) ))] +// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. +#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] // Don't link to std. We are std. #![no_std] +// Tell the compiler to link to either panic_abort or panic_unwind +#![needs_panic_runtime] +// +// Lints: #![warn(deprecated_in_future)] #![warn(missing_docs)] #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] -// Tell the compiler to link to either panic_abort or panic_unwind -#![needs_panic_runtime] +#![deny(rustc::existing_doc_keyword)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` -#![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))] +#![deny(ffi_unwind_calls)] // std may use features in a platform-specific way #![allow(unused_features)] +// +// Features: #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] -#![deny(rustc::existing_doc_keyword)] // // Language features: #![feature(alloc_error_handler)] @@ -241,11 +252,12 @@ #![feature(dropck_eyepatch)] #![feature(exhaustive_patterns)] #![feature(intra_doc_pointers)] -#![feature(label_break_value)] +#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(lang_items)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(linkage)] +#![feature(link_cfg)] #![feature(min_specialization)] #![feature(must_not_suspend)] #![feature(needs_panic_runtime)] @@ -258,6 +270,7 @@ #![feature(staged_api)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(utf8_chunks)] // // Library features (core): #![feature(array_error_internals)] @@ -269,10 +282,14 @@ #![feature(cstr_internals)] #![feature(duration_checked_float)] #![feature(duration_constants)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] +#![cfg_attr(not(bootstrap), feature(error_in_core))] +#![cfg_attr(not(bootstrap), feature(error_iter))] #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] #![feature(extend_one)] #![feature(float_minimum_maximum)] +#![feature(float_next_up_down)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(int_error_internals)] @@ -284,6 +301,8 @@ #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] +#![feature(pointer_byte_offsets)] +#![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(provide_any)] @@ -294,6 +313,8 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance)] +#![feature(maybe_uninit_uninit_array)] +#![feature(const_maybe_uninit_uninit_array)] // // Library features (alloc): #![feature(alloc_layout_extra)] @@ -576,6 +597,7 @@ pub mod alloc; // Private support modules mod panicking; +mod personality; #[path = "../../backtrace/src/lib.rs"] #[allow(dead_code, unused_attributes)] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 0cb21ef53..6e4ba1404 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -27,17 +27,31 @@ macro_rules! panic { /// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted /// immediately. /// +/// The `print!` macro will lock the standard output on each call. If you call +/// `print!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: +/// ``` +/// use std::io::{stdout, Write}; +/// +/// let mut lock = stdout().lock(); +/// write!(lock, "hello world").unwrap(); +/// ``` +/// /// Use `print!` only for the primary output of your program. Use /// [`eprint!`] instead to print error and progress messages. /// /// [flush]: crate::io::Write::flush /// [`println!`]: crate::println /// [`eprint!`]: crate::eprint +/// [lock]: crate::io::Stdout /// /// # Panics /// /// Panics if writing to `io::stdout()` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` @@ -75,16 +89,30 @@ macro_rules! print { /// This macro uses the same syntax as [`format!`], but writes to the standard output instead. /// See [`std::fmt`] for more information. /// +/// The `println!` macro will lock the standard output on each call. If you call +/// `println!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: +/// ``` +/// use std::io::{stdout, Write}; +/// +/// let mut lock = stdout().lock(); +/// writeln!(lock, "hello world").unwrap(); +/// ``` +/// /// Use `println!` only for the primary output of your program. Use /// [`eprintln!`] instead to print error and progress messages. /// /// [`std::fmt`]: crate::fmt /// [`eprintln!`]: crate::eprintln +/// [lock]: crate::io::Stdout /// /// # Panics /// /// Panics if writing to [`io::stdout`] fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// [`io::stdout`]: crate::io::stdout /// /// # Examples @@ -93,6 +121,8 @@ macro_rules! print { /// println!(); // prints just a newline /// println!("hello there!"); /// println!("format {} arguments", "some"); +/// let local_variable = "some"; +/// println!("format {local_variable} arguments"); /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] @@ -123,6 +153,9 @@ macro_rules! println { /// /// Panics if writing to `io::stderr` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` @@ -155,6 +188,9 @@ macro_rules! eprint { /// /// Panics if writing to `io::stderr` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs deleted file mode 100644 index 53fee952a..000000000 --- a/library/std/src/net/addr.rs +++ /dev/null @@ -1,988 +0,0 @@ -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -use crate::cmp::Ordering; -use crate::fmt; -use crate::hash; -use crate::io::{self, Write}; -use crate::iter; -use crate::mem; -use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use crate::option; -use crate::slice; -use crate::sys::net::netc as c; -use crate::sys_common::net::LookupHost; -use crate::sys_common::{FromInner, IntoInner}; -use crate::vec; - -/// An internet socket address, either IPv4 or IPv6. -/// -/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well -/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and -/// [`SocketAddrV6`]'s respective documentation for more details. -/// -/// The size of a `SocketAddr` instance may vary depending on the target operating -/// system. -/// -/// [IP address]: IpAddr -/// -/// # Examples -/// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -/// -/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); -/// -/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); -/// assert_eq!(socket.port(), 8080); -/// assert_eq!(socket.is_ipv4(), true); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum SocketAddr { - /// An IPv4 socket address. - #[stable(feature = "rust1", since = "1.0.0")] - V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), - /// An IPv6 socket address. - #[stable(feature = "rust1", since = "1.0.0")] - V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), -} - -/// An IPv4 socket address. -/// -/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as -/// stated in [IETF RFC 793]. -/// -/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. -/// -/// The size of a `SocketAddrV4` struct may vary depending on the target operating -/// system. Do not assume that this type has the same memory layout as the underlying -/// system representation. -/// -/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 -/// [`IPv4` address]: Ipv4Addr -/// -/// # Examples -/// -/// ``` -/// use std::net::{Ipv4Addr, SocketAddrV4}; -/// -/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); -/// -/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); -/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); -/// assert_eq!(socket.port(), 8080); -/// ``` -#[derive(Copy, Clone, Eq, PartialEq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SocketAddrV4 { - ip: Ipv4Addr, - port: u16, -} - -/// An IPv6 socket address. -/// -/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well -/// as fields containing the traffic class, the flow label, and a scope identifier -/// (see [IETF RFC 2553, Section 3.3] for more details). -/// -/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. -/// -/// The size of a `SocketAddrV6` struct may vary depending on the target operating -/// system. Do not assume that this type has the same memory layout as the underlying -/// system representation. -/// -/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 -/// [`IPv6` address]: Ipv6Addr -/// -/// # Examples -/// -/// ``` -/// use std::net::{Ipv6Addr, SocketAddrV6}; -/// -/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); -/// -/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); -/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); -/// assert_eq!(socket.port(), 8080); -/// ``` -#[derive(Copy, Clone, Eq, PartialEq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SocketAddrV6 { - ip: Ipv6Addr, - port: u16, - flowinfo: u32, - scope_id: u32, -} - -impl SocketAddr { - /// Creates a new socket address from an [IP address] and a port number. - /// - /// [IP address]: IpAddr - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[stable(feature = "ip_addr", since = "1.7.0")] - #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { - match ip { - IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), - IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), - } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - /// ``` - #[must_use] - #[stable(feature = "ip_addr", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn ip(&self) -> IpAddr { - match *self { - SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), - SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), - } - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: IpAddr) { - // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. - match (self, new_ip) { - (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), - (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), - (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), - } - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn port(&self) -> u16 { - match *self { - SocketAddr::V4(ref a) => a.port(), - SocketAddr::V6(ref a) => a.port(), - } - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// socket.set_port(1025); - /// assert_eq!(socket.port(), 1025); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - match *self { - SocketAddr::V4(ref mut a) => a.set_port(new_port), - SocketAddr::V6(ref mut a) => a.set_port(new_port), - } - } - - /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [`IPv4` address], and [`false`] otherwise. - /// - /// [IP address]: IpAddr - /// [`IPv4` address]: IpAddr::V4 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), true); - /// assert_eq!(socket.is_ipv6(), false); - /// ``` - #[must_use] - #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn is_ipv4(&self) -> bool { - matches!(*self, SocketAddr::V4(_)) - } - - /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [`IPv6` address], and [`false`] otherwise. - /// - /// [IP address]: IpAddr - /// [`IPv6` address]: IpAddr::V6 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), false); - /// assert_eq!(socket.is_ipv6(), true); - /// ``` - #[must_use] - #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn is_ipv6(&self) -> bool { - matches!(*self, SocketAddr::V6(_)) - } -} - -impl SocketAddrV4 { - /// Creates a new socket address from an [`IPv4` address] and a port number. - /// - /// [`IPv4` address]: Ipv4Addr - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { - SocketAddrV4 { ip, port } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn ip(&self) -> &Ipv4Addr { - &self.ip - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); - /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: Ipv4Addr) { - self.ip = new_ip; - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn port(&self) -> u16 { - self.port - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// socket.set_port(4242); - /// assert_eq!(socket.port(), 4242); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - self.port = new_port; - } -} - -impl SocketAddrV6 { - /// Creates a new socket address from an [`IPv6` address], a 16-bit port number, - /// and the `flowinfo` and `scope_id` fields. - /// - /// For more information on the meaning and layout of the `flowinfo` and `scope_id` - /// parameters, see [IETF RFC 2553, Section 3.3]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// [`IPv6` address]: Ipv6Addr - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { - SocketAddrV6 { ip, port, flowinfo, scope_id } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn ip(&self) -> &Ipv6Addr { - &self.ip - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); - /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: Ipv6Addr) { - self.ip = new_ip; - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn port(&self) -> u16 { - self.port - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// socket.set_port(4242); - /// assert_eq!(socket.port(), 4242); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - self.port = new_port; - } - - /// Returns the flow information associated with this address. - /// - /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, - /// as specified in [IETF RFC 2553, Section 3.3]. - /// It combines information about the flow label and the traffic class as specified - /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 - /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 - /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); - /// assert_eq!(socket.flowinfo(), 10); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn flowinfo(&self) -> u32 { - self.flowinfo - } - - /// Changes the flow information associated with this socket address. - /// - /// See [`SocketAddrV6::flowinfo`]'s documentation for more details. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); - /// socket.set_flowinfo(56); - /// assert_eq!(socket.flowinfo(), 56); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_flowinfo(&mut self, new_flowinfo: u32) { - self.flowinfo = new_flowinfo; - } - - /// Returns the scope ID associated with this address. - /// - /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, - /// as specified in [IETF RFC 2553, Section 3.3]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); - /// assert_eq!(socket.scope_id(), 78); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] - pub const fn scope_id(&self) -> u32 { - self.scope_id - } - - /// Changes the scope ID associated with this socket address. - /// - /// See [`SocketAddrV6::scope_id`]'s documentation for more details. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); - /// socket.set_scope_id(42); - /// assert_eq!(socket.scope_id(), 42); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_scope_id(&mut self, new_scope_id: u32) { - self.scope_id = new_scope_id; - } -} - -impl FromInner for SocketAddrV4 { - fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { - SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) } - } -} - -impl FromInner for SocketAddrV6 { - fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { - SocketAddrV6 { - ip: Ipv6Addr::from_inner(addr.sin6_addr), - port: u16::from_be(addr.sin6_port), - flowinfo: addr.sin6_flowinfo, - scope_id: addr.sin6_scope_id, - } - } -} - -impl IntoInner for SocketAddrV4 { - fn into_inner(self) -> c::sockaddr_in { - c::sockaddr_in { - sin_family: c::AF_INET as c::sa_family_t, - sin_port: self.port.to_be(), - sin_addr: self.ip.into_inner(), - ..unsafe { mem::zeroed() } - } - } -} - -impl IntoInner for SocketAddrV6 { - fn into_inner(self) -> c::sockaddr_in6 { - c::sockaddr_in6 { - sin6_family: c::AF_INET6 as c::sa_family_t, - sin6_port: self.port.to_be(), - sin6_addr: self.ip.into_inner(), - sin6_flowinfo: self.flowinfo, - sin6_scope_id: self.scope_id, - ..unsafe { mem::zeroed() } - } - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for SocketAddr { - /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. - fn from(sock4: SocketAddrV4) -> SocketAddr { - SocketAddr::V4(sock4) - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for SocketAddr { - /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. - fn from(sock6: SocketAddrV6) -> SocketAddr { - SocketAddr::V6(sock6) - } -} - -#[stable(feature = "addr_from_into_ip", since = "1.17.0")] -impl> From<(I, u16)> for SocketAddr { - /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. - /// - /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`] - /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`]. - /// - /// `u16` is treated as port of the newly created [`SocketAddr`]. - fn from(pieces: (I, u16)) -> SocketAddr { - SocketAddr::new(pieces.0.into(), pieces.1) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - SocketAddr::V4(ref a) => a.fmt(f), - SocketAddr::V6(ref a) => a.fmt(f), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddrV4 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Fast path: if there's no alignment stuff, write to the output buffer - // directly - if f.precision().is_none() && f.width().is_none() { - write!(f, "{}:{}", self.ip(), self.port()) - } else { - const IPV4_SOCKET_BUF_LEN: usize = (3 * 4) // the segments - + 3 // the separators - + 1 + 5; // the port - let mut buf = [0; IPV4_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - // Unwrap is fine because writing to a sufficiently-sized - // buffer is infallible - write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); - let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); - - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SocketAddrV4 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddrV6 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Fast path: if there's no alignment stuff, write to the output - // buffer directly - if f.precision().is_none() && f.width().is_none() { - match self.scope_id() { - 0 => write!(f, "[{}]:{}", self.ip(), self.port()), - scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()), - } - } else { - const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address - + 7 // The colon separators - + 2 // The brackets - + 1 + 10 // The scope id - + 1 + 5; // The port - - let mut buf = [0; IPV6_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - match self.scope_id() { - 0 => write!(buf_slice, "[{}]:{}", self.ip(), self.port()), - scope_id => write!(buf_slice, "[{}%{}]:{}", self.ip(), scope_id, self.port()), - } - // Unwrap is fine because writing to a sufficiently-sized - // buffer is infallible - .unwrap(); - let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); - - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SocketAddrV6 { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV4 { - fn partial_cmp(&self, other: &SocketAddrV4) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV6 { - fn partial_cmp(&self, other: &SocketAddrV6) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl Ord for SocketAddrV4 { - fn cmp(&self, other: &SocketAddrV4) -> Ordering { - self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl Ord for SocketAddrV6 { - fn cmp(&self, other: &SocketAddrV6) -> Ordering { - self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV4 { - fn hash(&self, s: &mut H) { - (self.port, self.ip).hash(s) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV6 { - fn hash(&self, s: &mut H) { - (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s) - } -} - -/// A trait for objects which can be converted or resolved to one or more -/// [`SocketAddr`] values. -/// -/// This trait is used for generic address resolution when constructing network -/// objects. By default it is implemented for the following types: -/// -/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. -/// -/// * [`SocketAddrV4`], [`SocketAddrV6`], ([IpAddr], [u16]), -/// ([Ipv4Addr], [u16]), ([Ipv6Addr], [u16]): -/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. -/// -/// * (&[str], [u16]): &[str] should be either a string representation -/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. [`u16`] is the port number. -/// -/// * &[str]: the string should be either a string representation of a -/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like -/// `:` pair where `` is a [`u16`] value. -/// -/// This trait allows constructing network objects like [`TcpStream`] or -/// [`UdpSocket`] easily with values of various types for the bind/connection -/// address. It is needed because sometimes one type is more appropriate than -/// the other: for simple uses a string like `"localhost:12345"` is much nicer -/// than manual construction of the corresponding [`SocketAddr`], but sometimes -/// [`SocketAddr`] value is *the* main source of the address, and converting it to -/// some other type (e.g., a string) just for it to be converted back to -/// [`SocketAddr`] in constructor methods is pointless. -/// -/// Addresses returned by the operating system that are not IP addresses are -/// silently ignored. -/// -/// [`FromStr`]: crate::str::FromStr "std::str::FromStr" -/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream" -/// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs -/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket" -/// -/// # Examples -/// -/// Creating a [`SocketAddr`] iterator that yields one item: -/// -/// ``` -/// use std::net::{ToSocketAddrs, SocketAddr}; -/// -/// let addr = SocketAddr::from(([127, 0, 0, 1], 443)); -/// let mut addrs_iter = addr.to_socket_addrs().unwrap(); -/// -/// assert_eq!(Some(addr), addrs_iter.next()); -/// assert!(addrs_iter.next().is_none()); -/// ``` -/// -/// Creating a [`SocketAddr`] iterator from a hostname: -/// -/// ```no_run -/// use std::net::{SocketAddr, ToSocketAddrs}; -/// -/// // assuming 'localhost' resolves to 127.0.0.1 -/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap(); -/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443)))); -/// assert!(addrs_iter.next().is_none()); -/// -/// // assuming 'foo' does not resolve -/// assert!("foo:443".to_socket_addrs().is_err()); -/// ``` -/// -/// Creating a [`SocketAddr`] iterator that yields multiple items: -/// -/// ``` -/// use std::net::{SocketAddr, ToSocketAddrs}; -/// -/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80)); -/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443)); -/// let addrs = vec![addr1, addr2]; -/// -/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap(); -/// -/// assert_eq!(Some(addr1), addrs_iter.next()); -/// assert_eq!(Some(addr2), addrs_iter.next()); -/// assert!(addrs_iter.next().is_none()); -/// ``` -/// -/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted -/// socket address `&str` (missing the port): -/// -/// ``` -/// use std::io; -/// use std::net::ToSocketAddrs; -/// -/// let err = "127.0.0.1".to_socket_addrs().unwrap_err(); -/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); -/// ``` -/// -/// [`TcpStream::connect`] is an example of an function that utilizes -/// `ToSocketAddrs` as a trait bound on its parameter in order to accept -/// different types: -/// -/// ```no_run -/// use std::net::{TcpStream, Ipv4Addr}; -/// -/// let stream = TcpStream::connect(("127.0.0.1", 443)); -/// // or -/// let stream = TcpStream::connect("127.0.0.1:443"); -/// // or -/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443)); -/// ``` -/// -/// [`TcpStream::connect`]: crate::net::TcpStream::connect -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ToSocketAddrs { - /// Returned iterator over socket addresses which this type may correspond - /// to. - #[stable(feature = "rust1", since = "1.0.0")] - type Iter: Iterator; - - /// Converts this object to an iterator of resolved [`SocketAddr`]s. - /// - /// The returned iterator might not actually yield any values depending on the - /// outcome of any resolution performed. - /// - /// Note that this function may block the current thread while resolution is - /// performed. - #[stable(feature = "rust1", since = "1.0.0")] - fn to_socket_addrs(&self) -> io::Result; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddr { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - Ok(Some(*self).into_iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddrV4 { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - SocketAddr::V4(*self).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddrV6 { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - SocketAddr::V6(*self).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (IpAddr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - match ip { - IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), - IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (Ipv4Addr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddrV4::new(ip, port).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (Ipv6Addr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs() - } -} - -fn resolve_socket_addr(lh: LookupHost) -> io::Result> { - let p = lh.port(); - let v: Vec<_> = lh - .map(|mut a| { - a.set_port(p); - a - }) - .collect(); - Ok(v.into_iter()) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (&str, u16) { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (host, port) = *self; - - // try to parse the host as a regular IP address first - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV4::new(addr, port); - return Ok(vec![SocketAddr::V4(addr)].into_iter()); - } - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV6::new(addr, port, 0, 0); - return Ok(vec![SocketAddr::V6(addr)].into_iter()); - } - - resolve_socket_addr((host, port).try_into()?) - } -} - -#[stable(feature = "string_u16_to_socket_addrs", since = "1.46.0")] -impl ToSocketAddrs for (String, u16) { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (&*self.0, self.1).to_socket_addrs() - } -} - -// accepts strings like 'localhost:12345' -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for str { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - // try to parse as a regular SocketAddr first - if let Ok(addr) = self.parse() { - return Ok(vec![addr].into_iter()); - } - - resolve_socket_addr(self.try_into()?) - } -} - -#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")] -impl<'a> ToSocketAddrs for &'a [SocketAddr] { - type Iter = iter::Cloned>; - - fn to_socket_addrs(&self) -> io::Result { - Ok(self.iter().cloned()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for &T { - type Iter = T::Iter; - fn to_socket_addrs(&self) -> io::Result { - (**self).to_socket_addrs() - } -} - -#[stable(feature = "string_to_socket_addrs", since = "1.16.0")] -impl ToSocketAddrs for String { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (&**self).to_socket_addrs() - } -} diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs deleted file mode 100644 index 585a17451..000000000 --- a/library/std/src/net/addr/tests.rs +++ /dev/null @@ -1,237 +0,0 @@ -use crate::net::test::{sa4, sa6, tsa}; -use crate::net::*; - -#[test] -fn to_socket_addr_ipaddr_u16() { - let a = Ipv4Addr::new(77, 88, 21, 11); - let p = 12345; - let e = SocketAddr::V4(SocketAddrV4::new(a, p)); - assert_eq!(Ok(vec![e]), tsa((a, p))); -} - -#[test] -fn to_socket_addr_str_u16() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - #[cfg(not(target_env = "sgx"))] - assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); - #[cfg(target_env = "sgx")] - let _ = a; -} - -#[test] -fn to_socket_addr_str() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - #[cfg(not(target_env = "sgx"))] - assert!(tsa("localhost:23924").unwrap().contains(&a)); - #[cfg(target_env = "sgx")] - let _ = a; -} - -#[test] -fn to_socket_addr_string() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); - - let s = format!("{}:{}", "77.88.21.11", "24352"); - assert_eq!(Ok(vec![a]), tsa(s)); - // s has been moved into the tsa call -} - -#[test] -fn bind_udp_socket_bad() { - // rust-lang/rust#53957: This is a regression test for a parsing problem - // discovered as part of issue rust-lang/rust#23076, where we were - // incorrectly parsing invalid input and then that would result in a - // successful `UdpSocket` binding when we would expect failure. - // - // At one time, this test was written as a call to `tsa` with - // INPUT_23076. However, that structure yields an unreliable test, - // because it ends up passing junk input to the DNS server, and some DNS - // servers will respond with `Ok` to such input, with the ip address of - // the DNS server itself. - // - // This form of the test is more robust: even when the DNS server - // returns its own address, it is still an error to bind a UDP socket to - // a non-local address, and so we still get an error here in that case. - - const INPUT_23076: &str = "1200::AB00:1234::2552:7777:1313:34300"; - - assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err()) -} - -#[test] -fn set_ip() { - fn ip4(low: u8) -> Ipv4Addr { - Ipv4Addr::new(77, 88, 21, low) - } - fn ip6(low: u16) -> Ipv6Addr { - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) - } - - let mut v4 = SocketAddrV4::new(ip4(11), 80); - assert_eq!(v4.ip(), &ip4(11)); - v4.set_ip(ip4(12)); - assert_eq!(v4.ip(), &ip4(12)); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); - addr.set_ip(IpAddr::V4(ip4(13))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); - addr.set_ip(IpAddr::V6(ip6(14))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); - - let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); - assert_eq!(v6.ip(), &ip6(1)); - v6.set_ip(ip6(2)); - assert_eq!(v6.ip(), &ip6(2)); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); - addr.set_ip(IpAddr::V6(ip6(3))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); - addr.set_ip(IpAddr::V4(ip4(4))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); -} - -#[test] -fn set_port() { - let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); - assert_eq!(v4.port(), 80); - v4.set_port(443); - assert_eq!(v4.port(), 443); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); - assert_eq!(v6.port(), 80); - v6.set_port(443); - assert_eq!(v6.port(), 443); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); -} - -#[test] -fn set_flowinfo() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); - assert_eq!(v6.flowinfo(), 10); - v6.set_flowinfo(20); - assert_eq!(v6.flowinfo(), 20); -} - -#[test] -fn set_scope_id() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); - assert_eq!(v6.scope_id(), 10); - v6.set_scope_id(20); - assert_eq!(v6.scope_id(), 20); -} - -#[test] -fn is_v4() { - let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); - assert!(v4.is_ipv4()); - assert!(!v4.is_ipv6()); -} - -#[test] -fn is_v6() { - let v6 = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), - 80, - 10, - 0, - )); - assert!(!v6.is_ipv4()); - assert!(v6.is_ipv6()); -} - -#[test] -fn socket_v4_to_str() { - let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); - - assert_eq!(format!("{socket}"), "192.168.0.1:8080"); - assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 "); - assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080"); - assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 "); - assert_eq!(format!("{socket:.10}"), "192.168.0."); -} - -#[test] -fn socket_v6_to_str() { - let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); - - assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::"); - - socket.set_scope_id(5); - - assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5"); -} - -#[test] -fn compare() { - let v4_1 = "224.120.45.1:23456".parse::().unwrap(); - let v4_2 = "224.210.103.5:12345".parse::().unwrap(); - let v4_3 = "224.210.103.5:23456".parse::().unwrap(); - let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); - let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); - let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); - - // equality - assert_eq!(v4_1, v4_1); - assert_eq!(v6_1, v6_1); - assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); - assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); - assert!(v4_1 != v4_2); - assert!(v6_1 != v6_2); - - // compare different addresses - assert!(v4_1 < v4_2); - assert!(v6_1 < v6_2); - assert!(v4_2 > v4_1); - assert!(v6_2 > v6_1); - - // compare the same address with different ports - assert!(v4_2 < v4_3); - assert!(v6_2 < v6_3); - assert!(v4_3 > v4_2); - assert!(v6_3 > v6_2); - - // compare different addresses with the same port - assert!(v4_1 < v4_3); - assert!(v6_1 < v6_3); - assert!(v4_3 > v4_1); - assert!(v6_3 > v6_1); - - // compare with an inferred right-hand side - assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); - assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); - assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); -} diff --git a/library/std/src/net/display_buffer.rs b/library/std/src/net/display_buffer.rs new file mode 100644 index 000000000..7aadf06e9 --- /dev/null +++ b/library/std/src/net/display_buffer.rs @@ -0,0 +1,40 @@ +use crate::fmt; +use crate::mem::MaybeUninit; +use crate::str; + +/// Used for slow path in `Display` implementations when alignment is required. +pub struct DisplayBuffer { + buf: [MaybeUninit; SIZE], + len: usize, +} + +impl DisplayBuffer { + #[inline] + pub const fn new() -> Self { + Self { buf: MaybeUninit::uninit_array(), len: 0 } + } + + #[inline] + pub fn as_str(&self) -> &str { + // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation + // which writes a valid UTF-8 string to `buf` and correctly sets `len`. + unsafe { + let s = MaybeUninit::slice_assume_init_ref(&self.buf[..self.len]); + str::from_utf8_unchecked(s) + } + } +} + +impl fmt::Write for DisplayBuffer { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + + if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) { + MaybeUninit::write_slice(buf, bytes); + self.len += bytes.len(); + Ok(()) + } else { + Err(fmt::Error) + } + } +} diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs deleted file mode 100644 index 41ca9ba84..000000000 --- a/library/std/src/net/ip.rs +++ /dev/null @@ -1,2040 +0,0 @@ -// Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -use crate::cmp::Ordering; -use crate::fmt::{self, Write as FmtWrite}; -use crate::io::Write as IoWrite; -use crate::mem::transmute; -use crate::sys::net::netc as c; -use crate::sys_common::{FromInner, IntoInner}; - -/// An IP address, either IPv4 or IPv6. -/// -/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their -/// respective documentation for more details. -/// -/// # Examples -/// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -/// -/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); -/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); -/// -/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); -/// assert_eq!("::1".parse(), Ok(localhost_v6)); -/// -/// assert_eq!(localhost_v4.is_ipv6(), false); -/// assert_eq!(localhost_v4.is_ipv4(), true); -/// ``` -#[stable(feature = "ip_addr", since = "1.7.0")] -#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] -pub enum IpAddr { - /// An IPv4 address. - #[stable(feature = "ip_addr", since = "1.7.0")] - V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), - /// An IPv6 address. - #[stable(feature = "ip_addr", since = "1.7.0")] - V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), -} - -/// An IPv4 address. -/// -/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. -/// They are usually represented as four octets. -/// -/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. -/// -/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 -/// -/// # Textual representation -/// -/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal -/// notation, divided by `.` (this is called "dot-decimal notation"). -/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which -/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. -/// -/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 -/// [`FromStr`]: crate::str::FromStr -/// -/// # Examples -/// -/// ``` -/// use std::net::Ipv4Addr; -/// -/// let localhost = Ipv4Addr::new(127, 0, 0, 1); -/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); -/// assert_eq!(localhost.is_loopback(), true); -/// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal -/// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal -/// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Ipv4Addr { - octets: [u8; 4], -} - -/// An IPv6 address. -/// -/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. -/// They are usually represented as eight 16-bit segments. -/// -/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 -/// -/// # Embedding IPv4 Addresses -/// -/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. -/// -/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: -/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. -/// -/// Both types of addresses are not assigned any special meaning by this implementation, -/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, -/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. -/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. -/// -/// ### IPv4-Compatible IPv6 Addresses -/// -/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. -/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: -/// -/// ```text -/// | 80 bits | 16 | 32 bits | -/// +--------------------------------------+--------------------------+ -/// |0000..............................0000|0000| IPv4 address | -/// +--------------------------------------+----+---------------------+ -/// ``` -/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. -/// -/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. -/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. -/// -/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 -/// -/// ### IPv4-Mapped IPv6 Addresses -/// -/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. -/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: -/// -/// ```text -/// | 80 bits | 16 | 32 bits | -/// +--------------------------------------+--------------------------+ -/// |0000..............................0000|FFFF| IPv4 address | -/// +--------------------------------------+----+---------------------+ -/// ``` -/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. -/// -/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. -/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. -/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use -/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. -/// -/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 -/// -/// # Textual representation -/// -/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent -/// an IPv6 address in text, but in general, each segments is written in hexadecimal -/// notation, and segments are separated by `:`. For more information, see -/// [IETF RFC 5952]. -/// -/// [`FromStr`]: crate::str::FromStr -/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 -/// -/// # Examples -/// -/// ``` -/// use std::net::Ipv6Addr; -/// -/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); -/// assert_eq!("::1".parse(), Ok(localhost)); -/// assert_eq!(localhost.is_loopback(), true); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Ipv6Addr { - octets: [u8; 16], -} - -/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. -/// -/// # Stability Guarantees -/// -/// Not all possible values for a multicast scope have been assigned. -/// Future RFCs may introduce new scopes, which will be added as variants to this enum; -/// because of this the enum is marked as `#[non_exhaustive]`. -/// -/// # Examples -/// ``` -/// #![feature(ip)] -/// -/// use std::net::Ipv6Addr; -/// use std::net::Ipv6MulticastScope::*; -/// -/// // An IPv6 multicast address with global scope (`ff0e::`). -/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); -/// -/// // Will print "Global scope". -/// match address.multicast_scope() { -/// Some(InterfaceLocal) => println!("Interface-Local scope"), -/// Some(LinkLocal) => println!("Link-Local scope"), -/// Some(RealmLocal) => println!("Realm-Local scope"), -/// Some(AdminLocal) => println!("Admin-Local scope"), -/// Some(SiteLocal) => println!("Site-Local scope"), -/// Some(OrganizationLocal) => println!("Organization-Local scope"), -/// Some(Global) => println!("Global scope"), -/// Some(_) => println!("Unknown scope"), -/// None => println!("Not a multicast address!") -/// } -/// -/// ``` -/// -/// [IPv6 multicast address]: Ipv6Addr -/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] -#[unstable(feature = "ip", issue = "27709")] -#[non_exhaustive] -pub enum Ipv6MulticastScope { - /// Interface-Local scope. - InterfaceLocal, - /// Link-Local scope. - LinkLocal, - /// Realm-Local scope. - RealmLocal, - /// Admin-Local scope. - AdminLocal, - /// Site-Local scope. - SiteLocal, - /// Organization-Local scope. - OrganizationLocal, - /// Global scope. - Global, -} - -impl IpAddr { - /// Returns [`true`] for the special 'unspecified' address. - /// - /// See the documentation for [`Ipv4Addr::is_unspecified()`] and - /// [`Ipv6Addr::is_unspecified()`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "ip_shared", since = "1.12.0")] - #[must_use] - #[inline] - pub const fn is_unspecified(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_unspecified(), - IpAddr::V6(ip) => ip.is_unspecified(), - } - } - - /// Returns [`true`] if this is a loopback address. - /// - /// See the documentation for [`Ipv4Addr::is_loopback()`] and - /// [`Ipv6Addr::is_loopback()`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "ip_shared", since = "1.12.0")] - #[must_use] - #[inline] - pub const fn is_loopback(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_loopback(), - IpAddr::V6(ip) => ip.is_loopback(), - } - } - - /// Returns [`true`] if the address appears to be globally routable. - /// - /// See the documentation for [`Ipv4Addr::is_global()`] and - /// [`Ipv6Addr::is_global()`] for more details. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_global(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_global(), - IpAddr::V6(ip) => ip.is_global(), - } - } - - /// Returns [`true`] if this is a multicast address. - /// - /// See the documentation for [`Ipv4Addr::is_multicast()`] and - /// [`Ipv6Addr::is_multicast()`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "ip_shared", since = "1.12.0")] - #[must_use] - #[inline] - pub const fn is_multicast(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_multicast(), - IpAddr::V6(ip) => ip.is_multicast(), - } - } - - /// Returns [`true`] if this address is in a range designated for documentation. - /// - /// See the documentation for [`Ipv4Addr::is_documentation()`] and - /// [`Ipv6Addr::is_documentation()`] for more details. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); - /// assert_eq!( - /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), - /// true - /// ); - /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_documentation(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_documentation(), - IpAddr::V6(ip) => ip.is_documentation(), - } - } - - /// Returns [`true`] if this address is in a range designated for benchmarking. - /// - /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and - /// [`Ipv6Addr::is_benchmarking()`] for more details. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); - /// ``` - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_benchmarking(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_benchmarking(), - IpAddr::V6(ip) => ip.is_benchmarking(), - } - } - - /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] - /// otherwise. - /// - /// [`IPv4` address]: IpAddr::V4 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "ipaddr_checker", since = "1.16.0")] - #[must_use] - #[inline] - pub const fn is_ipv4(&self) -> bool { - matches!(self, IpAddr::V4(_)) - } - - /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] - /// otherwise. - /// - /// [`IPv6` address]: IpAddr::V6 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "ipaddr_checker", since = "1.16.0")] - #[must_use] - #[inline] - pub const fn is_ipv6(&self) -> bool { - matches!(self, IpAddr::V6(_)) - } - - /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it - /// return `self` as-is. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); - /// ``` - #[inline] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - pub const fn to_canonical(&self) -> IpAddr { - match self { - &v4 @ IpAddr::V4(_) => v4, - IpAddr::V6(v6) => v6.to_canonical(), - } - } -} - -impl Ipv4Addr { - /// Creates a new IPv4 address from four eight-bit octets. - /// - /// The result will represent the IP address `a`.`b`.`c`.`d`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(127, 0, 0, 1); - /// ``` - #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - Ipv4Addr { octets: [a, b, c, d] } - } - - /// An IPv4 address with the address pointing to localhost: `127.0.0.1` - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::LOCALHOST; - /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); - /// ``` - #[stable(feature = "ip_constructors", since = "1.30.0")] - pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - - /// An IPv4 address representing an unspecified address: `0.0.0.0` - /// - /// This corresponds to the constant `INADDR_ANY` in other languages. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::UNSPECIFIED; - /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); - /// ``` - #[doc(alias = "INADDR_ANY")] - #[stable(feature = "ip_constructors", since = "1.30.0")] - pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); - - /// An IPv4 address representing the broadcast address: `255.255.255.255` - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::BROADCAST; - /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); - /// ``` - #[stable(feature = "ip_constructors", since = "1.30.0")] - pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); - - /// Returns the four eight-bit integers that make up this address. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(127, 0, 0, 1); - /// assert_eq!(addr.octets(), [127, 0, 0, 1]); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub const fn octets(&self) -> [u8; 4] { - self.octets - } - - /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). - /// - /// This property is defined in _UNIX Network Programming, Second Edition_, - /// W. Richard Stevens, p. 891; see also [ip7]. - /// - /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); - /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] - #[stable(feature = "ip_shared", since = "1.12.0")] - #[must_use] - #[inline] - pub const fn is_unspecified(&self) -> bool { - u32::from_be_bytes(self.octets) == 0 - } - - /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). - /// - /// This property is defined by [IETF RFC 1122]. - /// - /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); - /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_loopback(&self) -> bool { - self.octets()[0] == 127 - } - - /// Returns [`true`] if this is a private address. - /// - /// The private address ranges are defined in [IETF RFC 1918] and include: - /// - /// - `10.0.0.0/8` - /// - `172.16.0.0/12` - /// - `192.168.0.0/16` - /// - /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); - /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); - /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_private(&self) -> bool { - match self.octets() { - [10, ..] => true, - [172, b, ..] if b >= 16 && b <= 31 => true, - [192, 168, ..] => true, - _ => false, - } - } - - /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). - /// - /// This property is defined by [IETF RFC 3927]. - /// - /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); - /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); - /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_link_local(&self) -> bool { - matches!(self.octets(), [169, 254, ..]) - } - - /// Returns [`true`] if the address appears to be globally routable. - /// See [iana-ipv4-special-registry][ipv4-sr]. - /// - /// The following return [`false`]: - /// - /// - private addresses (see [`Ipv4Addr::is_private()`]) - /// - the loopback address (see [`Ipv4Addr::is_loopback()`]) - /// - the link-local address (see [`Ipv4Addr::is_link_local()`]) - /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`]) - /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`]) - /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole - /// `0.0.0.0/8` block - /// - addresses reserved for future protocols, except - /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable - /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`] - /// - addresses reserved for networking devices benchmarking (see - /// [`Ipv4Addr::is_benchmarking()`]) - /// - /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv4Addr; - /// - /// // private addresses are not global - /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); - /// - /// // the 0.0.0.0/8 block is not global - /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); - /// // in particular, the unspecified address is not global - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); - /// - /// // the loopback address is not global - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); - /// - /// // link local addresses are not global - /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); - /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); - /// - /// // the address space designated for documentation is not global - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); - /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); - /// - /// // shared addresses are not global - /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); - /// - /// // addresses reserved for protocol assignment are not global - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); - /// - /// // addresses reserved for future use are not global - /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); - /// - /// // addresses reserved for network devices benchmarking are not global - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); - /// - /// // All the other addresses are global - /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); - /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_global(&self) -> bool { - // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two - // globally routable addresses in the 192.0.0.0/24 range. - if u32::from_be_bytes(self.octets()) == 0xc0000009 - || u32::from_be_bytes(self.octets()) == 0xc000000a - { - return true; - } - !self.is_private() - && !self.is_loopback() - && !self.is_link_local() - && !self.is_broadcast() - && !self.is_documentation() - && !self.is_shared() - // addresses reserved for future protocols (`192.0.0.0/24`) - && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) - && !self.is_reserved() - && !self.is_benchmarking() - // Make sure the address is not in 0.0.0.0/8 - && self.octets()[0] != 0 - } - - /// Returns [`true`] if this address is part of the Shared Address Space defined in - /// [IETF RFC 6598] (`100.64.0.0/10`). - /// - /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); - /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); - /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_shared(&self) -> bool { - self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) - } - - /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for - /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` - /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. - /// - /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 - /// [errata 423]: https://www.rfc-editor.org/errata/eid423 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); - /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); - /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_benchmarking(&self) -> bool { - self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 - } - - /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] - /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the - /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since - /// it is obviously not reserved for future use. - /// - /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 - /// - /// # Warning - /// - /// As IANA assigns new addresses, this method will be - /// updated. This may result in non-reserved addresses being - /// treated as reserved in code that relies on an outdated version - /// of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); - /// - /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); - /// // The broadcast address is not considered as reserved for future use by this implementation - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); - /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_reserved(&self) -> bool { - self.octets()[0] & 240 == 240 && !self.is_broadcast() - } - - /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). - /// - /// Multicast addresses have a most significant octet between `224` and `239`, - /// and is defined by [IETF RFC 5771]. - /// - /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); - /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_multicast(&self) -> bool { - self.octets()[0] >= 224 && self.octets()[0] <= 239 - } - - /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). - /// - /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. - /// - /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); - /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_broadcast(&self) -> bool { - u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) - } - - /// Returns [`true`] if this address is in a range designated for documentation. - /// - /// This is defined in [IETF RFC 5737]: - /// - /// - `192.0.2.0/24` (TEST-NET-1) - /// - `198.51.100.0/24` (TEST-NET-2) - /// - `203.0.113.0/24` (TEST-NET-3) - /// - /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_documentation(&self) -> bool { - matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _]) - } - - /// Converts this address to an [IPv4-compatible] [`IPv6` address]. - /// - /// `a.b.c.d` becomes `::a.b.c.d` - /// - /// Note that IPv4-compatible addresses have been officially deprecated. - /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. - /// - /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses - /// [`IPv6` address]: Ipv6Addr - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!( - /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) - /// ); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { - let [a, b, c, d] = self.octets(); - Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] } - } - - /// Converts this address to an [IPv4-mapped] [`IPv6` address]. - /// - /// `a.b.c.d` becomes `::ffff:a.b.c.d` - /// - /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses - /// [`IPv6` address]: Ipv6Addr - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { - let [a, b, c, d] = self.octets(); - Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] } - } -} - -#[stable(feature = "ip_addr", since = "1.7.0")] -impl fmt::Display for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - IpAddr::V4(ip) => ip.fmt(fmt), - IpAddr::V6(ip) => ip.fmt(fmt), - } - } -} - -#[stable(feature = "ip_addr", since = "1.7.0")] -impl fmt::Debug for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for IpAddr { - /// Copies this address to a new `IpAddr::V4`. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr}; - /// - /// let addr = Ipv4Addr::new(127, 0, 0, 1); - /// - /// assert_eq!( - /// IpAddr::V4(addr), - /// IpAddr::from(addr) - /// ) - /// ``` - #[inline] - fn from(ipv4: Ipv4Addr) -> IpAddr { - IpAddr::V4(ipv4) - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for IpAddr { - /// Copies this address to a new `IpAddr::V6`. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr}; - /// - /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); - /// - /// assert_eq!( - /// IpAddr::V6(addr), - /// IpAddr::from(addr) - /// ); - /// ``` - #[inline] - fn from(ipv6: Ipv6Addr) -> IpAddr { - IpAddr::V6(ipv6) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let octets = self.octets(); - // Fast Path: if there's no alignment stuff, write directly to the buffer - if fmt.precision().is_none() && fmt.width().is_none() { - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) - } else { - const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address - let mut buf = [0u8; IPV4_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - // Note: The call to write should never fail, hence the unwrap - write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); - let len = IPV4_BUF_LEN - buf_slice.len(); - - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - fmt.pad(buf) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for IpAddr { - #[inline] - fn eq(&self, other: &Ipv4Addr) -> bool { - match self { - IpAddr::V4(v4) => v4 == other, - IpAddr::V6(_) => false, - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for Ipv4Addr { - #[inline] - fn eq(&self, other: &IpAddr) -> bool { - match other { - IpAddr::V4(v4) => self == v4, - IpAddr::V6(_) => false, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv4Addr { - #[inline] - fn partial_cmp(&self, other: &Ipv4Addr) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for IpAddr { - #[inline] - fn partial_cmp(&self, other: &Ipv4Addr) -> Option { - match self { - IpAddr::V4(v4) => v4.partial_cmp(other), - IpAddr::V6(_) => Some(Ordering::Greater), - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for Ipv4Addr { - #[inline] - fn partial_cmp(&self, other: &IpAddr) -> Option { - match other { - IpAddr::V4(v4) => self.partial_cmp(v4), - IpAddr::V6(_) => Some(Ordering::Less), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv4Addr { - #[inline] - fn cmp(&self, other: &Ipv4Addr) -> Ordering { - self.octets.cmp(&other.octets) - } -} - -impl IntoInner for Ipv4Addr { - #[inline] - fn into_inner(self) -> c::in_addr { - // `s_addr` is stored as BE on all machines and the array is in BE order. - // So the native endian conversion method is used so that it's never swapped. - c::in_addr { s_addr: u32::from_ne_bytes(self.octets) } - } -} -impl FromInner for Ipv4Addr { - fn from_inner(addr: c::in_addr) -> Ipv4Addr { - Ipv4Addr { octets: addr.s_addr.to_ne_bytes() } - } -} - -#[stable(feature = "ip_u32", since = "1.1.0")] -impl From for u32 { - /// Converts an `Ipv4Addr` into a host byte order `u32`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); - /// assert_eq!(0x12345678, u32::from(addr)); - /// ``` - #[inline] - fn from(ip: Ipv4Addr) -> u32 { - u32::from_be_bytes(ip.octets) - } -} - -#[stable(feature = "ip_u32", since = "1.1.0")] -impl From for Ipv4Addr { - /// Converts a host byte order `u32` into an `Ipv4Addr`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::from(0x12345678); - /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); - /// ``` - #[inline] - fn from(ip: u32) -> Ipv4Addr { - Ipv4Addr { octets: ip.to_be_bytes() } - } -} - -#[stable(feature = "from_slice_v4", since = "1.9.0")] -impl From<[u8; 4]> for Ipv4Addr { - /// Creates an `Ipv4Addr` from a four element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); - /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); - /// ``` - #[inline] - fn from(octets: [u8; 4]) -> Ipv4Addr { - Ipv4Addr { octets } - } -} - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u8; 4]> for IpAddr { - /// Creates an `IpAddr::V4` from a four element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr}; - /// - /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); - /// ``` - #[inline] - fn from(octets: [u8; 4]) -> IpAddr { - IpAddr::V4(Ipv4Addr::from(octets)) - } -} - -impl Ipv6Addr { - /// Creates a new IPv6 address from eight 16-bit segments. - /// - /// The result will represent the IP address `a:b:c:d:e:f:g:h`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); - /// ``` - #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { - let addr16 = [ - a.to_be(), - b.to_be(), - c.to_be(), - d.to_be(), - e.to_be(), - f.to_be(), - g.to_be(), - h.to_be(), - ]; - Ipv6Addr { - // All elements in `addr16` are big endian. - // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. - octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, - } - } - - /// An IPv6 address representing localhost: `::1`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::LOCALHOST; - /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - /// ``` - #[stable(feature = "ip_constructors", since = "1.30.0")] - pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - - /// An IPv6 address representing the unspecified address: `::` - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::UNSPECIFIED; - /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - /// ``` - #[stable(feature = "ip_constructors", since = "1.30.0")] - pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); - - /// Returns the eight 16-bit segments that make up this address. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), - /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub const fn segments(&self) -> [u16; 8] { - // All elements in `self.octets` must be big endian. - // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. - let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; - // We want native endian u16 - [ - u16::from_be(a), - u16::from_be(b), - u16::from_be(c), - u16::from_be(d), - u16::from_be(e), - u16::from_be(f), - u16::from_be(g), - u16::from_be(h), - ] - } - - /// Returns [`true`] for the special 'unspecified' address (`::`). - /// - /// This property is defined in [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_unspecified(&self) -> bool { - u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) - } - - /// Returns [`true`] if this is the [loopback address] (`::1`), - /// as defined in [IETF RFC 4291 section 2.5.3]. - /// - /// Contrary to IPv4, in IPv6 there is only one loopback address. - /// - /// [loopback address]: Ipv6Addr::LOCALHOST - /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_loopback(&self) -> bool { - u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) - } - - /// Returns [`true`] if the address appears to be globally routable. - /// - /// The following return [`false`]: - /// - /// - the loopback address - /// - link-local and unique local unicast addresses - /// - interface-, link-, realm-, admin- and site-local multicast addresses - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_global(&self) -> bool { - match self.multicast_scope() { - Some(Ipv6MulticastScope::Global) => true, - None => self.is_unicast_global(), - _ => false, - } - } - - /// Returns [`true`] if this is a unique local address (`fc00::/7`). - /// - /// This property is defined in [IETF RFC 4193]. - /// - /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); - /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_unique_local(&self) -> bool { - (self.segments()[0] & 0xfe00) == 0xfc00 - } - - /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. - /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [multicast address]: Ipv6Addr::is_multicast - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// // The unspecified and loopback addresses are unicast. - /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); - /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); - /// - /// // Any address that is not a multicast address (`ff00::/8`) is unicast. - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_unicast(&self) -> bool { - !self.is_multicast() - } - - /// Returns `true` if the address is a unicast address with link-local scope, - /// as defined in [RFC 4291]. - /// - /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. - /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], - /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: - /// - /// ```text - /// | 10 bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111010| 0 | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, - /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, - /// and those addresses will have link-local scope. - /// - /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", - /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. - /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 - /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 - /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 - /// [loopback address]: Ipv6Addr::LOCALHOST - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// // The loopback address (`::1`) does not actually have link-local scope. - /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); - /// - /// // Only addresses in `fe80::/10` have link-local scope. - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); - /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); - /// - /// // Addresses outside the stricter `fe80::/64` also have link-local scope. - /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); - /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_unicast_link_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfe80 - } - - /// Returns [`true`] if this is an address reserved for documentation - /// (`2001:db8::/32`). - /// - /// This property is defined in [IETF RFC 3849]. - /// - /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_documentation(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) - } - - /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). - /// - /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. - /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. - /// - /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 - /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); - /// ``` - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_benchmarking(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) - } - - /// Returns [`true`] if the address is a globally routable unicast address. - /// - /// The following return false: - /// - /// - the loopback address - /// - the link-local addresses - /// - unique local addresses - /// - the unspecified address - /// - the address range reserved for documentation - /// - /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] - /// - /// ```no_rust - /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer - /// be supported in new implementations (i.e., new implementations must treat this prefix as - /// Global Unicast). - /// ``` - /// - /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn is_unicast_global(&self) -> bool { - self.is_unicast() - && !self.is_loopback() - && !self.is_unicast_link_local() - && !self.is_unique_local() - && !self.is_unspecified() - && !self.is_documentation() - } - - /// Returns the address's multicast scope if the address is multicast. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; - /// - /// assert_eq!( - /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), - /// Some(Ipv6MulticastScope::Global) - /// ); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use] - #[inline] - pub const fn multicast_scope(&self) -> Option { - if self.is_multicast() { - match self.segments()[0] & 0x000f { - 1 => Some(Ipv6MulticastScope::InterfaceLocal), - 2 => Some(Ipv6MulticastScope::LinkLocal), - 3 => Some(Ipv6MulticastScope::RealmLocal), - 4 => Some(Ipv6MulticastScope::AdminLocal), - 5 => Some(Ipv6MulticastScope::SiteLocal), - 8 => Some(Ipv6MulticastScope::OrganizationLocal), - 14 => Some(Ipv6MulticastScope::Global), - _ => None, - } - } else { - None - } - } - - /// Returns [`true`] if this is a multicast address (`ff00::/8`). - /// - /// This property is defined by [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(since = "1.7.0", feature = "ip_17")] - #[must_use] - #[inline] - pub const fn is_multicast(&self) -> bool { - (self.segments()[0] & 0xff00) == 0xff00 - } - - /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, - /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. - /// - /// `::ffff:a.b.c.d` becomes `a.b.c.d`. - /// All addresses *not* starting with `::ffff` will return `None`. - /// - /// [`IPv4` address]: Ipv4Addr - /// [IPv4-mapped]: Ipv6Addr - /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), - /// Some(Ipv4Addr::new(192, 10, 2, 255))); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn to_ipv4_mapped(&self) -> Option { - match self.octets() { - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { - Some(Ipv4Addr::new(a, b, c, d)) - } - _ => None, - } - } - - /// Converts this address to an [`IPv4` address] if it is either - /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], - /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], - /// otherwise returns [`None`]. - /// - /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use - /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. - /// - /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. - /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. - /// - /// [`IPv4` address]: Ipv4Addr - /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses - /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses - /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 - /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), - /// Some(Ipv4Addr::new(192, 10, 2, 255))); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), - /// Some(Ipv4Addr::new(0, 0, 0, 1))); - /// ``` - #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn to_ipv4(&self) -> Option { - if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { - let [a, b] = ab.to_be_bytes(); - let [c, d] = cd.to_be_bytes(); - Some(Ipv4Addr::new(a, b, c, d)) - } else { - None - } - } - - /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it - /// returns self wrapped in an `IpAddr::V6`. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); - /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn to_canonical(&self) -> IpAddr { - if let Some(mapped) = self.to_ipv4_mapped() { - return IpAddr::V4(mapped); - } - IpAddr::V6(*self) - } - - /// Returns the sixteen eight-bit integers the IPv6 address consists of. - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), - /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - /// ``` - #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] - #[stable(feature = "ipv6_to_octets", since = "1.12.0")] - #[must_use] - #[inline] - pub const fn octets(&self) -> [u8; 16] { - self.octets - } -} - -/// Write an Ipv6Addr, conforming to the canonical style described by -/// [RFC 5952](https://tools.ietf.org/html/rfc5952). -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Ipv6Addr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // If there are no alignment requirements, write out the IP address to - // f. Otherwise, write it to a local buffer, then use f.pad. - if f.precision().is_none() && f.width().is_none() { - let segments = self.segments(); - - // Special case for :: and ::1; otherwise they get written with the - // IPv4 formatter - if self.is_unspecified() { - f.write_str("::") - } else if self.is_loopback() { - f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } - } else { - #[derive(Copy, Clone, Default)] - struct Span { - start: usize, - len: usize, - } - - // Find the inner 0 span - let zeroes = { - let mut longest = Span::default(); - let mut current = Span::default(); - - for (i, &segment) in segments.iter().enumerate() { - if segment == 0 { - if current.len == 0 { - current.start = i; - } - - current.len += 1; - - if current.len > longest.len { - longest = current; - } - } else { - current = Span::default(); - } - } - - longest - }; - - /// Write a colon-separated part of the address - #[inline] - fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { - if let Some((first, tail)) = chunk.split_first() { - write!(f, "{:x}", first)?; - for segment in tail { - f.write_char(':')?; - write!(f, "{:x}", segment)?; - } - } - Ok(()) - } - - if zeroes.len > 1 { - fmt_subslice(f, &segments[..zeroes.start])?; - f.write_str("::")?; - fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) - } else { - fmt_subslice(f, &segments) - } - } - } else { - // Slow path: write the address to a local buffer, then use f.pad. - // Defined recursively by using the fast path to write to the - // buffer. - - // This is the largest possible size of an IPv6 address - const IPV6_BUF_LEN: usize = (4 * 8) + 7; - let mut buf = [0u8; IPV6_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - // Note: This call to write should never fail, so unwrap is okay. - write!(buf_slice, "{}", self).unwrap(); - let len = IPV6_BUF_LEN - buf_slice.len(); - - // This is safe because we know exactly what can be in this buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for Ipv6Addr { - #[inline] - fn eq(&self, other: &IpAddr) -> bool { - match other { - IpAddr::V4(_) => false, - IpAddr::V6(v6) => self == v6, - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for IpAddr { - #[inline] - fn eq(&self, other: &Ipv6Addr) -> bool { - match self { - IpAddr::V4(_) => false, - IpAddr::V6(v6) => v6 == other, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv6Addr { - #[inline] - fn partial_cmp(&self, other: &Ipv6Addr) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for IpAddr { - #[inline] - fn partial_cmp(&self, other: &Ipv6Addr) -> Option { - match self { - IpAddr::V4(_) => Some(Ordering::Less), - IpAddr::V6(v6) => v6.partial_cmp(other), - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for Ipv6Addr { - #[inline] - fn partial_cmp(&self, other: &IpAddr) -> Option { - match other { - IpAddr::V4(_) => Some(Ordering::Greater), - IpAddr::V6(v6) => self.partial_cmp(v6), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv6Addr { - #[inline] - fn cmp(&self, other: &Ipv6Addr) -> Ordering { - self.segments().cmp(&other.segments()) - } -} - -impl IntoInner for Ipv6Addr { - fn into_inner(self) -> c::in6_addr { - c::in6_addr { s6_addr: self.octets } - } -} -impl FromInner for Ipv6Addr { - #[inline] - fn from_inner(addr: c::in6_addr) -> Ipv6Addr { - Ipv6Addr { octets: addr.s6_addr } - } -} - -#[stable(feature = "i128", since = "1.26.0")] -impl From for u128 { - /// Convert an `Ipv6Addr` into a host byte order `u128`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::new( - /// 0x1020, 0x3040, 0x5060, 0x7080, - /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, - /// ); - /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); - /// ``` - #[inline] - fn from(ip: Ipv6Addr) -> u128 { - u128::from_be_bytes(ip.octets) - } -} -#[stable(feature = "i128", since = "1.26.0")] -impl From for Ipv6Addr { - /// Convert a host byte order `u128` into an `Ipv6Addr`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); - /// assert_eq!( - /// Ipv6Addr::new( - /// 0x1020, 0x3040, 0x5060, 0x7080, - /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, - /// ), - /// addr); - /// ``` - #[inline] - fn from(ip: u128) -> Ipv6Addr { - Ipv6Addr::from(ip.to_be_bytes()) - } -} - -#[stable(feature = "ipv6_from_octets", since = "1.9.0")] -impl From<[u8; 16]> for Ipv6Addr { - /// Creates an `Ipv6Addr` from a sixteen element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::from([ - /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, - /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, - /// ]); - /// assert_eq!( - /// Ipv6Addr::new( - /// 0x1918, 0x1716, - /// 0x1514, 0x1312, - /// 0x1110, 0x0f0e, - /// 0x0d0c, 0x0b0a - /// ), - /// addr - /// ); - /// ``` - #[inline] - fn from(octets: [u8; 16]) -> Ipv6Addr { - Ipv6Addr { octets } - } -} - -#[stable(feature = "ipv6_from_segments", since = "1.16.0")] -impl From<[u16; 8]> for Ipv6Addr { - /// Creates an `Ipv6Addr` from an eight element 16-bit array. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::from([ - /// 525u16, 524u16, 523u16, 522u16, - /// 521u16, 520u16, 519u16, 518u16, - /// ]); - /// assert_eq!( - /// Ipv6Addr::new( - /// 0x20d, 0x20c, - /// 0x20b, 0x20a, - /// 0x209, 0x208, - /// 0x207, 0x206 - /// ), - /// addr - /// ); - /// ``` - #[inline] - fn from(segments: [u16; 8]) -> Ipv6Addr { - let [a, b, c, d, e, f, g, h] = segments; - Ipv6Addr::new(a, b, c, d, e, f, g, h) - } -} - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u8; 16]> for IpAddr { - /// Creates an `IpAddr::V6` from a sixteen element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr}; - /// - /// let addr = IpAddr::from([ - /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, - /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, - /// ]); - /// assert_eq!( - /// IpAddr::V6(Ipv6Addr::new( - /// 0x1918, 0x1716, - /// 0x1514, 0x1312, - /// 0x1110, 0x0f0e, - /// 0x0d0c, 0x0b0a - /// )), - /// addr - /// ); - /// ``` - #[inline] - fn from(octets: [u8; 16]) -> IpAddr { - IpAddr::V6(Ipv6Addr::from(octets)) - } -} - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u16; 8]> for IpAddr { - /// Creates an `IpAddr::V6` from an eight element 16-bit array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr}; - /// - /// let addr = IpAddr::from([ - /// 525u16, 524u16, 523u16, 522u16, - /// 521u16, 520u16, 519u16, 518u16, - /// ]); - /// assert_eq!( - /// IpAddr::V6(Ipv6Addr::new( - /// 0x20d, 0x20c, - /// 0x20b, 0x20a, - /// 0x209, 0x208, - /// 0x207, 0x206 - /// )), - /// addr - /// ); - /// ``` - #[inline] - fn from(segments: [u16; 8]) -> IpAddr { - IpAddr::V6(Ipv6Addr::from(segments)) - } -} diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs deleted file mode 100644 index c29509331..000000000 --- a/library/std/src/net/ip/tests.rs +++ /dev/null @@ -1,969 +0,0 @@ -use crate::net::test::{sa4, sa6, tsa}; -use crate::net::*; -use crate::str::FromStr; - -#[test] -fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - // octal - let none: Option = "255.0.0.01".parse().ok(); - assert_eq!(None, none); - // octal zero - let none: Option = "255.0.0.00".parse().ok(); - assert_eq!(None, none); - let none: Option = "255.0.00.0".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - // `::` indicating zero groups of zeros - let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); - assert_eq!( - Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse() - ); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1:2:3:4:5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1:2:3:4:5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), - "[::127.0.0.1]:22".parse() - ); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn ipv4_addr_to_string() { - assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); - // Short address - assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); - // Long address - assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); - - // Test padding - assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); - assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); -} - -#[test] -fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); - - // longest possible IPv6 length - assert_eq!( - Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), - "1111:2222:3333:4444:5555:6666:7777:8888" - ); - // padding - assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); - assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); - - // reduce a single run of zeros - assert_eq!( - "ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() - ); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - - // don't prefix `0x` to each segment in `dbg!`. - assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8))); -} - -#[test] -fn ipv4_to_ipv6() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() - ); -} - -#[test] -fn ipv6_to_ipv4_mapped() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); -} - -#[test] -fn ipv6_to_ipv4() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); -} - -#[test] -fn ip_properties() { - macro_rules! ip { - ($s:expr) => { - IpAddr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - let benchmarking: u8 = 1 << 5; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & doc) == doc { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - }}; - } - - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - let benchmarking: u8 = 1 << 5; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7"); - check!("127.1.2.3", loopback); - check!("172.31.254.253"); - check!("169.254.253.242"); - check!("192.0.2.183", doc); - check!("192.1.2.183", global); - check!("192.168.254.253"); - check!("198.51.100.0", doc); - check!("203.0.113.0", doc); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255"); - // make sure benchmarking addresses are not global - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - // make sure addresses reserved for protocol assignment are not global - check!("192.0.0.0"); - check!("192.0.0.255"); - check!("192.0.0.100"); - // make sure reserved addresses are not global - check!("240.0.0.0"); - check!("251.54.1.76"); - check!("254.255.255.255"); - // make sure shared addresses are not global - check!("100.64.0.0"); - check!("100.127.255.255"); - check!("100.100.100.0"); - - check!("::", unspec); - check!("::1", loopback); - check!("::0.0.0.2", global); - check!("1::", global); - check!("fc00::"); - check!("fdff:ffff::"); - check!("fe80:ffff::"); - check!("febf:ffff::"); - check!("fec0::", global); - check!("ff01::", multicast); - check!("ff02::", multicast); - check!("ff03::", multicast); - check!("ff04::", multicast); - check!("ff05::", multicast); - check!("ff08::", multicast); - check!("ff0e::", global | multicast); - check!("2001:db8:85a3::8a2e:370:7334", doc); - check!("2001:2::ac32:23ff:21", global | benchmarking); - check!("102:304:506:708:90a:b0c:d0e:f10", global); -} - -#[test] -fn ipv4_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv4Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & private) == private { - assert!(ip!($s).is_private()); - } else { - assert!(!ip!($s).is_private()); - } - - if ($mask & link_local) == link_local { - assert!(ip!($s).is_link_local()); - } else { - assert!(!ip!($s).is_link_local()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & broadcast) == broadcast { - assert!(ip!($s).is_broadcast()); - } else { - assert!(!ip!($s).is_broadcast()); - } - - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - - if ($mask & reserved) == reserved { - assert!(ip!($s).is_reserved()); - } else { - assert!(!ip!($s).is_reserved()); - } - - if ($mask & shared) == shared { - assert!(ip!($s).is_shared()); - } else { - assert!(!ip!($s).is_shared()); - } - }}; - } - - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7", private); - check!("127.1.2.3", loopback); - check!("172.31.254.253", private); - check!("169.254.253.242", link_local); - check!("192.0.2.183", documentation); - check!("192.1.2.183", global); - check!("192.168.254.253", private); - check!("198.51.100.0", documentation); - check!("203.0.113.0", documentation); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255", broadcast); - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - check!("192.0.0.0"); - check!("192.0.0.255"); - check!("192.0.0.100"); - check!("240.0.0.0", reserved); - check!("251.54.1.76", reserved); - check!("254.255.255.255", reserved); - check!("100.64.0.0", shared); - check!("100.127.255.255", shared); - check!("100.100.100.0", shared); -} - -#[test] -fn ipv6_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv6Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr, &[$($octet:expr),*], $mask:expr) => { - assert_eq!($s, ip!($s).to_string()); - let octets = &[$($octet),*]; - assert_eq!(&ip!($s).octets(), octets); - assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let benchmarking: u32 = 1 << 16; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - let multicast: u32 = multicast_interface_local - | multicast_admin_local - | multicast_global - | multicast_link_local - | multicast_realm_local - | multicast_site_local - | multicast_organization_local; - - if ($mask & unspecified) == unspecified { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - if ($mask & unique_local) == unique_local { - assert!(ip!($s).is_unique_local()); - } else { - assert!(!ip!($s).is_unique_local()); - } - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - if ($mask & unicast_link_local) == unicast_link_local { - assert!(ip!($s).is_unicast_link_local()); - } else { - assert!(!ip!($s).is_unicast_link_local()); - } - if ($mask & unicast_global) == unicast_global { - assert!(ip!($s).is_unicast_global()); - } else { - assert!(!ip!($s).is_unicast_global()); - } - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - if ($mask & multicast) != 0 { - assert!(ip!($s).multicast_scope().is_some()); - assert!(ip!($s).is_multicast()); - } else { - assert!(ip!($s).multicast_scope().is_none()); - assert!(!ip!($s).is_multicast()); - } - if ($mask & multicast_interface_local) == multicast_interface_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::InterfaceLocal); - } - if ($mask & multicast_link_local) == multicast_link_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::LinkLocal); - } - if ($mask & multicast_realm_local) == multicast_realm_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::RealmLocal); - } - if ($mask & multicast_admin_local) == multicast_admin_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::AdminLocal); - } - if ($mask & multicast_site_local) == multicast_site_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::SiteLocal); - } - if ($mask & multicast_organization_local) == multicast_organization_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::OrganizationLocal); - } - if ($mask & multicast_global) == multicast_global { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Global); - } - } - } - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let benchmarking: u32 = 1 << 16; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - - check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); - - check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - - check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); - - check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); - - check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); - - check!( - "fdff:ffff::", - &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unique_local - ); - - check!( - "fe80:ffff::", - &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); - - check!( - "febf:ffff::", - &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); - - check!( - "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - &[ - 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80::ffff:ffff:ffff:ffff", - &[ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80:0:0:1::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fec0::", - &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_global | global - ); - - check!( - "ff01::", - &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_interface_local - ); - - check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local); - - check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local); - - check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local); - - check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local); - - check!( - "ff08::", - &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_organization_local - ); - - check!( - "ff0e::", - &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_global | global - ); - - check!( - "2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - documentation - ); - - check!( - "2001:2::ac32:23ff:21", - &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], - global | unicast_global | benchmarking - ); - - check!( - "102:304:506:708:90a:b0c:d0e:f10", - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - global | unicast_global - ); -} - -#[test] -fn to_socket_addr_socketaddr() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); - assert_eq!(Ok(vec![a]), tsa(a)); -} - -#[test] -fn test_ipv4_to_int() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(u32::from(a), 0x11223344); -} - -#[test] -fn test_int_to_ipv4() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(Ipv4Addr::from(0x11223344), a); -} - -#[test] -fn test_ipv6_to_int() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); -} - -#[test] -fn test_int_to_ipv6() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); -} - -#[test] -fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); - assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); - assert!(Ipv4Addr::BROADCAST.is_broadcast()); -} - -#[test] -fn ipv6_from_constructors() { - assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); -} - -#[test] -fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) -} - -#[test] -fn ipv6_from_segments() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); - assert_eq!(new, from_u16s); -} - -#[test] -fn ipv6_from_octets() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s = Ipv6Addr::from([ - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, - 0xff, - ]); - assert_eq!(from_u16s, from_u8s); -} - -#[test] -fn cmp() { - let v41 = Ipv4Addr::new(100, 64, 3, 3); - let v42 = Ipv4Addr::new(192, 0, 2, 2); - let v61 = "2001:db8:f00::1002".parse::().unwrap(); - let v62 = "2001:db8:f00::2001".parse::().unwrap(); - assert!(v41 < v42); - assert!(v61 < v62); - - assert_eq!(v41, IpAddr::V4(v41)); - assert_eq!(v61, IpAddr::V6(v61)); - assert!(v41 != IpAddr::V4(v42)); - assert!(v61 != IpAddr::V6(v62)); - - assert!(v41 < IpAddr::V4(v42)); - assert!(v61 < IpAddr::V6(v62)); - assert!(IpAddr::V4(v41) < v42); - assert!(IpAddr::V6(v61) < v62); - - assert!(v41 < IpAddr::V6(v61)); - assert!(IpAddr::V4(v41) < v61); -} - -#[test] -fn is_v4() { - let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); - assert!(ip.is_ipv4()); - assert!(!ip.is_ipv6()); -} - -#[test] -fn is_v6() { - let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); - assert!(!ip.is_ipv4()); - assert!(ip.is_ipv6()); -} - -#[test] -fn ipv4_const() { - // test that the methods of `Ipv4Addr` are usable in a const context - - const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); - - const OCTETS: [u8; 4] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [127, 0, 0, 1]); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_PRIVATE: bool = IP_ADDRESS.is_private(); - assert!(!IS_PRIVATE); - - const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); - assert!(!IS_LINK_LOCAL); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_SHARED: bool = IP_ADDRESS.is_shared(); - assert!(!IS_SHARED); - - const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); - assert!(!IS_RESERVED); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); - assert!(!IS_BROADCAST); - - const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); - assert_eq!( - IP_V6_COMPATIBLE, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) - ); - - const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); - assert_eq!( - IP_V6_MAPPED, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) - ); -} - -#[test] -fn ipv6_const() { - // test that the methods of `Ipv6Addr` are usable in a const context - - const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); - - const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); - assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); - - const OCTETS: [u8; 16] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); - assert!(!IS_UNIQUE_LOCAL); - - const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); - assert!(!IS_UNICAST_LINK_LOCAL); - - const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); - assert!(!IS_UNICAST_GLOBAL); - - const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); - assert_eq!(MULTICAST_SCOPE, None); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IP_V4: Option = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} - -#[test] -fn ip_const() { - // test that the methods of `IpAddr` are usable in a const context - - const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); - assert!(IS_IP_V4); - - const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); - assert!(!IS_IP_V6); -} - -#[test] -fn structural_match() { - // test that all IP types can be structurally matched upon - - const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST; - match IPV4 { - Ipv4Addr::LOCALHOST => {} - _ => unreachable!(), - } - - const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST; - match IPV6 { - Ipv6Addr::LOCALHOST => {} - _ => unreachable!(), - } - - const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); - match IP { - IpAddr::V4(Ipv4Addr::LOCALHOST) => {} - _ => unreachable!(), - } -} diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs new file mode 100644 index 000000000..4f14fc280 --- /dev/null +++ b/library/std/src/net/ip_addr.rs @@ -0,0 +1,2095 @@ +// Tests for this module +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +use crate::cmp::Ordering; +use crate::fmt::{self, Write}; +use crate::mem::transmute; +use crate::sys::net::netc as c; +use crate::sys_common::{FromInner, IntoInner}; + +use super::display_buffer::DisplayBuffer; + +/// An IP address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +/// +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); +/// +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); +/// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")] +#[stable(feature = "ip_addr", since = "1.7.0")] +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// An IPv4 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), + /// An IPv6 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), +} + +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. +/// +/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 +/// [`FromStr`]: crate::str::FromStr +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv4Addr")] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv4Addr { + octets: [u8; 4], +} + +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// +/// # Embedding IPv4 Addresses +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: +/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. +/// +/// Both types of addresses are not assigned any special meaning by this implementation, +/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, +/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. +/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. +/// +/// ### IPv4-Compatible IPv6 Addresses +/// +/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. +/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|0000| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. +/// +/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 +/// +/// ### IPv4-Mapped IPv6 Addresses +/// +/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. +/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|FFFF| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. +/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use +/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. +/// +/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: crate::str::FromStr +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv6Addr")] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv6Addr { + octets: [u8; 16], +} + +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// +/// # Stability Guarantees +/// +/// Not all possible values for a multicast scope have been assigned. +/// Future RFCs may introduce new scopes, which will be added as variants to this enum; +/// because of this the enum is marked as `#[non_exhaustive]`. +/// +/// # Examples +/// ``` +/// #![feature(ip)] +/// +/// use std::net::Ipv6Addr; +/// use std::net::Ipv6MulticastScope::*; +/// +/// // An IPv6 multicast address with global scope (`ff0e::`). +/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); +/// +/// // Will print "Global scope". +/// match address.multicast_scope() { +/// Some(InterfaceLocal) => println!("Interface-Local scope"), +/// Some(LinkLocal) => println!("Link-Local scope"), +/// Some(RealmLocal) => println!("Realm-Local scope"), +/// Some(AdminLocal) => println!("Admin-Local scope"), +/// Some(SiteLocal) => println!("Site-Local scope"), +/// Some(OrganizationLocal) => println!("Organization-Local scope"), +/// Some(Global) => println!("Global scope"), +/// Some(_) => println!("Unknown scope"), +/// None => println!("Not a multicast address!") +/// } +/// +/// ``` +/// +/// [IPv6 multicast address]: Ipv6Addr +/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[unstable(feature = "ip", issue = "27709")] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + /// Interface-Local scope. + InterfaceLocal, + /// Link-Local scope. + LinkLocal, + /// Realm-Local scope. + RealmLocal, + /// Admin-Local scope. + AdminLocal, + /// Site-Local scope. + SiteLocal, + /// Organization-Local scope. + OrganizationLocal, + /// Global scope. + Global, +} + +impl IpAddr { + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified()`] and + /// [`Ipv6Addr::is_unspecified()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback()`] and + /// [`Ipv6Addr::is_loopback()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global()`] and + /// [`Ipv6Addr::is_global()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast()`] and + /// [`Ipv6Addr::is_multicast()`] for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation()`] and + /// [`Ipv6Addr::is_documentation()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); + /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + + /// Returns [`true`] if this address is in a range designated for benchmarking. + /// + /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and + /// [`Ipv6Addr::is_benchmarking()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + + /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] + /// otherwise. + /// + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + #[must_use] + #[inline] + pub const fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + + /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] + /// otherwise. + /// + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + #[must_use] + #[inline] + pub const fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it + /// return `self` as-is. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} + +impl Ipv4Addr { + /// Creates a new IPv4 address from four eight-bit octets. + /// + /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` + #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { octets: [a, b, c, d] } + } + + /// An IPv4 address with the address pointing to localhost: `127.0.0.1` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::LOCALHOST; + /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + + /// An IPv4 address representing an unspecified address: `0.0.0.0` + /// + /// This corresponds to the constant `INADDR_ANY` in other languages. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); + /// ``` + #[doc(alias = "INADDR_ANY")] + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: `255.255.255.255` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + + /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 4] { + self.octets + } + + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). + /// + /// This property is defined in _UNIX Network Programming, Second Edition_, + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u32::from_be_bytes(self.octets) == 0 + } + + /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). + /// + /// This property is defined by [IETF RFC 1122]. + /// + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + + /// Returns [`true`] if this is a private address. + /// + /// The private address ranges are defined in [IETF RFC 1918] and include: + /// + /// - `10.0.0.0/8` + /// - `172.16.0.0/12` + /// - `192.168.0.0/16` + /// + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + + /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). + /// + /// This property is defined by [IETF RFC 3927]. + /// + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv4 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// + /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) + /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) + /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) + /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) + /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) + /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) + /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) + /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) + /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. + /// + /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [unspecified address]: Ipv4Addr::UNSPECIFIED + /// [broadcast address]: Ipv4Addr::BROADCAST + + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// // Most IPv4 addresses are globally reachable: + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`0.0.0.0`) + /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); + /// + /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// + /// // Addresses in the shared address space (`100.64.0.0/10`) + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// + /// // The loopback addresses (`127.0.0.0/8`) + /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); + /// + /// // Link-local addresses (`169.254.0.0/16`) + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// + /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`198.18.0.0/15`) + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// + /// // Reserved addresses (`240.0.0.0/4`) + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// + /// // The broadcast address (`255.255.255.255`) + /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); + /// + /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. + /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.octets()[0] == 0 // "This network" + || self.is_private() + || self.is_shared() + || self.is_loopback() + || self.is_link_local() + // addresses reserved for future protocols (`192.0.0.0/24`) + ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) + || self.is_documentation() + || self.is_benchmarking() + || self.is_reserved() + || self.is_broadcast()) + } + + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 + /// [errata 423]: https://www.rfc-editor.org/errata/eid423 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// + /// # Warning + /// + /// As IANA assigns new addresses, this method will be + /// updated. This may result in non-reserved addresses being + /// treated as reserved in code that relies on an outdated version + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + + /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). + /// + /// Multicast addresses have a most significant octet between `224` and `239`, + /// and is defined by [IETF RFC 5771]. + /// + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + + /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). + /// + /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. + /// + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// This is defined in [IETF RFC 5737]: + /// + /// - `192.0.2.0/24` (TEST-NET-1) + /// - `198.51.100.0/24` (TEST-NET-2) + /// - `203.0.113.0/24` (TEST-NET-3) + /// + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _]) + } + + /// Converts this address to an [IPv4-compatible] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::a.b.c.d` + /// + /// Note that IPv4-compatible addresses have been officially deprecated. + /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. + /// + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) + /// ); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] } + } + + /// Converts this address to an [IPv4-mapped] [`IPv6` address]. + /// + /// `a.b.c.d` becomes `::ffff:a.b.c.d` + /// + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] } + } +} + +#[stable(feature = "ip_addr", since = "1.7.0")] +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), + } + } +} + +#[stable(feature = "ip_addr", since = "1.7.0")] +impl fmt::Debug for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for IpAddr { + /// Copies this address to a new `IpAddr::V4`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// + /// assert_eq!( + /// IpAddr::V4(addr), + /// IpAddr::from(addr) + /// ) + /// ``` + #[inline] + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for IpAddr { + /// Copies this address to a new `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// + /// assert_eq!( + /// IpAddr::V6(addr), + /// IpAddr::from(addr) + /// ); + /// ``` + #[inline] + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let octets = self.octets(); + + // If there are no alignment requirements, write the IP address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. + if fmt.precision().is_none() && fmt.width().is_none() { + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } else { + const LONGEST_IPV4_ADDR: &str = "255.255.255.255"; + + let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new(); + // Buffer is long enough for the longest possible IPv4 address, so this should never fail. + write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); + + fmt.pad(buf.as_str()) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for IpAddr { + #[inline] + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for Ipv4Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for Ipv4Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv4Addr { + #[inline] + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + self.octets.cmp(&other.octets) + } +} + +impl IntoInner for Ipv4Addr { + #[inline] + fn into_inner(self) -> c::in_addr { + // `s_addr` is stored as BE on all machines and the array is in BE order. + // So the native endian conversion method is used so that it's never swapped. + c::in_addr { s_addr: u32::from_ne_bytes(self.octets) } + } +} +impl FromInner for Ipv4Addr { + fn from_inner(addr: c::in_addr) -> Ipv4Addr { + Ipv4Addr { octets: addr.s_addr.to_ne_bytes() } + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for u32 { + /// Converts an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); + /// assert_eq!(0x12345678, u32::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv4Addr) -> u32 { + u32::from_be_bytes(ip.octets) + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for Ipv4Addr { + /// Converts a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x12345678); + /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); + /// ``` + #[inline] + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr { octets: ip.to_be_bytes() } + } +} + +#[stable(feature = "from_slice_v4", since = "1.9.0")] +impl From<[u8; 4]> for Ipv4Addr { + /// Creates an `Ipv4Addr` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr { octets } + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 4]> for IpAddr { + /// Creates an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` + #[inline] + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} + +impl Ipv6Addr { + /// Creates a new IPv6 address from eight 16-bit segments. + /// + /// The result will represent the IP address `a:b:c:d:e:f:g:h`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` + #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; + Ipv6Addr { + // All elements in `addr16` are big endian. + // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, + } + } + + /// An IPv6 address representing localhost: `::1`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::LOCALHOST; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + + /// An IPv6 address representing the unspecified address: `::` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + + /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub const fn segments(&self) -> [u16; 8] { + // All elements in `self.octets` must be big endian. + // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; + // We want native endian u16 + [ + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), + ] + } + + /// Returns [`true`] for the special 'unspecified' address (`::`). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + + /// Returns [`true`] if this is the [loopback address] (`::1`), + /// as defined in [IETF RFC 4291 section 2.5.3]. + /// + /// Contrary to IPv4, in IPv6 there is only one loopback address. + /// + /// [loopback address]: Ipv6Addr::LOCALHOST + /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv6 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. + /// + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) + /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) + /// - IPv4-mapped addresses + /// - Addresses reserved for benchmarking + /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) + /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) + /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. + /// + /// Note that an address having global scope is not the same as being globally reachable, + /// and there is no direct relation between the two concepts: There exist addresses with global scope + /// that are not globally reachable (for example unique local addresses), + /// and addresses that are globally reachable without having global scope + /// (multicast addresses with non-global scope). + /// + /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + /// [unspecified address]: Ipv6Addr::UNSPECIFIED + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // Most IPv6 addresses are globally reachable: + /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`::`) + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); + /// + /// // The loopback address (`::1`) + /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); + /// + /// // IPv4-mapped addresses (`::ffff:0:0/96`) + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`2001:2::/48`) + /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); + /// + /// // Addresses reserved for documentation (`2001:db8::/32`) + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unique local addresses (`fc00::/7`) + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unicast addresses with link-local scope (`fe80::/10`) + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_global(&self) -> bool { + !(self.is_unspecified() + || self.is_loopback() + // IPv4-mapped Address (`::ffff:0:0/96`) + || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) + || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) + // Discard-Only Address Block (`100::/64`) + || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) + // IETF Protocol Assignments (`2001::/23`) + || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) + && !( + // Port Control Protocol Anycast (`2001:1::1`) + u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 + // Traversal Using Relays around NAT Anycast (`2001:1::2`) + || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 + // AMT (`2001:3::/32`) + || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) + // AS112-v6 (`2001:4:112::/48`) + || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) + // ORCHIDv2 (`2001:20::/28`) + || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) + )) + || self.is_documentation() + || self.is_unique_local() + || self.is_unicast_link_local()) + } + + /// Returns [`true`] if this is a unique local address (`fc00::/7`). + /// + /// This property is defined in [IETF RFC 4193]. + /// + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. + /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); + /// + /// // Any address that is not a multicast address (`ff00::/8`) is unicast. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. + /// + /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. + /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], + /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: + /// + /// ```text + /// | 10 bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, + /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, + /// and those addresses will have link-local scope. + /// + /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", + /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [loopback address]: Ipv6Addr::LOCALHOST + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The loopback address (`::1`) does not actually have link-local scope. + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); + /// + /// // Only addresses in `fe80::/10` have link-local scope. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// + /// // Addresses outside the stricter `fe80::/64` also have link-local scope. + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + + /// Returns [`true`] if this is an address reserved for documentation + /// (`2001:db8::/32`). + /// + /// This property is defined in [IETF RFC 3849]. + /// + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + + /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). + /// + /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. + /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. + /// + /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 + /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + + /// Returns [`true`] if the address is a globally routable unicast address. + /// + /// The following return false: + /// + /// - the loopback address + /// - the link-local addresses + /// - unique local addresses + /// - the unspecified address + /// - the address range reserved for documentation + /// + /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] + /// + /// ```no_rust + /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer + /// be supported in new implementations (i.e., new implementations must treat this prefix as + /// Global Unicast). + /// ``` + /// + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() + && !self.is_benchmarking() + } + + /// Returns the address's multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } + } + + /// Returns [`true`] if this is a multicast address (`ff00::/8`). + /// + /// This property is defined by [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(since = "1.7.0", feature = "ip_17")] + #[must_use] + #[inline] + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, + /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. + /// + /// `::ffff:a.b.c.d` becomes `a.b.c.d`. + /// All addresses *not* starting with `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-mapped]: Ipv6Addr + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4_mapped(&self) -> Option { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + + /// Converts this address to an [`IPv4` address] if it is either + /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], + /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], + /// otherwise returns [`None`]. + /// + /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use + /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. + /// + /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. + /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. + /// + /// [`IPv4` address]: Ipv4Addr + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), + /// Some(Ipv4Addr::new(0, 0, 0, 1))); + /// ``` + #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_ipv4(&self) -> Option { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { + None + } + } + + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it + /// returns self wrapped in an `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + + /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), + /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// ``` + #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")] + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] + #[must_use] + #[inline] + pub const fn octets(&self) -> [u8; 16] { + self.octets + } +} + +/// Write an Ipv6Addr, conforming to the canonical style described by +/// [RFC 5952](https://tools.ietf.org/html/rfc5952). +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv6Addr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If there are no alignment requirements, write the IP address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. + if f.precision().is_none() && f.width().is_none() { + let segments = self.segments(); + + // Special case for :: and ::1; otherwise they get written with the + // IPv4 formatter + if self.is_unspecified() { + f.write_str("::") + } else if self.is_loopback() { + f.write_str("::1") + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + // IPv4 Compatible address + 0 => write!(f, "::{}", ipv4), + // IPv4 Mapped address + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { + #[derive(Copy, Clone, Default)] + struct Span { + start: usize, + len: usize, + } + + // Find the inner 0 span + let zeroes = { + let mut longest = Span::default(); + let mut current = Span::default(); + + for (i, &segment) in segments.iter().enumerate() { + if segment == 0 { + if current.len == 0 { + current.start = i; + } + + current.len += 1; + + if current.len > longest.len { + longest = current; + } + } else { + current = Span::default(); + } + } + + longest + }; + + /// Write a colon-separated part of the address + #[inline] + fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { + if let Some((first, tail)) = chunk.split_first() { + write!(f, "{:x}", first)?; + for segment in tail { + f.write_char(':')?; + write!(f, "{:x}", segment)?; + } + } + Ok(()) + } + + if zeroes.len > 1 { + fmt_subslice(f, &segments[..zeroes.start])?; + f.write_str("::")?; + fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) + } else { + fmt_subslice(f, &segments) + } + } + } else { + const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"; + + let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new(); + // Buffer is long enough for the longest possible IPv6 address, so this should never fail. + write!(buf, "{}", self).unwrap(); + + f.pad(buf.as_str()) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for Ipv6Addr { + #[inline] + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for IpAddr { + #[inline] + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for IpAddr { + #[inline] + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for Ipv6Addr { + #[inline] + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv6Addr { + #[inline] + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} + +impl IntoInner for Ipv6Addr { + fn into_inner(self) -> c::in6_addr { + c::in6_addr { s6_addr: self.octets } + } +} +impl FromInner for Ipv6Addr { + #[inline] + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr { octets: addr.s6_addr } + } +} + +#[stable(feature = "i128", since = "1.26.0")] +impl From for u128 { + /// Convert an `Ipv6Addr` into a host byte order `u128`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ); + /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); + /// ``` + #[inline] + fn from(ip: Ipv6Addr) -> u128 { + u128::from_be_bytes(ip.octets) + } +} +#[stable(feature = "i128", since = "1.26.0")] +impl From for Ipv6Addr { + /// Convert a host byte order `u128` into an `Ipv6Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ), + /// addr); + /// ``` + #[inline] + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} + +#[stable(feature = "ipv6_from_octets", since = "1.9.0")] +impl From<[u8; 16]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> Ipv6Addr { + Ipv6Addr { octets } + } +} + +#[stable(feature = "ipv6_from_segments", since = "1.16.0")] +impl From<[u16; 8]> for Ipv6Addr { + /// Creates an `Ipv6Addr` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// ), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 16]> for IpAddr { + /// Creates an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u16; 8]> for IpAddr { + /// Creates an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` + #[inline] + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs new file mode 100644 index 000000000..7c3430b2b --- /dev/null +++ b/library/std/src/net/ip_addr/tests.rs @@ -0,0 +1,1039 @@ +use crate::net::test::{sa4, sa6, tsa}; +use crate::net::*; +use crate::str::FromStr; + +#[test] +fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); + // octal + let none: Option = "255.0.0.01".parse().ok(); + assert_eq!(None, none); + // octal zero + let none: Option = "255.0.0.00".parse().ok(); + assert_eq!(None, none); + let none: Option = "255.0.00.0".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); + assert_eq!( + Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse() + ); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1:2:3:4:5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1:2:3:4:5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse() + ); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn ipv4_addr_to_string() { + assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); +} + +#[test] +fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); + assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); + + // reduce a single run of zeros + assert_eq!( + "ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() + ); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); + + // don't prefix `0x` to each segment in `dbg!`. + assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8))); +} + +#[test] +fn ipv4_to_ipv6() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() + ); +} + +#[test] +fn ipv6_to_ipv4_mapped() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); +} + +#[test] +fn ipv6_to_ipv4() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); +} + +#[test] +fn ip_properties() { + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + }}; + } + + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255"); + // make sure benchmarking addresses are not global + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::0.0.0.2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", global | multicast); + check!("ff02::", global | multicast); + check!("ff03::", global | multicast); + check!("ff04::", global | multicast); + check!("ff05::", global | multicast); + check!("ff08::", global | multicast); + check!("ff0e::", global | multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("2001:2::ac32:23ff:21", benchmarking); + check!("102:304:506:708:90a:b0c:d0e:f10", global); +} + +#[test] +fn ipv4_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }}; + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); +} + +#[test] +fn ipv6_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + assert_eq!(&ip!($s).octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast: u32 = multicast_interface_local + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + } + } + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + + check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); + + check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); + + check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + + check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + + check!( + "::ffff:127.0.0.1", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], + unicast_global + ); + + check!( + "64:ff9b:1::", + &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_global + ); + + check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:1::1", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + global | unicast_global + ); + + check!( + "2001:1::2", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + global | unicast_global + ); + + check!( + "2001:3::", + &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:4:112::", + &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:20::", + &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:200::", + &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); + + check!( + "fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local + ); + + check!( + "fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80::ffff:ffff:ffff:ffff", + &[ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_global | global + ); + + check!( + "ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local | global + ); + + check!( + "ff02::", + &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_link_local | global + ); + + check!( + "ff03::", + &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_realm_local | global + ); + + check!( + "ff04::", + &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_admin_local | global + ); + + check!( + "ff05::", + &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_site_local | global + ); + + check!( + "ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local | global + ); + + check!( + "ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global + ); + + check!( + "2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation + ); + + check!( + "2001:2::ac32:23ff:21", + &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], + benchmarking + ); + + check!( + "102:304:506:708:90a:b0c:d0e:f10", + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + global | unicast_global + ); +} + +#[test] +fn to_socket_addr_socketaddr() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); +} + +#[test] +fn test_ipv4_to_int() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(u32::from(a), 0x11223344); +} + +#[test] +fn test_int_to_ipv4() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(Ipv4Addr::from(0x11223344), a); +} + +#[test] +fn test_ipv6_to_int() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); +} + +#[test] +fn test_int_to_ipv6() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); +} + +#[test] +fn ipv4_from_constructors() { + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); +} + +#[test] +fn ipv6_from_constructors() { + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); +} + +#[test] +fn ipv4_from_octets() { + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) +} + +#[test] +fn ipv6_from_segments() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); + assert_eq!(new, from_u16s); +} + +#[test] +fn ipv6_from_octets() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s = Ipv6Addr::from([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); + assert_eq!(from_u16s, from_u8s); +} + +#[test] +fn cmp() { + let v41 = Ipv4Addr::new(100, 64, 3, 3); + let v42 = Ipv4Addr::new(192, 0, 2, 2); + let v61 = "2001:db8:f00::1002".parse::().unwrap(); + let v62 = "2001:db8:f00::2001".parse::().unwrap(); + assert!(v41 < v42); + assert!(v61 < v62); + + assert_eq!(v41, IpAddr::V4(v41)); + assert_eq!(v61, IpAddr::V6(v61)); + assert!(v41 != IpAddr::V4(v42)); + assert!(v61 != IpAddr::V6(v62)); + + assert!(v41 < IpAddr::V4(v42)); + assert!(v61 < IpAddr::V6(v62)); + assert!(IpAddr::V4(v41) < v42); + assert!(IpAddr::V6(v61) < v62); + + assert!(v41 < IpAddr::V6(v61)); + assert!(IpAddr::V4(v41) < v61); +} + +#[test] +fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); +} + +#[test] +fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); +} + +#[test] +fn ipv4_const() { + // test that the methods of `Ipv4Addr` are usable in a const context + + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE: bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED: bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!( + IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) + ); + + const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!( + IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) + ); +} + +#[test] +fn ipv6_const() { + // test that the methods of `Ipv6Addr` are usable in a const context + + const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); + + const OCTETS: [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4: Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} + +#[test] +fn ip_const() { + // test that the methods of `IpAddr` are usable in a const context + + const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); + assert!(IS_IP_V4); + + const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); + assert!(!IS_IP_V6); +} + +#[test] +fn structural_match() { + // test that all IP types can be structurally matched upon + + const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST; + match IPV4 { + Ipv4Addr::LOCALHOST => {} + _ => unreachable!(), + } + + const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST; + match IPV6 { + Ipv6Addr::LOCALHOST => {} + _ => unreachable!(), + } + + const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + match IP { + IpAddr::V4(Ipv4Addr::LOCALHOST) => {} + _ => unreachable!(), + } +} diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index e7a40bdaf..01e3db9de 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -24,11 +24,11 @@ use crate::io::{self, ErrorKind}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::parser::AddrParseError; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] pub use self::tcp::IntoIncoming; #[stable(feature = "rust1", since = "1.0.0")] @@ -36,12 +36,13 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::udp::UdpSocket; -mod addr; -mod ip; +mod display_buffer; +mod ip_addr; mod parser; +mod socket_addr; mod tcp; #[cfg(test)] -mod test; +pub(crate) mod test; mod udp; /// Possible values which can be passed to the [`TcpStream::shutdown`] method. diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index 069b66099..a38031c48 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -39,8 +39,8 @@ struct Parser<'a> { } impl<'a> Parser<'a> { - fn new(input: &'a str) -> Parser<'a> { - Parser { state: input.as_bytes() } + fn new(input: &'a [u8]) -> Parser<'a> { + Parser { state: input } } /// Run a parser, and restore the pre-parse state if it fails. @@ -273,32 +273,106 @@ impl<'a> Parser<'a> { } } +impl IpAddr { + /// Parse an IP address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); + /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// + /// assert_eq!(IpAddr::parse_ascii(b"127.0.0.1"), Ok(localhost_v4)); + /// assert_eq!(IpAddr::parse_ascii(b"::1"), Ok(localhost_v6)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { + Parser::new(b).parse_with(|p| p.read_ip_addr(), AddrKind::Ip) + } +} + #[stable(feature = "ip_addr", since = "1.7.0")] impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip) + Self::parse_ascii(s.as_bytes()) } } -#[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for Ipv4Addr { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { +impl Ipv4Addr { + /// Parse an IPv4 address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::Ipv4Addr; + /// + /// let localhost = Ipv4Addr::new(127, 0, 0, 1); + /// + /// assert_eq!(Ipv4Addr::parse_ascii(b"127.0.0.1"), Ok(localhost)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { // don't try to parse if too long - if s.len() > 15 { + if b.len() > 15 { Err(AddrParseError(AddrKind::Ipv4)) } else { - Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4) + Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4) } } } +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for Ipv4Addr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result { + Self::parse_ascii(s.as_bytes()) + } +} + +impl Ipv6Addr { + /// Parse an IPv6 address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::Ipv6Addr; + /// + /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + /// + /// assert_eq!(Ipv6Addr::parse_ascii(b"::1"), Ok(localhost)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { + Parser::new(b).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for Ipv6Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6) + Self::parse_ascii(s.as_bytes()) + } +} + +impl SocketAddrV4 { + /// Parse an IPv4 socket address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::{Ipv4Addr, SocketAddrV4}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// + /// assert_eq!(SocketAddrV4::parse_ascii(b"127.0.0.1:8080"), Ok(socket)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { + Parser::new(b).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4) } } @@ -306,7 +380,25 @@ impl FromStr for Ipv6Addr { impl FromStr for SocketAddrV4 { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4) + Self::parse_ascii(s.as_bytes()) + } +} + +impl SocketAddrV6 { + /// Parse an IPv6 socket address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::{Ipv6Addr, SocketAddrV6}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// + /// assert_eq!(SocketAddrV6::parse_ascii(b"[2001:db8::1]:8080"), Ok(socket)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { + Parser::new(b).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6) } } @@ -314,7 +406,27 @@ impl FromStr for SocketAddrV4 { impl FromStr for SocketAddrV6 { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6) + Self::parse_ascii(s.as_bytes()) + } +} + +impl SocketAddr { + /// Parse a socket address from a slice of bytes. + /// + /// ``` + /// #![feature(addr_parse_ascii)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; + /// + /// let socket_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// let socket_v6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080); + /// + /// assert_eq!(SocketAddr::parse_ascii(b"127.0.0.1:8080"), Ok(socket_v4)); + /// assert_eq!(SocketAddr::parse_ascii(b"[::1]:8080"), Ok(socket_v6)); + /// ``` + #[unstable(feature = "addr_parse_ascii", issue = "101035")] + pub fn parse_ascii(b: &[u8]) -> Result { + Parser::new(b).parse_with(|p| p.read_socket_addr(), AddrKind::Socket) } } @@ -322,7 +434,7 @@ impl FromStr for SocketAddrV6 { impl FromStr for SocketAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket) + Self::parse_ascii(s.as_bytes()) } } diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs new file mode 100644 index 000000000..33b0dfa03 --- /dev/null +++ b/library/std/src/net/socket_addr.rs @@ -0,0 +1,974 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +use crate::cmp::Ordering; +use crate::fmt::{self, Write}; +use crate::hash; +use crate::io; +use crate::iter; +use crate::mem; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use crate::option; +use crate::slice; +use crate::sys::net::netc as c; +use crate::sys_common::net::LookupHost; +use crate::sys_common::{FromInner, IntoInner}; +use crate::vec; + +use super::display_buffer::DisplayBuffer; + +/// An internet socket address, either IPv4 or IPv6. +/// +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. +/// +/// The size of a `SocketAddr` instance may vary depending on the target operating +/// system. +/// +/// [IP address]: IpAddr +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[stable(feature = "rust1", since = "1.0.0")] +pub enum SocketAddr { + /// An IPv4 socket address. + #[stable(feature = "rust1", since = "1.0.0")] + V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), + /// An IPv6 socket address. + #[stable(feature = "rust1", since = "1.0.0")] + V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), +} + +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV4` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`IPv4` address]: Ipv4Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SocketAddrV4 { + ip: Ipv4Addr, + port: u16, +} + +/// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// The size of a `SocketAddrV6` struct may vary depending on the target operating +/// system. Do not assume that this type has the same memory layout as the underlying +/// system representation. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [`IPv6` address]: Ipv6Addr +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` +#[derive(Copy, Clone, Eq, PartialEq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SocketAddrV6 { + ip: Ipv6Addr, + port: u16, + flowinfo: u32, + scope_id: u32, +} + +impl SocketAddr { + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: IpAddr + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[stable(feature = "ip_addr", since = "1.7.0")] + #[must_use] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { + match ip { + IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), + IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), + } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + /// ``` + #[must_use] + #[stable(feature = "ip_addr", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn ip(&self) -> IpAddr { + match *self { + SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), + SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), + } + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_ip(&mut self, new_ip: IpAddr) { + // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. + match (self, new_ip) { + (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), + (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), + (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), + } + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn port(&self) -> u16 { + match *self { + SocketAddr::V4(ref a) => a.port(), + SocketAddr::V6(ref a) => a.port(), + } + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// socket.set_port(1025); + /// assert_eq!(socket.port(), 1025); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_port(&mut self, new_port: u16) { + match *self { + SocketAddr::V4(ref mut a) => a.set_port(new_port), + SocketAddr::V6(ref mut a) => a.set_port(new_port), + } + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv4` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv4` address]: IpAddr::V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), true); + /// assert_eq!(socket.is_ipv6(), false); + /// ``` + #[must_use] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn is_ipv4(&self) -> bool { + matches!(*self, SocketAddr::V4(_)) + } + + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [`IPv6` address], and [`false`] otherwise. + /// + /// [IP address]: IpAddr + /// [`IPv6` address]: IpAddr::V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; + /// + /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); + /// assert_eq!(socket.is_ipv4(), false); + /// assert_eq!(socket.is_ipv6(), true); + /// ``` + #[must_use] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn is_ipv6(&self) -> bool { + matches!(*self, SocketAddr::V6(_)) + } +} + +impl SocketAddrV4 { + /// Creates a new socket address from an [`IPv4` address] and a port number. + /// + /// [`IPv4` address]: Ipv4Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { + SocketAddrV4 { ip, port } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn ip(&self) -> &Ipv4Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } +} + +impl SocketAddrV6 { + /// Creates a new socket address from an [`IPv6` address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [`IPv6` address]: Ipv6Addr + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { + SocketAddrV6 { ip, port, flowinfo, scope_id } + } + + /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn ip(&self) -> &Ipv6Addr { + &self.ip + } + + /// Changes the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + self.ip = new_ip; + } + + /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.port(), 8080); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn port(&self) -> u16 { + self.port + } + + /// Changes the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_port(&mut self, new_port: u16) { + self.port = new_port; + } + + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// assert_eq!(socket.flowinfo(), 10); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn flowinfo(&self) -> u32 { + self.flowinfo + } + + /// Changes the flow information associated with this socket address. + /// + /// See [`SocketAddrV6::flowinfo`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// socket.set_flowinfo(56); + /// assert_eq!(socket.flowinfo(), 56); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + self.flowinfo = new_flowinfo; + } + + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// assert_eq!(socket.scope_id(), 78); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + pub const fn scope_id(&self) -> u32 { + self.scope_id + } + + /// Changes the scope ID associated with this socket address. + /// + /// See [`SocketAddrV6::scope_id`]'s documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// socket.set_scope_id(42); + /// assert_eq!(socket.scope_id(), 42); + /// ``` + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + pub fn set_scope_id(&mut self, new_scope_id: u32) { + self.scope_id = new_scope_id; + } +} + +impl FromInner for SocketAddrV4 { + fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { + SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) } + } +} + +impl FromInner for SocketAddrV6 { + fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { + SocketAddrV6 { + ip: Ipv6Addr::from_inner(addr.sin6_addr), + port: u16::from_be(addr.sin6_port), + flowinfo: addr.sin6_flowinfo, + scope_id: addr.sin6_scope_id, + } + } +} + +impl IntoInner for SocketAddrV4 { + fn into_inner(self) -> c::sockaddr_in { + c::sockaddr_in { + sin_family: c::AF_INET as c::sa_family_t, + sin_port: self.port.to_be(), + sin_addr: self.ip.into_inner(), + ..unsafe { mem::zeroed() } + } + } +} + +impl IntoInner for SocketAddrV6 { + fn into_inner(self) -> c::sockaddr_in6 { + c::sockaddr_in6 { + sin6_family: c::AF_INET6 as c::sa_family_t, + sin6_port: self.port.to_be(), + sin6_addr: self.ip.into_inner(), + sin6_flowinfo: self.flowinfo, + sin6_scope_id: self.scope_id, + ..unsafe { mem::zeroed() } + } + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for SocketAddr { + /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. + fn from(sock4: SocketAddrV4) -> SocketAddr { + SocketAddr::V4(sock4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for SocketAddr { + /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. + fn from(sock6: SocketAddrV6) -> SocketAddr { + SocketAddr::V6(sock6) + } +} + +#[stable(feature = "addr_from_into_ip", since = "1.17.0")] +impl> From<(I, u16)> for SocketAddr { + /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. + /// + /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`] + /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`]. + /// + /// `u16` is treated as port of the newly created [`SocketAddr`]. + fn from(pieces: (I, u16)) -> SocketAddr { + SocketAddr::new(pieces.0.into(), pieces.1) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + SocketAddr::V4(ref a) => a.fmt(f), + SocketAddr::V6(ref a) => a.fmt(f), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddrV4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If there are no alignment requirements, write the socket address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. + if f.precision().is_none() && f.width().is_none() { + write!(f, "{}:{}", self.ip(), self.port()) + } else { + const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536"; + + let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new(); + // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail. + write!(buf, "{}:{}", self.ip(), self.port()).unwrap(); + + f.pad(buf.as_str()) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for SocketAddrV4 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for SocketAddrV6 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If there are no alignment requirements, write the socket address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. + if f.precision().is_none() && f.width().is_none() { + match self.scope_id() { + 0 => write!(f, "[{}]:{}", self.ip(), self.port()), + scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()), + } + } else { + const LONGEST_IPV6_SOCKET_ADDR: &str = + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536"; + + let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new(); + match self.scope_id() { + 0 => write!(buf, "[{}]:{}", self.ip(), self.port()), + scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()), + } + // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail. + .unwrap(); + + f.pad(buf.as_str()) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for SocketAddrV6 { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV4 { + fn partial_cmp(&self, other: &SocketAddrV4) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV6 { + fn partial_cmp(&self, other: &SocketAddrV6) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl Ord for SocketAddrV4 { + fn cmp(&self, other: &SocketAddrV4) -> Ordering { + self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl Ord for SocketAddrV6 { + fn cmp(&self, other: &SocketAddrV6) -> Ordering { + self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for SocketAddrV4 { + fn hash(&self, s: &mut H) { + (self.port, self.ip).hash(s) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for SocketAddrV6 { + fn hash(&self, s: &mut H) { + (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s) + } +} + +/// A trait for objects which can be converted or resolved to one or more +/// [`SocketAddr`] values. +/// +/// This trait is used for generic address resolution when constructing network +/// objects. By default it is implemented for the following types: +/// +/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. +/// +/// * [`SocketAddrV4`], [`SocketAddrV6`], ([IpAddr], [u16]), +/// ([Ipv4Addr], [u16]), ([Ipv6Addr], [u16]): +/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. +/// +/// * (&[str], [u16]): &[str] should be either a string representation +/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host +/// name. [`u16`] is the port number. +/// +/// * &[str]: the string should be either a string representation of a +/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like +/// `:` pair where `` is a [`u16`] value. +/// +/// This trait allows constructing network objects like [`TcpStream`] or +/// [`UdpSocket`] easily with values of various types for the bind/connection +/// address. It is needed because sometimes one type is more appropriate than +/// the other: for simple uses a string like `"localhost:12345"` is much nicer +/// than manual construction of the corresponding [`SocketAddr`], but sometimes +/// [`SocketAddr`] value is *the* main source of the address, and converting it to +/// some other type (e.g., a string) just for it to be converted back to +/// [`SocketAddr`] in constructor methods is pointless. +/// +/// Addresses returned by the operating system that are not IP addresses are +/// silently ignored. +/// +/// [`FromStr`]: crate::str::FromStr "std::str::FromStr" +/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream" +/// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs +/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket" +/// +/// # Examples +/// +/// Creating a [`SocketAddr`] iterator that yields one item: +/// +/// ``` +/// use std::net::{ToSocketAddrs, SocketAddr}; +/// +/// let addr = SocketAddr::from(([127, 0, 0, 1], 443)); +/// let mut addrs_iter = addr.to_socket_addrs().unwrap(); +/// +/// assert_eq!(Some(addr), addrs_iter.next()); +/// assert!(addrs_iter.next().is_none()); +/// ``` +/// +/// Creating a [`SocketAddr`] iterator from a hostname: +/// +/// ```no_run +/// use std::net::{SocketAddr, ToSocketAddrs}; +/// +/// // assuming 'localhost' resolves to 127.0.0.1 +/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap(); +/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443)))); +/// assert!(addrs_iter.next().is_none()); +/// +/// // assuming 'foo' does not resolve +/// assert!("foo:443".to_socket_addrs().is_err()); +/// ``` +/// +/// Creating a [`SocketAddr`] iterator that yields multiple items: +/// +/// ``` +/// use std::net::{SocketAddr, ToSocketAddrs}; +/// +/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80)); +/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443)); +/// let addrs = vec![addr1, addr2]; +/// +/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap(); +/// +/// assert_eq!(Some(addr1), addrs_iter.next()); +/// assert_eq!(Some(addr2), addrs_iter.next()); +/// assert!(addrs_iter.next().is_none()); +/// ``` +/// +/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted +/// socket address `&str` (missing the port): +/// +/// ``` +/// use std::io; +/// use std::net::ToSocketAddrs; +/// +/// let err = "127.0.0.1".to_socket_addrs().unwrap_err(); +/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); +/// ``` +/// +/// [`TcpStream::connect`] is an example of an function that utilizes +/// `ToSocketAddrs` as a trait bound on its parameter in order to accept +/// different types: +/// +/// ```no_run +/// use std::net::{TcpStream, Ipv4Addr}; +/// +/// let stream = TcpStream::connect(("127.0.0.1", 443)); +/// // or +/// let stream = TcpStream::connect("127.0.0.1:443"); +/// // or +/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443)); +/// ``` +/// +/// [`TcpStream::connect`]: crate::net::TcpStream::connect +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ToSocketAddrs { + /// Returned iterator over socket addresses which this type may correspond + /// to. + #[stable(feature = "rust1", since = "1.0.0")] + type Iter: Iterator; + + /// Converts this object to an iterator of resolved [`SocketAddr`]s. + /// + /// The returned iterator might not actually yield any values depending on the + /// outcome of any resolution performed. + /// + /// Note that this function may block the current thread while resolution is + /// performed. + #[stable(feature = "rust1", since = "1.0.0")] + fn to_socket_addrs(&self) -> io::Result; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddr { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + Ok(Some(*self).into_iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddrV4 { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + SocketAddr::V4(*self).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for SocketAddrV6 { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + SocketAddr::V6(*self).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (IpAddr, u16) { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (ip, port) = *self; + match ip { + IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), + IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (Ipv4Addr, u16) { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (ip, port) = *self; + SocketAddrV4::new(ip, port).to_socket_addrs() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (Ipv6Addr, u16) { + type Iter = option::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (ip, port) = *self; + SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs() + } +} + +fn resolve_socket_addr(lh: LookupHost) -> io::Result> { + let p = lh.port(); + let v: Vec<_> = lh + .map(|mut a| { + a.set_port(p); + a + }) + .collect(); + Ok(v.into_iter()) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for (&str, u16) { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + let (host, port) = *self; + + // try to parse the host as a regular IP address first + if let Ok(addr) = host.parse::() { + let addr = SocketAddrV4::new(addr, port); + return Ok(vec![SocketAddr::V4(addr)].into_iter()); + } + if let Ok(addr) = host.parse::() { + let addr = SocketAddrV6::new(addr, port, 0, 0); + return Ok(vec![SocketAddr::V6(addr)].into_iter()); + } + + resolve_socket_addr((host, port).try_into()?) + } +} + +#[stable(feature = "string_u16_to_socket_addrs", since = "1.46.0")] +impl ToSocketAddrs for (String, u16) { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + (&*self.0, self.1).to_socket_addrs() + } +} + +// accepts strings like 'localhost:12345' +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for str { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + // try to parse as a regular SocketAddr first + if let Ok(addr) = self.parse() { + return Ok(vec![addr].into_iter()); + } + + resolve_socket_addr(self.try_into()?) + } +} + +#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")] +impl<'a> ToSocketAddrs for &'a [SocketAddr] { + type Iter = iter::Cloned>; + + fn to_socket_addrs(&self) -> io::Result { + Ok(self.iter().cloned()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToSocketAddrs for &T { + type Iter = T::Iter; + fn to_socket_addrs(&self) -> io::Result { + (**self).to_socket_addrs() + } +} + +#[stable(feature = "string_to_socket_addrs", since = "1.16.0")] +impl ToSocketAddrs for String { + type Iter = vec::IntoIter; + fn to_socket_addrs(&self) -> io::Result> { + (&**self).to_socket_addrs() + } +} diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs new file mode 100644 index 000000000..15211f819 --- /dev/null +++ b/library/std/src/net/socket_addr/tests.rs @@ -0,0 +1,306 @@ +use crate::net::test::{sa4, sa6, tsa}; +use crate::net::*; + +#[test] +fn to_socket_addr_ipaddr_u16() { + let a = Ipv4Addr::new(77, 88, 21, 11); + let p = 12345; + let e = SocketAddr::V4(SocketAddrV4::new(a, p)); + assert_eq!(Ok(vec![e]), tsa((a, p))); +} + +#[test] +fn to_socket_addr_str_u16() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] + assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; +} + +#[test] +fn to_socket_addr_str() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] + assert!(tsa("localhost:23924").unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; +} + +#[test] +fn to_socket_addr_string() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); + + let s = format!("{}:{}", "77.88.21.11", "24352"); + assert_eq!(Ok(vec![a]), tsa(s)); + // s has been moved into the tsa call +} + +#[test] +fn ipv4_socket_addr_to_string() { + // Shortest possible IPv4 length. + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0"); + + // Longest possible IPv4 length. + assert_eq!( + SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(), + "255.255.255.255:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + "1.1.1.1:53 " + ); + assert_eq!( + &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + " 1.1.1.1:53" + ); +} + +#[test] +fn ipv6_socket_addr_to_string() { + // IPv4-mapped address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0) + .to_string(), + "[::ffff:192.0.2.128]:8080" + ); + + // IPv4-compatible address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), + "[::192.0.2.128]:8080" + ); + + // IPv6 address with no zero segments. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(), + "[8:9:a:b:c:d:e:f]:80" + ); + + // Shortest possible IPv6 length. + assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0"); + + // Longest possible IPv6 length. + assert_eq!( + SocketAddrV6::new( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888), + u16::MAX, + u32::MAX, + u32::MAX, + ) + .to_string(), + "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + "[1:2:3:4:5:6:7:8]:9 " + ); + assert_eq!( + &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + " [1:2:3:4:5:6:7:8]:9" + ); +} + +#[test] +fn bind_udp_socket_bad() { + // rust-lang/rust#53957: This is a regression test for a parsing problem + // discovered as part of issue rust-lang/rust#23076, where we were + // incorrectly parsing invalid input and then that would result in a + // successful `UdpSocket` binding when we would expect failure. + // + // At one time, this test was written as a call to `tsa` with + // INPUT_23076. However, that structure yields an unreliable test, + // because it ends up passing junk input to the DNS server, and some DNS + // servers will respond with `Ok` to such input, with the ip address of + // the DNS server itself. + // + // This form of the test is more robust: even when the DNS server + // returns its own address, it is still an error to bind a UDP socket to + // a non-local address, and so we still get an error here in that case. + + const INPUT_23076: &str = "1200::AB00:1234::2552:7777:1313:34300"; + + assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err()) +} + +#[test] +fn set_ip() { + fn ip4(low: u8) -> Ipv4Addr { + Ipv4Addr::new(77, 88, 21, low) + } + fn ip6(low: u16) -> Ipv6Addr { + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) + } + + let mut v4 = SocketAddrV4::new(ip4(11), 80); + assert_eq!(v4.ip(), &ip4(11)); + v4.set_ip(ip4(12)); + assert_eq!(v4.ip(), &ip4(12)); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); + addr.set_ip(IpAddr::V4(ip4(13))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); + addr.set_ip(IpAddr::V6(ip6(14))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); + + let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); + assert_eq!(v6.ip(), &ip6(1)); + v6.set_ip(ip6(2)); + assert_eq!(v6.ip(), &ip6(2)); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); + addr.set_ip(IpAddr::V6(ip6(3))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); + addr.set_ip(IpAddr::V4(ip4(4))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); +} + +#[test] +fn set_port() { + let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); + assert_eq!(v4.port(), 80); + v4.set_port(443); + assert_eq!(v4.port(), 443); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); + + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); + assert_eq!(v6.port(), 80); + v6.set_port(443); + assert_eq!(v6.port(), 443); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); +} + +#[test] +fn set_flowinfo() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); + assert_eq!(v6.flowinfo(), 10); + v6.set_flowinfo(20); + assert_eq!(v6.flowinfo(), 20); +} + +#[test] +fn set_scope_id() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); + assert_eq!(v6.scope_id(), 10); + v6.set_scope_id(20); + assert_eq!(v6.scope_id(), 20); +} + +#[test] +fn is_v4() { + let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); + assert!(v4.is_ipv4()); + assert!(!v4.is_ipv6()); +} + +#[test] +fn is_v6() { + let v6 = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), + 80, + 10, + 0, + )); + assert!(!v6.is_ipv4()); + assert!(v6.is_ipv6()); +} + +#[test] +fn socket_v4_to_str() { + let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); + + assert_eq!(format!("{socket}"), "192.168.0.1:8080"); + assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 "); + assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080"); + assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 "); + assert_eq!(format!("{socket:.10}"), "192.168.0."); +} + +#[test] +fn socket_v6_to_str() { + let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); + + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::"); + + socket.set_scope_id(5); + + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5"); +} + +#[test] +fn compare() { + let v4_1 = "224.120.45.1:23456".parse::().unwrap(); + let v4_2 = "224.210.103.5:12345".parse::().unwrap(); + let v4_3 = "224.210.103.5:23456".parse::().unwrap(); + let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); + let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); + let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); + + // equality + assert_eq!(v4_1, v4_1); + assert_eq!(v6_1, v6_1); + assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); + assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); + assert!(v4_1 != v4_2); + assert!(v6_1 != v6_2); + + // compare different addresses + assert!(v4_1 < v4_2); + assert!(v6_1 < v6_2); + assert!(v4_2 > v4_1); + assert!(v6_2 > v6_1); + + // compare the same address with different ports + assert!(v4_2 < v4_3); + assert!(v6_2 < v6_3); + assert!(v4_3 > v4_2); + assert!(v6_3 > v6_2); + + // compare different addresses with the same port + assert!(v4_1 < v4_3); + assert!(v6_1 < v6_3); + assert!(v4_3 > v4_1); + assert!(v6_3 > v6_1); + + // compare with an inferred right-hand side + assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); + assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); + assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); +} diff --git a/library/std/src/os/android/mod.rs b/library/std/src/os/android/mod.rs index dbb0127f3..5adcb82b6 100644 --- a/library/std/src/os/android/mod.rs +++ b/library/std/src/os/android/mod.rs @@ -3,4 +3,5 @@ #![stable(feature = "raw_ext", since = "1.1.0")] pub mod fs; +pub mod net; pub mod raw; diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs new file mode 100644 index 000000000..ff96125c3 --- /dev/null +++ b/library/std/src/os/android/net.rs @@ -0,0 +1,4 @@ +//! Linux and Android-specific definitions for socket options. + +#![unstable(feature = "tcp_quickack", issue = "96256")] +pub use crate::os::net::tcp::TcpStreamExt; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a463bc41d..71e33fb9e 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -104,7 +104,8 @@ impl BorrowedFd<'_> { #[cfg(target_os = "espidf")] let cmd = libc::F_DUPFD; - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + // Avoid using file descriptors below 3 as they are used for stdio + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?; Ok(unsafe { OwnedFd::from_raw_fd(fd) }) } diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 081915ed1..1b3d11042 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -14,7 +14,7 @@ use crate::os::wasi::io::OwnedFd; use crate::sys_common::{AsInner, IntoInner}; /// Raw file descriptors. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] pub type RawFd = raw::c_int; @@ -23,7 +23,7 @@ pub type RawFd = raw::c_int; /// This is only available on unix and WASI platforms and must be imported in /// order to call the method. Windows platforms have a corresponding /// `AsRawHandle` and `AsRawSocket` set of traits. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { /// Extracts the raw file descriptor. @@ -59,7 +59,7 @@ pub trait AsRawFd { /// A trait to express the ability to construct an object from a raw file /// descriptor. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file @@ -103,7 +103,7 @@ pub trait FromRawFd { /// A trait to express the ability to consume an object and acquire ownership of /// its raw file descriptor. -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[stable(feature = "into_raw_os", since = "1.4.0")] pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs index a40dabe19..39a42f4e1 100644 --- a/library/std/src/os/fortanix_sgx/mod.rs +++ b/library/std/src/os/fortanix_sgx/mod.rs @@ -26,10 +26,13 @@ pub mod usercalls { free, insecure_time, launch_thread, read, read_alloc, send, wait, write, }; pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs}; + pub use crate::sys::abi::usercalls::raw::{Register, RegisterArgument, ReturnValue}; // fortanix-sgx-abi re-exports pub use crate::sys::abi::usercalls::raw::Error; - pub use crate::sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall}; + pub use crate::sys::abi::usercalls::raw::{ + ByteBuffer, Cancel, FifoDescriptor, Return, Usercall, + }; pub use crate::sys::abi::usercalls::raw::{Fd, Result, Tcs}; pub use crate::sys::abi::usercalls::raw::{ EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT, diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index 8e7776f66..c17053011 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -4,5 +4,6 @@ #![doc(cfg(target_os = "linux"))] pub mod fs; +pub mod net; pub mod process; pub mod raw; diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs new file mode 100644 index 000000000..ff96125c3 --- /dev/null +++ b/library/std/src/os/linux/net.rs @@ -0,0 +1,4 @@ +//! Linux and Android-specific definitions for socket options. + +#![unstable(feature = "tcp_quickack", issue = "96256")] +pub use crate::os::net::tcp::TcpStreamExt; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 6fbaa42c7..18c64b510 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -148,3 +148,6 @@ pub mod vxworks; #[cfg(any(unix, target_os = "wasi", doc))] mod fd; + +#[cfg(any(target_os = "linux", target_os = "android", doc))] +mod net; diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs new file mode 100644 index 000000000..d6d84d24e --- /dev/null +++ b/library/std/src/os/net/mod.rs @@ -0,0 +1,7 @@ +//! Linux and Android-specific definitions for socket options. + +#![unstable(feature = "tcp_quickack", issue = "96256")] +#![doc(cfg(any(target_os = "linux", target_os = "android",)))] +pub mod tcp; +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/net/tcp.rs b/library/std/src/os/net/tcp.rs new file mode 100644 index 000000000..5e9ee65a4 --- /dev/null +++ b/library/std/src/os/net/tcp.rs @@ -0,0 +1,70 @@ +//! Linux and Android-specific tcp extensions to primitives in the [`std::net`] module. +//! +//! [`std::net`]: crate::net + +use crate::io; +use crate::net; +use crate::sealed::Sealed; +use crate::sys_common::AsInner; + +/// Os-specific extensions for [`TcpStream`] +/// +/// [`TcpStream`]: net::TcpStream +#[unstable(feature = "tcp_quickack", issue = "96256")] +pub trait TcpStreamExt: Sealed { + /// Enable or disable `TCP_QUICKACK`. + /// + /// This flag causes Linux to eagerly send ACKs rather than delaying them. + /// Linux may reset this flag after further operations on the socket. + /// + /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) and + /// [TCP delayed acknowledgement](https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment) + /// for more information. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_quickack)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_quickack(true).expect("set_quickack call failed"); + /// ``` + #[unstable(feature = "tcp_quickack", issue = "96256")] + fn set_quickack(&self, quickack: bool) -> io::Result<()>; + + /// Gets the value of the `TCP_QUICKACK` option on this socket. + /// + /// For more information about this option, see [`TcpStreamExt::set_quickack`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_quickack)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_quickack(true).expect("set_quickack call failed"); + /// assert_eq!(stream.quickack().unwrap_or(false), true); + /// ``` + #[unstable(feature = "tcp_quickack", issue = "96256")] + fn quickack(&self) -> io::Result; +} + +#[unstable(feature = "tcp_quickack", issue = "96256")] +impl Sealed for net::TcpStream {} + +#[unstable(feature = "tcp_quickack", issue = "96256")] +impl TcpStreamExt for net::TcpStream { + fn set_quickack(&self, quickack: bool) -> io::Result<()> { + self.as_inner().as_inner().set_quickack(quickack) + } + + fn quickack(&self) -> io::Result { + self.as_inner().as_inner().quickack() + } +} diff --git a/library/std/src/os/net/tests.rs b/library/std/src/os/net/tests.rs new file mode 100644 index 000000000..4704e3156 --- /dev/null +++ b/library/std/src/os/net/tests.rs @@ -0,0 +1,29 @@ +#[cfg(any(target_os = "android", target_os = "linux",))] +#[test] +fn quickack() { + use crate::{ + net::{test::next_test_ip4, TcpListener, TcpStream}, + os::net::tcp::TcpStreamExt, + }; + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; + } + + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_quickack(false)); + assert_eq!(false, t!(stream.quickack())); + t!(stream.set_quickack(true)); + assert_eq!(true, t!(stream.quickack())); + t!(stream.set_quickack(false)); + assert_eq!(false, t!(stream.quickack())); +} diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 9aeae4b2c..094085e19 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, mem, ptr}; +use crate::{fmt, io, mem, ptr}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -64,18 +64,6 @@ enum AddressKind<'a> { Abstract(&'a [u8]), } -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - /// An address associated with a Unix socket. /// /// # Examples @@ -329,7 +317,7 @@ impl SocketAddr { crate::ptr::copy_nonoverlapping( namespace.as_ptr(), - addr.sun_path.as_mut_ptr().offset(1) as *mut u8, + addr.sun_path.as_mut_ptr().add(1) as *mut u8, namespace.len(), ); let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; @@ -343,7 +331,7 @@ impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.address() { AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()), AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"), } } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 8008acfd1..f758f88d0 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -838,6 +838,31 @@ impl UnixDatagram { self.0.passcred() } + /// Set the id of the socket for network filtering purpose + /// + #[cfg_attr( + any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"), + doc = "```no_run" + )] + #[cfg_attr( + not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")), + doc = "```ignore" + )] + /// #![feature(unix_set_mark)] + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_mark(32)?; + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))] + #[unstable(feature = "unix_set_mark", issue = "96467")] + pub fn set_mark(&self, mark: u32) -> io::Result<()> { + self.0.set_mark(mark) + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 7c0d53950..02090afc8 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -73,9 +73,11 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; + const backlog: libc::c_int = + if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 }; cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?; + cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) } @@ -109,12 +111,16 @@ impl UnixListener { pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + #[cfg(target_os = "linux")] + const backlog: libc::c_int = -1; + #[cfg(not(target_os = "linux"))] + const backlog: libc::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _, ))?; - cvt(libc::listen(inner.as_raw_fd(), 128))?; + cvt(libc::listen(inner.as_raw_fd(), backlog))?; Ok(UnixListener(inner)) } } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index cc3a88587..dff8f6e85 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -427,6 +427,31 @@ impl UnixStream { self.0.passcred() } + /// Set the id of the socket for network filtering purpose + /// + #[cfg_attr( + any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"), + doc = "```no_run" + )] + #[cfg_attr( + not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")), + doc = "```ignore" + )] + /// #![feature(unix_set_mark)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// sock.set_mark(32)?; + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))] + #[unstable(feature = "unix_set_mark", issue = "96467")] + pub fn set_mark(&self, mark: u32) -> io::Result<()> { + self.0.set_mark(mark) + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index 930aca887..75703af6a 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -1,9 +1,10 @@ //! Owned and borrowed file descriptors. -#![unstable(feature = "wasi_ext", issue = "71213")] +#![stable(feature = "io_safety_wasi", since = "1.65.0")] // Tests for this module #[cfg(test)] mod tests; +#[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use crate::os::fd::owned::*; diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs index 6c884e2ea..4f5cfbf9a 100644 --- a/library/std/src/os/wasi/io/mod.rs +++ b/library/std/src/os/wasi/io/mod.rs @@ -1,12 +1,12 @@ //! WASI-specific extensions to general I/O primitives. #![deny(unsafe_op_in_unsafe_fn)] -#![unstable(feature = "wasi_ext", issue = "71213")] +#![stable(feature = "io_safety_wasi", since = "1.65.0")] mod fd; mod raw; -#[unstable(feature = "wasi_ext", issue = "71213")] +#[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use fd::*; -#[unstable(feature = "wasi_ext", issue = "71213")] +#[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use raw::*; diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs index da3b36ada..4ac792ee8 100644 --- a/library/std/src/os/wasi/io/raw.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -1,20 +1,6 @@ //! WASI-specific extensions to general I/O primitives. -#![unstable(feature = "wasi_ext", issue = "71213")] +#![stable(feature = "io_safety_wasi", since = "1.65.0")] -// NOTE: despite the fact that this module is unstable, -// stable Rust had the capability to access the stable -// re-exported items from os::fd::raw through this -// unstable module. -// In PR #95956 the stability checker was changed to check -// all path segments of an item rather than just the last, -// which caused the aforementioned stable usage to regress -// (see issue #99502). -// As a result, the items in os::fd::raw were given the -// rustc_allowed_through_unstable_modules attribute. -// No regression tests were added to ensure this property, -// as CI is not configured to test wasm32-wasi. -// If this module is stabilized, -// you may want to remove those attributes -// (assuming no other unstable modules need them). +#[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use crate::os::fd::raw::*; diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 45bc56efb..c4f022de0 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -295,23 +295,22 @@ pub fn get_backtrace_style() -> Option { return Some(style); } - // Setting environment variables for Fuchsia components isn't a standard - // or easily supported workflow. For now, display backtraces by default. - let format = if cfg!(target_os = "fuchsia") { - BacktraceStyle::Full - } else { - crate::env::var_os("RUST_BACKTRACE") - .map(|x| { - if &x == "0" { - BacktraceStyle::Off - } else if &x == "full" { - BacktraceStyle::Full - } else { - BacktraceStyle::Short - } - }) - .unwrap_or(BacktraceStyle::Off) - }; + let format = crate::env::var_os("RUST_BACKTRACE") + .map(|x| { + if &x == "0" { + BacktraceStyle::Off + } else if &x == "full" { + BacktraceStyle::Full + } else { + BacktraceStyle::Short + } + }) + .unwrap_or(if cfg!(target_os = "fuchsia") { + // Fuchsia components default to full backtrace. + BacktraceStyle::Full + } else { + BacktraceStyle::Off + }); set_backtrace_style(format); Some(format) } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 351cf6988..dd307022c 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1768,6 +1768,7 @@ fn test_windows_absolute() { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { let prefix = "my/home"; let mut paths: Vec<_> = @@ -1781,6 +1782,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -1799,6 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { let prefix = "my/home"; let paths: Vec<_> = @@ -1817,6 +1820,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -1835,6 +1839,7 @@ fn bench_path_hashset(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset_miss(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = diff --git a/library/std/src/personality.rs b/library/std/src/personality.rs new file mode 100644 index 000000000..63f0ad4f1 --- /dev/null +++ b/library/std/src/personality.rs @@ -0,0 +1,46 @@ +//! This module contains the implementation of the `eh_personality` lang item. +//! +//! The actual implementation is heavily dependent on the target since Rust +//! tries to use the native stack unwinding mechanism whenever possible. +//! +//! This personality function is still required with `-C panic=abort` because +//! it is used to catch foreign exceptions from `extern "C-unwind"` and turn +//! them into aborts. +//! +//! Additionally, ARM EHABI uses the personality function when generating +//! backtraces. + +mod dwarf; + +#[cfg(not(test))] +cfg_if::cfg_if! { + if #[cfg(target_os = "emscripten")] { + mod emcc; + } else if #[cfg(target_env = "msvc")] { + // This is required by the compiler to exist (e.g., it's a lang item), + // but it's never actually called by the compiler because + // _CxxFrameHandler3 is the personality function that is always used. + // Hence this is just an aborting stub. + #[lang = "eh_personality"] + fn rust_eh_personality() { + core::intrinsics::abort() + } + } else if #[cfg(any( + all(target_family = "windows", target_env = "gnu"), + target_os = "psp", + target_os = "solid_asp3", + all(target_family = "unix", not(target_os = "espidf")), + all(target_vendor = "fortanix", target_env = "sgx"), + ))] { + mod gcc; + } else { + // Targets that don't support unwinding. + // - family=wasm + // - os=none ("bare metal" targets) + // - os=uefi + // - os=espidf + // - os=hermit + // - nvptx64-nvidia-cuda + // - arch=avr + } +} diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs new file mode 100644 index 000000000..8799137b7 --- /dev/null +++ b/library/std/src/personality/dwarf/eh.rs @@ -0,0 +1,192 @@ +//! Parsing of GCC-style Language-Specific Data Area (LSDA) +//! For details see: +//! * +//! * +//! * +//! * +//! +//! A reference implementation may be found in the GCC source tree +//! (`/libgcc/unwind-c.c` as of this writing). + +#![allow(non_upper_case_globals)] +#![allow(unused)] + +use super::DwarfReader; +use core::mem; + +pub const DW_EH_PE_omit: u8 = 0xFF; +pub const DW_EH_PE_absptr: u8 = 0x00; + +pub const DW_EH_PE_uleb128: u8 = 0x01; +pub const DW_EH_PE_udata2: u8 = 0x02; +pub const DW_EH_PE_udata4: u8 = 0x03; +pub const DW_EH_PE_udata8: u8 = 0x04; +pub const DW_EH_PE_sleb128: u8 = 0x09; +pub const DW_EH_PE_sdata2: u8 = 0x0A; +pub const DW_EH_PE_sdata4: u8 = 0x0B; +pub const DW_EH_PE_sdata8: u8 = 0x0C; + +pub const DW_EH_PE_pcrel: u8 = 0x10; +pub const DW_EH_PE_textrel: u8 = 0x20; +pub const DW_EH_PE_datarel: u8 = 0x30; +pub const DW_EH_PE_funcrel: u8 = 0x40; +pub const DW_EH_PE_aligned: u8 = 0x50; + +pub const DW_EH_PE_indirect: u8 = 0x80; + +#[derive(Copy, Clone)] +pub struct EHContext<'a> { + pub ip: usize, // Current instruction pointer + pub func_start: usize, // Address of the current function + pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section + pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section +} + +pub enum EHAction { + None, + Cleanup(usize), + Catch(usize), + Terminate, +} + +pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); + +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { + if lsda.is_null() { + return Ok(EHAction::None); + } + + let func_start = context.func_start; + let mut reader = DwarfReader::new(lsda); + + let start_encoding = reader.read::(); + // base address for landing pad offsets + let lpad_base = if start_encoding != DW_EH_PE_omit { + read_encoded_pointer(&mut reader, context, start_encoding)? + } else { + func_start + }; + + let ttype_encoding = reader.read::(); + if ttype_encoding != DW_EH_PE_omit { + // Rust doesn't analyze exception types, so we don't care about the type table + reader.read_uleb128(); + } + + let call_site_encoding = reader.read::(); + let call_site_table_length = reader.read_uleb128(); + let action_table = reader.ptr.add(call_site_table_length as usize); + let ip = context.ip; + + if !USING_SJLJ_EXCEPTIONS { + while reader.ptr < action_table { + let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?; + let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?; + let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?; + let cs_action = reader.read_uleb128(); + // Callsite table is sorted by cs_start, so if we've passed the ip, we + // may stop searching. + if ip < func_start + cs_start { + break; + } + if ip < func_start + cs_start + cs_len { + if cs_lpad == 0 { + return Ok(EHAction::None); + } else { + let lpad = lpad_base + cs_lpad; + return Ok(interpret_cs_action(cs_action, lpad)); + } + } + } + // Ip is not present in the table. This should not happen... but it does: issue #35011. + // So rather than returning EHAction::Terminate, we do this. + Ok(EHAction::None) + } else { + // SjLj version: + // The "IP" is an index into the call-site table, with two exceptions: + // -1 means 'no-action', and 0 means 'terminate'. + match ip as isize { + -1 => return Ok(EHAction::None), + 0 => return Ok(EHAction::Terminate), + _ => (), + } + let mut idx = ip; + loop { + let cs_lpad = reader.read_uleb128(); + let cs_action = reader.read_uleb128(); + idx -= 1; + if idx == 0 { + // Can never have null landing pad for sjlj -- that would have + // been indicated by a -1 call site index. + let lpad = (cs_lpad + 1) as usize; + return Ok(interpret_cs_action(cs_action, lpad)); + } + } + } +} + +fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { + if cs_action == 0 { + // If cs_action is 0 then this is a cleanup (Drop::drop). We run these + // for both Rust panics and foreign exceptions. + EHAction::Cleanup(lpad) + } else { + // Stop unwinding Rust panics at catch_unwind. + EHAction::Catch(lpad) + } +} + +#[inline] +fn round_up(unrounded: usize, align: usize) -> Result { + if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) } +} + +unsafe fn read_encoded_pointer( + reader: &mut DwarfReader, + context: &EHContext<'_>, + encoding: u8, +) -> Result { + if encoding == DW_EH_PE_omit { + return Err(()); + } + + // DW_EH_PE_aligned implies it's an absolute pointer value + if encoding == DW_EH_PE_aligned { + reader.ptr = round_up(reader.ptr as usize, mem::size_of::())? as *const u8; + return Ok(reader.read::()); + } + + let mut result = match encoding & 0x0F { + DW_EH_PE_absptr => reader.read::(), + DW_EH_PE_uleb128 => reader.read_uleb128() as usize, + DW_EH_PE_udata2 => reader.read::() as usize, + DW_EH_PE_udata4 => reader.read::() as usize, + DW_EH_PE_udata8 => reader.read::() as usize, + DW_EH_PE_sleb128 => reader.read_sleb128() as usize, + DW_EH_PE_sdata2 => reader.read::() as usize, + DW_EH_PE_sdata4 => reader.read::() as usize, + DW_EH_PE_sdata8 => reader.read::() as usize, + _ => return Err(()), + }; + + result += match encoding & 0x70 { + DW_EH_PE_absptr => 0, + // relative to address of the encoded value, despite the name + DW_EH_PE_pcrel => reader.ptr as usize, + DW_EH_PE_funcrel => { + if context.func_start == 0 { + return Err(()); + } + context.func_start + } + DW_EH_PE_textrel => (*context.get_text_start)(), + DW_EH_PE_datarel => (*context.get_data_start)(), + _ => return Err(()), + }; + + if encoding & DW_EH_PE_indirect != 0 { + result = *(result as *const usize); + } + + Ok(result) +} diff --git a/library/std/src/personality/dwarf/mod.rs b/library/std/src/personality/dwarf/mod.rs new file mode 100644 index 000000000..652fbe95a --- /dev/null +++ b/library/std/src/personality/dwarf/mod.rs @@ -0,0 +1,73 @@ +//! Utilities for parsing DWARF-encoded data streams. +//! See , +//! DWARF-4 standard, Section 7 - "Data Representation" + +// This module is used only by x86_64-pc-windows-gnu for now, but we +// are compiling it everywhere to avoid regressions. +#![allow(unused)] + +#[cfg(test)] +mod tests; + +pub mod eh; + +use core::mem; + +pub struct DwarfReader { + pub ptr: *const u8, +} + +#[repr(C, packed)] +struct Unaligned(T); + +impl DwarfReader { + pub fn new(ptr: *const u8) -> DwarfReader { + DwarfReader { ptr } + } + + // DWARF streams are packed, so e.g., a u32 would not necessarily be aligned + // on a 4-byte boundary. This may cause problems on platforms with strict + // alignment requirements. By wrapping data in a "packed" struct, we are + // telling the backend to generate "misalignment-safe" code. + pub unsafe fn read(&mut self) -> T { + let Unaligned(result) = *(self.ptr as *const Unaligned); + self.ptr = self.ptr.add(mem::size_of::()); + result + } + + // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable + // Length Data". + pub unsafe fn read_uleb128(&mut self) -> u64 { + let mut shift: usize = 0; + let mut result: u64 = 0; + let mut byte: u8; + loop { + byte = self.read::(); + result |= ((byte & 0x7F) as u64) << shift; + shift += 7; + if byte & 0x80 == 0 { + break; + } + } + result + } + + pub unsafe fn read_sleb128(&mut self) -> i64 { + let mut shift: u32 = 0; + let mut result: u64 = 0; + let mut byte: u8; + loop { + byte = self.read::(); + result |= ((byte & 0x7F) as u64) << shift; + shift += 7; + if byte & 0x80 == 0 { + break; + } + } + // sign-extend + if shift < u64::BITS && (byte & 0x40) != 0 { + result |= (!0 as u64) << shift; + } + result as i64 + } +} diff --git a/library/std/src/personality/dwarf/tests.rs b/library/std/src/personality/dwarf/tests.rs new file mode 100644 index 000000000..1644f3708 --- /dev/null +++ b/library/std/src/personality/dwarf/tests.rs @@ -0,0 +1,19 @@ +use super::*; + +#[test] +fn dwarf_reader() { + let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF]; + + let mut reader = DwarfReader::new(encoded.as_ptr()); + + unsafe { + assert!(reader.read::() == u8::to_be(1u8)); + assert!(reader.read::() == u16::to_be(0x0203)); + assert!(reader.read::() == u32::to_be(0x04050607)); + + assert!(reader.read_uleb128() == 624485); + assert!(reader.read_sleb128() == -624485); + + assert!(reader.read::() == i8::to_be(-1)); + } +} diff --git a/library/std/src/personality/emcc.rs b/library/std/src/personality/emcc.rs new file mode 100644 index 000000000..f942bdf18 --- /dev/null +++ b/library/std/src/personality/emcc.rs @@ -0,0 +1,20 @@ +//! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward +//! to `__gxx_personality_v0` which is provided by Emscripten. + +use libc::c_int; +use unwind as uw; + +// This is required by the compiler to exist (e.g., it's a lang item), but it's +// never actually called by the compiler. Emscripten EH doesn't use a +// personality function at all, it instead uses __cxa_find_matching_catch. +// Wasm error handling would use __gxx_personality_wasm0. +#[lang = "eh_personality"] +unsafe extern "C" fn rust_eh_personality( + _version: c_int, + _actions: uw::_Unwind_Action, + _exception_class: uw::_Unwind_Exception_Class, + _exception_object: *mut uw::_Unwind_Exception, + _context: *mut uw::_Unwind_Context, +) -> uw::_Unwind_Reason_Code { + core::intrinsics::abort() +} diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs new file mode 100644 index 000000000..7f0b0439c --- /dev/null +++ b/library/std/src/personality/gcc.rs @@ -0,0 +1,279 @@ +//! Implementation of panics backed by libgcc/libunwind (in some form). +//! +//! For background on exception handling and stack unwinding please see +//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and +//! documents linked from it. +//! These are also good reads: +//! * +//! * +//! * +//! +//! ## A brief summary +//! +//! Exception handling happens in two phases: a search phase and a cleanup +//! phase. +//! +//! In both phases the unwinder walks stack frames from top to bottom using +//! information from the stack frame unwind sections of the current process's +//! modules ("module" here refers to an OS module, i.e., an executable or a +//! dynamic library). +//! +//! For each stack frame, it invokes the associated "personality routine", whose +//! address is also stored in the unwind info section. +//! +//! In the search phase, the job of a personality routine is to examine +//! exception object being thrown, and to decide whether it should be caught at +//! that stack frame. Once the handler frame has been identified, cleanup phase +//! begins. +//! +//! In the cleanup phase, the unwinder invokes each personality routine again. +//! This time it decides which (if any) cleanup code needs to be run for +//! the current stack frame. If so, the control is transferred to a special +//! branch in the function body, the "landing pad", which invokes destructors, +//! frees memory, etc. At the end of the landing pad, control is transferred +//! back to the unwinder and unwinding resumes. +//! +//! Once stack has been unwound down to the handler frame level, unwinding stops +//! and the last personality routine transfers control to the catch block. + +use super::dwarf::eh::{self, EHAction, EHContext}; +use libc::{c_int, uintptr_t}; +use unwind as uw; + +// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() +// and TargetLowering::getExceptionSelectorRegister() for each architecture, +// then mapped to DWARF register numbers via register definition tables +// (typically RegisterInfo.td, search for "DwarfRegNum"). +// See also https://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. + +#[cfg(target_arch = "x86")] +const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX + +#[cfg(target_arch = "x86_64")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 + +#[cfg(target_arch = "m68k")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1 + +#[cfg(any(target_arch = "mips", target_arch = "mips64"))] +const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 + +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 + +#[cfg(target_arch = "s390x")] +const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 + +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] +const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 + +#[cfg(target_arch = "hexagon")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 + +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] +const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 + +// The following code is based on GCC's C and C++ personality routines. For reference, see: +// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc +// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c + +cfg_if::cfg_if! { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { + // ARM EHABI personality routine. + // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf + // + // iOS uses the default routine instead since it uses SjLj unwinding. + #[lang = "eh_personality"] + unsafe extern "C" fn rust_eh_personality( + state: uw::_Unwind_State, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + ) -> uw::_Unwind_Reason_Code { + let state = state as c_int; + let action = state & uw::_US_ACTION_MASK as c_int; + let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { + // Backtraces on ARM will call the personality routine with + // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases + // we want to continue unwinding the stack, otherwise all our backtraces + // would end at __rust_try + if state & uw::_US_FORCE_UNWIND as c_int != 0 { + return continue_unwind(exception_object, context); + } + true + } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { + false + } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int { + return continue_unwind(exception_object, context); + } else { + return uw::_URC_FAILURE; + }; + + // The DWARF unwinder assumes that _Unwind_Context holds things like the function + // and LSDA pointers, however ARM EHABI places them into the exception object. + // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which + // take only the context pointer, GCC personality routines stash a pointer to + // exception_object in the context, using location reserved for ARM's + // "scratch register" (r12). + uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr); + // ...A more principled approach would be to provide the full definition of ARM's + // _Unwind_Context in our libunwind bindings and fetch the required data from there + // directly, bypassing DWARF compatibility functions. + + let eh_action = match find_eh_action(context) { + Ok(action) => action, + Err(_) => return uw::_URC_FAILURE, + }; + if search_phase { + match eh_action { + EHAction::None | EHAction::Cleanup(_) => { + return continue_unwind(exception_object, context); + } + EHAction::Catch(_) => { + // EHABI requires the personality routine to update the + // SP value in the barrier cache of the exception object. + (*exception_object).private[5] = + uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG); + return uw::_URC_HANDLER_FOUND; + } + EHAction::Terminate => return uw::_URC_FAILURE, + } + } else { + match eh_action { + EHAction::None => return continue_unwind(exception_object, context), + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + uw::_Unwind_SetGR( + context, + UNWIND_DATA_REG.0, + exception_object as uintptr_t, + ); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FAILURE, + } + } + + // On ARM EHABI the personality routine is responsible for actually + // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + unsafe fn continue_unwind( + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + ) -> uw::_Unwind_Reason_Code { + if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON { + uw::_URC_CONTINUE_UNWIND + } else { + uw::_URC_FAILURE + } + } + // defined in libgcc + extern "C" { + fn __gnu_unwind_frame( + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + ) -> uw::_Unwind_Reason_Code; + } + } + } else { + // Default personality routine, which is used directly on most targets + // and indirectly on Windows x86_64 via SEH. + unsafe extern "C" fn rust_eh_personality_impl( + version: c_int, + actions: uw::_Unwind_Action, + _exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + ) -> uw::_Unwind_Reason_Code { + if version != 1 { + return uw::_URC_FATAL_PHASE1_ERROR; + } + let eh_action = match find_eh_action(context) { + Ok(action) => action, + Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, + }; + if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { + match eh_action { + EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => uw::_URC_HANDLER_FOUND, + EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR, + } + } else { + match eh_action { + EHAction::None => uw::_URC_CONTINUE_UNWIND, + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + uw::_Unwind_SetGR( + context, + UNWIND_DATA_REG.0, + exception_object as uintptr_t, + ); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + uw::_URC_INSTALL_CONTEXT + } + EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR, + } + } + } + + cfg_if::cfg_if! { + if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] { + // On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind + // handler data (aka LSDA) uses GCC-compatible encoding. + #[lang = "eh_personality"] + #[allow(nonstandard_style)] + unsafe extern "C" fn rust_eh_personality( + exceptionRecord: *mut uw::EXCEPTION_RECORD, + establisherFrame: uw::LPVOID, + contextRecord: *mut uw::CONTEXT, + dispatcherContext: *mut uw::DISPATCHER_CONTEXT, + ) -> uw::EXCEPTION_DISPOSITION { + uw::_GCC_specific_handler( + exceptionRecord, + establisherFrame, + contextRecord, + dispatcherContext, + rust_eh_personality_impl, + ) + } + } else { + // The personality routine for most of our targets. + #[lang = "eh_personality"] + unsafe extern "C" fn rust_eh_personality( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + ) -> uw::_Unwind_Reason_Code { + rust_eh_personality_impl( + version, + actions, + exception_class, + exception_object, + context, + ) + } + } + } + } +} + +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result { + let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; + let mut ip_before_instr: c_int = 0; + let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); + let eh_context = EHContext { + // The return address points 1 byte past the call instruction, + // which could be in the next IP range in LSDA range table. + // + // `ip = -1` has special meaning, so use wrapping sub to allow for that + ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) }, + func_start: uw::_Unwind_GetRegionStart(context), + get_text_start: &|| uw::_Unwind_GetTextRelBase(context), + get_data_start: &|| uw::_Unwind_GetDataRelBase(context), + }; + eh::find_eh_action(lsda, &eh_context) +} diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index b8e546164..242f44ade 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -801,11 +801,53 @@ mod prim_array {} /// assert_eq!(2 * pointer_size, std::mem::size_of::>()); /// assert_eq!(2 * pointer_size, std::mem::size_of::>()); /// ``` +/// +/// ## Trait Implementations +/// +/// Some traits are implemented for slices if the element type implements +/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`]. +/// +/// ## Iteration +/// +/// The slices implement `IntoIterator`. The iterator yields references to the +/// slice elements. +/// +/// ``` +/// let numbers: &[i32] = &[0, 1, 2]; +/// for n in numbers { +/// println!("{n} is a number!"); +/// } +/// ``` +/// +/// The mutable slice yields mutable references to the elements: +/// +/// ``` +/// let mut scores: &mut [i32] = &mut [7, 8, 9]; +/// for score in scores { +/// *score += 1; +/// } +/// ``` +/// +/// This iterator yields mutable references to the slice's elements, so while +/// the element type of the slice is `i32`, the element type of the iterator is +/// `&mut i32`. +/// +/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default +/// iterators. +/// * Further methods that return iterators are [`.split`], [`.splitn`], +/// [`.chunks`], [`.windows`] and more. +/// +/// [`Hash`]: core::hash::Hash +/// [`.iter`]: slice::iter +/// [`.iter_mut`]: slice::iter_mut +/// [`.split`]: slice::split +/// [`.splitn`]: slice::splitn +/// [`.chunks`]: slice::chunks +/// [`.windows`]: slice::windows #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice {} #[doc(primitive = "str")] -// /// String slices. /// /// *[See also the `std::str` module](crate::str).* @@ -816,19 +858,22 @@ mod prim_slice {} /// /// String slices are always valid UTF-8. /// -/// # Examples +/// # Basic Usage /// /// String literals are string slices: /// /// ``` -/// let hello = "Hello, world!"; -/// -/// // with an explicit type annotation -/// let hello: &'static str = "Hello, world!"; +/// let hello_world = "Hello, World!"; /// ``` /// -/// They are `'static` because they're stored directly in the final binary, and -/// so will be valid for the `'static` duration. +/// Here we have declared a string slice initialized with a string literal. +/// String literals have a static lifetime, which means the string `hello_world` +/// is guaranteed to be valid for the duration of the entire program. +/// We can explicitly specify `hello_world`'s lifetime as well: +/// +/// ``` +/// let hello_world: &'static str = "Hello, world!"; +/// ``` /// /// # Representation /// @@ -996,7 +1041,7 @@ impl (T,) {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl Clone for (T,) { fn clone(&self) -> Self { @@ -1007,7 +1052,7 @@ impl Clone for (T,) { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl Copy for (T,) { // empty @@ -1178,7 +1223,7 @@ mod prim_usize {} #[doc(alias = "&")] #[doc(alias = "&mut")] // -/// References, both shared and mutable. +/// References, `&T` and `&mut T`. /// /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` /// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or @@ -1484,13 +1529,12 @@ mod prim_fn {} // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls #[doc(hidden)] -#[cfg(not(bootstrap))] impl fn(T) -> Ret {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl Clone for fn(T) -> Ret { fn clone(&self) -> Self { @@ -1501,7 +1545,7 @@ impl Clone for fn(T) -> Ret { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl Copy for fn(T) -> Ret { // empty diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d6cba7e75..d91d4fa64 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -169,15 +169,15 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; pub struct Child { pub(crate) handle: imp::Process, - /// The handle for writing to the child's standard input (stdin), if it has - /// been captured. To avoid partially moving - /// the `child` and thus blocking yourself from calling - /// functions on `child` while using `stdin`, - /// you might find it helpful: + /// The handle for writing to the child's standard input (stdin), if it + /// has been captured. You might find it helpful to do /// /// ```compile_fail,E0425 /// let stdin = child.stdin.take().unwrap(); /// ``` + /// + /// to avoid partially moving the `child` and thus blocking yourself from calling + /// functions on `child` while using `stdin`. #[stable(feature = "process", since = "1.0.0")] pub stdin: Option, diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 663537a05..98f6cc7aa 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -72,10 +72,29 @@ macro_rules! rtunwrap { // Runs before `main`. // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. +// +// # The `sigpipe` parameter +// +// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to +// `SIG_IGN`. Applications have good reasons to want a different behavior +// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that +// can be used to select how `SIGPIPE` shall be setup (if changed at all) before +// `fn main()` is called. See +// for more info. +// +// The `sigpipe` parameter to this function gets its value via the code that +// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for +// all platforms and not only Unix, is because std is not allowed to have `cfg` +// directives as this high level. See the module docs in +// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` +// has a value, but its value is ignored. +// +// Even though it is an `u8`, it only ever has 3 values. These are documented in +// `compiler/rustc_session/src/config/sigpipe.rs`. #[cfg_attr(test, allow(dead_code))] -unsafe fn init(argc: isize, argv: *const *const u8) { +unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { unsafe { - sys::init(argc, argv); + sys::init(argc, argv, sigpipe); let main_guard = sys::thread::guard::init(); // Next, set up the current Thread with the guard information we just @@ -107,6 +126,7 @@ fn lang_start_internal( main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), argc: isize, argv: *const *const u8, + sigpipe: u8, ) -> Result { use crate::{mem, panic}; let rt_abort = move |e| { @@ -124,7 +144,7 @@ fn lang_start_internal( // prevent libstd from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?; + panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?; let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) .map_err(move |e| { mem::forget(e); @@ -140,11 +160,16 @@ fn lang_start( main: fn() -> T, argc: isize, argv: *const *const u8, + #[cfg(not(bootstrap))] sigpipe: u8, ) -> isize { let Ok(v) = lang_start_internal( &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), argc, argv, + #[cfg(bootstrap)] + 2, // Temporary inlining of sigpipe::DEFAULT until bootstrap stops being special + #[cfg(not(bootstrap))] + sigpipe, ); v } diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs index 9f4f31ed0..34b2a9a98 100644 --- a/library/std/src/sync/mpsc/mpsc_queue/tests.rs +++ b/library/std/src/sync/mpsc/mpsc_queue/tests.rs @@ -13,7 +13,7 @@ fn test_full() { #[test] fn test() { let nthreads = 8; - let nmsgs = 1000; + let nmsgs = if cfg!(miri) { 100 } else { 1000 }; let q = Queue::new(); match q.pop() { Empty => {} diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs index 467ef3dbd..eb6d5c2cf 100644 --- a/library/std/src/sync/mpsc/spsc_queue/tests.rs +++ b/library/std/src/sync/mpsc/spsc_queue/tests.rs @@ -77,12 +77,13 @@ fn stress() { } unsafe fn stress_bound(bound: usize) { + let count = if cfg!(miri) { 1000 } else { 100000 }; let q = Arc::new(Queue::with_additions(bound, (), ())); let (tx, rx) = channel(); let q2 = q.clone(); let _t = thread::spawn(move || { - for _ in 0..100000 { + for _ in 0..count { loop { match q2.pop() { Some(1) => break, @@ -93,7 +94,7 @@ fn stress() { } tx.send(()).unwrap(); }); - for _ in 0..100000 { + for _ in 0..count { q.push(1); } rx.recv().unwrap(); diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index e58649bab..63c794369 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -113,23 +113,25 @@ fn chan_gone_concurrent() { #[test] fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = sync_channel::(0); thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..count { assert_eq!(rx.recv().unwrap(), 1); } } #[test] fn stress_recv_timeout_two_threads() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = sync_channel::(0); thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); @@ -146,12 +148,12 @@ fn stress_recv_timeout_two_threads() { } } - assert_eq!(recv_count, 10000); + assert_eq!(recv_count, count); } #[test] fn stress_recv_timeout_shared() { - const AMT: u32 = 1000; + const AMT: u32 = if cfg!(miri) { 100 } else { 1000 }; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); @@ -191,7 +193,7 @@ fn stress_recv_timeout_shared() { #[test] fn stress_shared() { - const AMT: u32 = 1000; + const AMT: u32 = if cfg!(miri) { 100 } else { 1000 }; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); @@ -438,12 +440,13 @@ fn stream_send_recv_stress() { #[test] fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { + let (tx, rx) = sync_channel(count); + for _ in 0..count { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..count { rx.recv().unwrap(); } } diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs index 4deb3e596..f6d0796f6 100644 --- a/library/std/src/sync/mpsc/tests.rs +++ b/library/std/src/sync/mpsc/tests.rs @@ -120,13 +120,14 @@ fn chan_gone_concurrent() { #[test] fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = channel::(); let t = thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..count { assert_eq!(rx.recv().unwrap(), 1); } t.join().ok().expect("thread panicked"); @@ -134,7 +135,7 @@ fn stress() { #[test] fn stress_shared() { - const AMT: u32 = 10000; + const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; const NTHREADS: u32 = 8; let (tx, rx) = channel::(); @@ -504,12 +505,13 @@ fn very_long_recv_timeout_wont_panic() { #[test] fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); - for _ in 0..10000 { + for _ in 0..count { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..count { rx.recv().unwrap(); } } diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index e0d13cd64..de851c8fb 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -192,6 +192,7 @@ unsafe impl Sync for Mutex {} and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")] pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, poison: poison::Guard, diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 813516040..37413ec62 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -3,7 +3,6 @@ use crate::fmt; use crate::marker::PhantomData; use crate::mem::MaybeUninit; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::Once; /// A synchronization primitive which can be written to only once. @@ -223,60 +222,6 @@ impl OnceLock { Ok(unsafe { self.get_unchecked() }) } - /// Internal-only API that gets the contents of the cell, initializing it - /// in two steps with `f` and `g` if the cell was empty. - /// - /// `f` is called to construct the value, which is then moved into the cell - /// and given as a (pinned) mutable reference to `g` to finish - /// initialization. - /// - /// This allows `g` to inspect an manipulate the value after it has been - /// moved into its final place in the cell, but before the cell is - /// considered initialized. - /// - /// # Panics - /// - /// If `f` or `g` panics, the panic is propagated to the caller, and the - /// cell remains uninitialized. - /// - /// With the current implementation, if `g` panics, the value from `f` will - /// not be dropped. This should probably be fixed if this is ever used for - /// a type where this matters. - /// - /// It is an error to reentrantly initialize the cell from `f`. The exact - /// outcome is unspecified. Current implementation deadlocks, but this may - /// be changed to a panic in the future. - pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> - where - F: FnOnce() -> T, - G: FnOnce(Pin<&mut T>), - { - if let Some(value) = self.get_ref().get() { - // SAFETY: The inner value was already initialized, and will not be - // moved anymore. - return unsafe { Pin::new_unchecked(value) }; - } - - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|_| { - let value = f(); - // SAFETY: We use the Once (self.once) to guarantee unique access - // to the UnsafeCell (slot). - let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; - // SAFETY: The value has been written to its final place in - // self.value. We do not to move it anymore, which we promise here - // with a Pin<&mut T>. - g(unsafe { Pin::new_unchecked(value) }); - }); - - // SAFETY: The inner value has been initialized, and will not be moved - // anymore. - unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } - } - /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 6e4a2cfc8..9ab781561 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -101,6 +101,7 @@ unsafe impl Sync for RwLock {} and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a // `Ref` argument doesn't hold immutability for its whole scope, only until it drops. @@ -130,6 +131,7 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} and cause Future's to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, poison: poison::Guard, diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 08255c985..b5b3ad989 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -19,7 +19,7 @@ fn smoke() { #[test] fn frob() { const N: u32 = 10; - const M: usize = 1000; + const M: usize = if cfg!(miri) { 100 } else { 1000 }; let r = Arc::new(RwLock::new(())); diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs deleted file mode 100644 index 22059ca0d..000000000 --- a/library/std/src/sys/hermit/condvar.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::ffi::c_void; -use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use crate::sys::hermit::abi; -use crate::sys::locks::Mutex; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; -use crate::time::Duration; - -// The implementation is inspired by Andrew D. Birrell's paper -// "Implementing Condition Variables with Semaphores" - -pub struct Condvar { - counter: AtomicUsize, - sem1: *const c_void, - sem2: *const c_void, -} - -pub(crate) type MovableCondvar = LazyBox; - -impl LazyInit for Condvar { - fn init() -> Box { - Box::new(Self::new()) - } -} - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub fn new() -> Self { - let mut condvar = - Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }; - unsafe { - let _ = abi::sem_init(&mut condvar.sem1, 0); - let _ = abi::sem_init(&mut condvar.sem2, 0); - } - condvar - } - - pub unsafe fn notify_one(&self) { - if self.counter.load(SeqCst) > 0 { - self.counter.fetch_sub(1, SeqCst); - abi::sem_post(self.sem1); - abi::sem_timedwait(self.sem2, 0); - } - } - - pub unsafe fn notify_all(&self) { - let counter = self.counter.swap(0, SeqCst); - for _ in 0..counter { - abi::sem_post(self.sem1); - } - for _ in 0..counter { - abi::sem_timedwait(self.sem2, 0); - } - } - - pub unsafe fn wait(&self, mutex: &Mutex) { - self.counter.fetch_add(1, SeqCst); - mutex.unlock(); - abi::sem_timedwait(self.sem1, 0); - abi::sem_post(self.sem2); - mutex.lock(); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.counter.fetch_add(1, SeqCst); - mutex.unlock(); - let millis = dur.as_millis().min(u32::MAX as u128) as u32; - - let res = if millis > 0 { - abi::sem_timedwait(self.sem1, millis) - } else { - abi::sem_trywait(self.sem1) - }; - - abi::sem_post(self.sem2); - mutex.lock(); - res == 0 - } -} - -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { - let _ = abi::sem_destroy(self.sem1); - let _ = abi::sem_destroy(self.sem2); - } - } -} diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index fa9a7fb19..f921839cf 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString}; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; -use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom}; +use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::os::unix::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys::cvt; @@ -41,6 +41,9 @@ pub struct OpenOptions { mode: i32, } +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + pub struct FilePermissions(!); pub struct FileType(!); @@ -110,6 +113,11 @@ impl fmt::Debug for FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + impl FileType { pub fn is_dir(&self) -> bool { self.0 @@ -312,8 +320,8 @@ impl File { false } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - crate::io::default_read_buf(|buf| self.read(buf), buf) + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } pub fn write(&self, buf: &[u8]) -> io::Result { @@ -344,6 +352,10 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + Err(Error::from_raw_os_error(22)) + } } impl DirBuilder { diff --git a/library/std/src/sys/hermit/futex.rs b/library/std/src/sys/hermit/futex.rs new file mode 100644 index 000000000..b64c174b0 --- /dev/null +++ b/library/std/src/sys/hermit/futex.rs @@ -0,0 +1,39 @@ +use super::abi; +use crate::ptr::null; +use crate::sync::atomic::AtomicU32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool { + // Calculate the timeout as a relative timespec. + // + // Overflows are rounded up to an infinite timeout (None). + let timespec = timeout.and_then(|dur| { + Some(abi::timespec { + tv_sec: dur.as_secs().try_into().ok()?, + tv_nsec: dur.subsec_nanos().into(), + }) + }); + + let r = unsafe { + abi::futex_wait( + futex.as_mut_ptr(), + expected, + timespec.as_ref().map_or(null(), |t| t as *const abi::timespec), + abi::FUTEX_RELATIVE_TIMEOUT, + ) + }; + + r != -abi::errno::ETIMEDOUT +} + +#[inline] +pub fn futex_wake(futex: &AtomicU32) -> bool { + unsafe { abi::futex_wake(futex.as_mut_ptr(), 1) > 0 } +} + +#[inline] +pub fn futex_wake_all(futex: &AtomicU32) { + unsafe { + abi::futex_wake(futex.as_mut_ptr(), i32::MAX); + } +} diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 60b7a973c..827d82900 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -25,6 +25,7 @@ pub mod cmath; pub mod env; pub mod fd; pub mod fs; +pub mod futex; #[path = "../unsupported/io.rs"] pub mod io; pub mod memchr; @@ -45,14 +46,14 @@ pub mod thread_local_dtor; pub mod thread_local_key; pub mod time; -mod condvar; -mod mutex; -mod rwlock; - +#[path = "../unix/locks"] pub mod locks { - pub use super::condvar::*; - pub use super::mutex::*; - pub use super::rwlock::*; + mod futex_condvar; + mod futex_mutex; + mod futex_rwlock; + pub(crate) use futex_condvar::MovableCondvar; + pub(crate) use futex_mutex::{MovableMutex, Mutex}; + pub(crate) use futex_rwlock::{MovableRwLock, RwLock}; } use crate::io::ErrorKind; @@ -98,7 +99,7 @@ pub extern "C" fn __rust_abort() { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(argc: isize, argv: *const *const u8) { +pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { let _ = net::init(); args::init(argc, argv); } diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs deleted file mode 100644 index eb15a04ff..000000000 --- a/library/std/src/sys/hermit/mutex.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::collections::VecDeque; -use crate::hint; -use crate::ops::{Deref, DerefMut, Drop}; -use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sys::hermit::abi; - -/// This type provides a lock based on busy waiting to realize mutual exclusion -/// -/// # Description -/// -/// This structure behaves a lot like a common mutex. There are some differences: -/// -/// - By using busy waiting, it can be used outside the runtime. -/// - It is a so called ticket lock and is completely fair. -#[cfg_attr(target_arch = "x86_64", repr(align(128)))] -#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))] -struct Spinlock { - queue: AtomicUsize, - dequeue: AtomicUsize, - data: UnsafeCell, -} - -unsafe impl Sync for Spinlock {} -unsafe impl Send for Spinlock {} - -/// A guard to which the protected data can be accessed -/// -/// When the guard falls out of scope it will release the lock. -struct SpinlockGuard<'a, T: ?Sized + 'a> { - dequeue: &'a AtomicUsize, - data: &'a mut T, -} - -impl Spinlock { - pub const fn new(user_data: T) -> Spinlock { - Spinlock { - queue: AtomicUsize::new(0), - dequeue: AtomicUsize::new(1), - data: UnsafeCell::new(user_data), - } - } - - #[inline] - fn obtain_lock(&self) { - let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1; - let mut counter: u16 = 0; - while self.dequeue.load(Ordering::SeqCst) != ticket { - counter += 1; - if counter < 100 { - hint::spin_loop(); - } else { - counter = 0; - unsafe { - abi::yield_now(); - } - } - } - } - - #[inline] - pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> { - self.obtain_lock(); - SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() } - } -} - -impl Default for Spinlock { - fn default() -> Spinlock { - Spinlock::new(Default::default()) - } -} - -impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> { - type Target = T; - fn deref(&self) -> &T { - &*self.data - } -} - -impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> { - fn deref_mut(&mut self) -> &mut T { - &mut *self.data - } -} - -impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> { - /// The dropping of the SpinlockGuard will release the lock it was created from. - fn drop(&mut self) { - self.dequeue.fetch_add(1, Ordering::SeqCst); - } -} - -/// Realize a priority queue for tasks -struct PriorityQueue { - queues: [Option>; abi::NO_PRIORITIES], - prio_bitmap: u64, -} - -impl PriorityQueue { - pub const fn new() -> PriorityQueue { - PriorityQueue { - queues: [ - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, - ], - prio_bitmap: 0, - } - } - - /// Add a task id by its priority to the queue - pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) { - let i: usize = prio.into().into(); - self.prio_bitmap |= (1 << i) as u64; - if let Some(queue) = &mut self.queues[i] { - queue.push_back(id); - } else { - let mut queue = VecDeque::new(); - queue.push_back(id); - self.queues[i] = Some(queue); - } - } - - fn pop_from_queue(&mut self, queue_index: usize) -> Option { - if let Some(queue) = &mut self.queues[queue_index] { - let id = queue.pop_front(); - - if queue.is_empty() { - self.prio_bitmap &= !(1 << queue_index as u64); - } - - id - } else { - None - } - } - - /// Pop the task handle with the highest priority from the queue - pub fn pop(&mut self) -> Option { - for i in 0..abi::NO_PRIORITIES { - if self.prio_bitmap & (1 << i) != 0 { - return self.pop_from_queue(i); - } - } - - None - } -} - -struct MutexInner { - locked: bool, - blocked_task: PriorityQueue, -} - -impl MutexInner { - pub const fn new() -> MutexInner { - MutexInner { locked: false, blocked_task: PriorityQueue::new() } - } -} - -pub struct Mutex { - inner: Spinlock, -} - -pub type MovableMutex = Mutex; - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { inner: Spinlock::new(MutexInner::new()) } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn lock(&self) { - loop { - let mut guard = self.inner.lock(); - if guard.locked == false { - guard.locked = true; - return; - } else { - let prio = abi::get_priority(); - let id = abi::getpid(); - - guard.blocked_task.push(prio, id); - abi::block_current_task(); - drop(guard); - abi::yield_now(); - } - } - } - - #[inline] - pub unsafe fn unlock(&self) { - let mut guard = self.inner.lock(); - guard.locked = false; - if let Some(tid) = guard.blocked_task.pop() { - abi::wakeup_task(tid); - } - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - let mut guard = self.inner.lock(); - if guard.locked == false { - guard.locked = true; - } - guard.locked - } -} diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 745476171..8a13879d8 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -487,6 +487,4 @@ pub mod netc { #[derive(Copy, Clone)] pub struct sockaddr {} - - pub type socklen_t = usize; } diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs deleted file mode 100644 index 9701bab1f..000000000 --- a/library/std/src/sys/hermit/rwlock.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::locks::{MovableCondvar, Mutex}; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; - -pub struct RwLock { - lock: Mutex, - cond: MovableCondvar, - state: UnsafeCell, -} - -pub type MovableRwLock = RwLock; - -enum State { - Unlocked, - Reading(usize), - Writing, -} - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -// This rwlock implementation is a relatively simple implementation which has a -// condition variable for readers/writers as well as a mutex protecting the -// internal state of the lock. A current downside of the implementation is that -// unlocking the lock will notify *all* waiters rather than just readers or just -// writers. This can cause lots of "thundering stampede" problems. While -// hopefully correct this implementation is very likely to want to be changed in -// the future. - -impl RwLock { - pub const fn new() -> RwLock { - RwLock { - lock: Mutex::new(), - cond: MovableCondvar::new(), - state: UnsafeCell::new(State::Unlocked), - } - } - - #[inline] - pub unsafe fn read(&self) { - self.lock.lock(); - while !(*self.state.get()).inc_readers() { - self.cond.wait(&self.lock); - } - self.lock.unlock(); - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - self.lock.lock(); - let ok = (*self.state.get()).inc_readers(); - self.lock.unlock(); - return ok; - } - - #[inline] - pub unsafe fn write(&self) { - self.lock.lock(); - while !(*self.state.get()).inc_writers() { - self.cond.wait(&self.lock); - } - self.lock.unlock(); - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - self.lock.lock(); - let ok = (*self.state.get()).inc_writers(); - self.lock.unlock(); - return ok; - } - - #[inline] - pub unsafe fn read_unlock(&self) { - self.lock.lock(); - let notify = (*self.state.get()).dec_readers(); - self.lock.unlock(); - if notify { - // FIXME: should only wake up one of these some of the time - self.cond.notify_all(); - } - } - - #[inline] - pub unsafe fn write_unlock(&self) { - self.lock.lock(); - (*self.state.get()).dec_writers(); - self.lock.unlock(); - // FIXME: should only wake up one of these some of the time - self.cond.notify_all(); - } -} - -impl State { - fn inc_readers(&mut self) -> bool { - match *self { - State::Unlocked => { - *self = State::Reading(1); - true - } - State::Reading(ref mut cnt) => { - *cnt += 1; - true - } - State::Writing => false, - } - } - - fn inc_writers(&mut self) -> bool { - match *self { - State::Unlocked => { - *self = State::Writing; - true - } - State::Reading(_) | State::Writing => false, - } - } - - fn dec_readers(&mut self) -> bool { - let zero = match *self { - State::Reading(ref mut cnt) => { - *cnt -= 1; - *cnt == 0 - } - State::Unlocked | State::Writing => invalid(), - }; - if zero { - *self = State::Unlocked; - } - zero - } - - fn dec_writers(&mut self) { - match *self { - State::Writing => {} - State::Unlocked | State::Reading(_) => invalid(), - } - *self = State::Unlocked; - } -} - -fn invalid() -> ! { - panic!("inconsistent rwlock"); -} diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 715e94c3b..085662e6d 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -31,12 +31,6 @@ impl Mutex { Mutex { mtx: SpinIdOnceCell::new() } } - pub unsafe fn init(&mut self) { - // Initialize `self.mtx` eagerly - let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); - unsafe { self.mtx.set_unchecked((id, ())) }; - } - /// Get the inner mutex's ID, which is lazily created. fn raw(&self) -> abi::ID { match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { diff --git a/library/std/src/sys/sgx/abi/thread.rs b/library/std/src/sys/sgx/abi/thread.rs index ef55b821a..2b23e368c 100644 --- a/library/std/src/sys/sgx/abi/thread.rs +++ b/library/std/src/sys/sgx/abi/thread.rs @@ -7,7 +7,11 @@ use fortanix_sgx_abi::Tcs; #[unstable(feature = "sgx_platform", issue = "56975")] pub fn current() -> Tcs { extern "C" { - fn get_tcs_addr() -> Tcs; + fn get_tcs_addr() -> *mut u8; + } + let addr = unsafe { get_tcs_addr() }; + match Tcs::new(addr) { + Some(tcs) => tcs, + None => rtabort!("TCS must not be placed at address zero (this is a linker error)"), } - unsafe { get_tcs_addr() } } diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index ea24fedd0..5409bd177 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -56,6 +56,8 @@ unsafe impl UserSafeSized for Usercall {} #[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for Return {} #[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeSized for Cancel {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for [T; 2] {} /// A type that can be represented in memory as one or more `UserSafeSized`s. @@ -115,7 +117,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) }; + let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); @@ -305,6 +307,34 @@ where } } +// Split a memory region ptr..ptr + len into three parts: +// +--------+ +// | small0 | Chunk smaller than 8 bytes +// +--------+ +// | big | Chunk 8-byte aligned, and size a multiple of 8 bytes +// +--------+ +// | small1 | Chunk smaller than 8 bytes +// +--------+ +fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (usize, usize, usize) { + let small0_size = if ptr as usize % 8 == 0 { 0 } else { 8 - ptr as usize % 8 }; + let small1_size = (len - small0_size as usize) % 8; + let big_size = len - small0_size as usize - small1_size as usize; + + (small0_size, big_size, small1_size) +} + +unsafe fn copy_quadwords(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + asm!( + "rep movsq (%rsi), (%rdi)", + inout("rcx") len / 8 => _, + inout("rdi") dst => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); + } +} + /// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` /// /// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either: @@ -343,17 +373,6 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) } } - unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) { - unsafe { - asm!( - "rep movsq (%rsi), (%rdi)", - inout("rcx") len / 8 => _, - inout("rdi") dst => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); - } - } assert!(!src.is_null()); assert!(!dst.is_null()); assert!(is_enclave_range(src, len)); @@ -367,10 +386,10 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) unsafe { copy_bytewise_to_userspace(src, dst, len); } - } else if len % 8 == 0 && dst as usize % 8 == 0 { + } else if len % 8 == 0 && dst.is_aligned_to(8) { // Copying 8-byte aligned quadwords: copy quad word per quad word unsafe { - copy_aligned_quadwords_to_userspace(src, dst, len); + copy_quadwords(src, dst, len); } } else { // Split copies into three parts: @@ -381,20 +400,16 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) // +--------+ // | small1 | Chunk smaller than 8 bytes // +--------+ + let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len); unsafe { // Copy small0 - let small0_size = (8 - dst as usize % 8) as u8; - let small0_src = src; - let small0_dst = dst; - copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _); + copy_bytewise_to_userspace(src, dst, small0_size as _); // Copy big - let small1_size = ((len - small0_size as usize) % 8) as u8; - let big_size = len - small0_size as usize - small1_size as usize; let big_src = src.offset(small0_size as _); let big_dst = dst.offset(small0_size as _); - copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size); + copy_quadwords(big_src as _, big_dst, big_size); // Copy small1 let small1_src = src.offset(big_size as isize + small0_size as isize); @@ -404,6 +419,106 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) } } +/// Copies `len` bytes of data from userspace pointer `src` to enclave pointer `dst` +/// +/// This function mitigates AEPIC leak vulnerabilities by ensuring all reads from untrusted memory are 8-byte aligned +/// +/// # Panics +/// This function panics if: +/// +/// * The `src` pointer is null +/// * The `dst` pointer is null +/// * The `src` memory range is not in user memory +/// * The `dst` memory range is not in enclave memory +/// +/// # References +/// - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00657.html +/// - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/stale-data-read-from-xapic.html +pub(crate) unsafe fn copy_from_userspace(src: *const u8, dst: *mut u8, len: usize) { + // Copies memory region `src..src + len` to the enclave at `dst`. The source memory region + // is: + // - strictly less than 8 bytes in size and may be + // - located at a misaligned memory location + fn copy_misaligned_chunk_to_enclave(src: *const u8, dst: *mut u8, len: usize) { + let mut tmp_buff = [0u8; 16]; + + unsafe { + // Compute an aligned memory region to read from + // +--------+ <-- aligned_src + aligned_len (8B-aligned) + // | pad1 | + // +--------+ <-- src + len (misaligned) + // | | + // | | + // | | + // +--------+ <-- src (misaligned) + // | pad0 | + // +--------+ <-- aligned_src (8B-aligned) + let pad0_size = src as usize % 8; + let aligned_src = src.sub(pad0_size); + + let pad1_size = 8 - (src.add(len) as usize % 8); + let aligned_len = pad0_size + len + pad1_size; + + debug_assert!(len < 8); + debug_assert_eq!(aligned_src as usize % 8, 0); + debug_assert_eq!(aligned_len % 8, 0); + debug_assert!(aligned_len <= 16); + + // Copy the aligned buffer to a temporary buffer + // Note: copying from a slightly different memory location is a bit odd. In this case it + // can't lead to page faults or inadvertent copying from the enclave as we only ensured + // that the `src` pointer is aligned at an 8 byte boundary. As pages are 4096 bytes + // aligned, `aligned_src` must be on the same page as `src`. A similar argument can be made + // for `src + len` + copy_quadwords(aligned_src as _, tmp_buff.as_mut_ptr(), aligned_len); + + // Copy the correct parts of the temporary buffer to the destination + ptr::copy(tmp_buff.as_ptr().add(pad0_size), dst, len); + } + } + + assert!(!src.is_null()); + assert!(!dst.is_null()); + assert!(is_user_range(src, len)); + assert!(is_enclave_range(dst, len)); + assert!(!(src as usize).overflowing_add(len + 8).1); + assert!(!(dst as usize).overflowing_add(len + 8).1); + + if len < 8 { + copy_misaligned_chunk_to_enclave(src, dst, len); + } else if len % 8 == 0 && src as usize % 8 == 0 { + // Copying 8-byte aligned quadwords: copy quad word per quad word + unsafe { + copy_quadwords(src, dst, len); + } + } else { + // Split copies into three parts: + // +--------+ + // | small0 | Chunk smaller than 8 bytes + // +--------+ + // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes + // +--------+ + // | small1 | Chunk smaller than 8 bytes + // +--------+ + let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len); + + unsafe { + // Copy small0 + copy_misaligned_chunk_to_enclave(src, dst, small0_size); + + // Copy big + let big_src = src.add(small0_size); + let big_dst = dst.add(small0_size); + copy_quadwords(big_src, big_dst, big_size); + + // Copy small1 + let small1_src = src.add(big_size + small0_size); + let small1_dst = dst.add(big_size + small0_size); + copy_misaligned_chunk_to_enclave(small1_src, small1_dst, small1_size); + } + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl UserRef where @@ -468,7 +583,7 @@ where pub fn copy_to_enclave(&self, dest: &mut T) { unsafe { assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get())); - ptr::copy( + copy_from_userspace( self.0.get() as *const T as *const u8, dest as *mut T as *mut u8, mem::size_of_val(dest), @@ -494,7 +609,11 @@ where { /// Copies the value from user memory into enclave memory. pub fn to_enclave(&self) -> T { - unsafe { ptr::read(self.0.get()) } + unsafe { + let mut data: T = mem::MaybeUninit::uninit().assume_init(); + copy_from_userspace(self.0.get() as _, &mut data as *mut T as _, mem::size_of::()); + data + } } } diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 79d1db5e1..e19e84326 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -292,12 +292,17 @@ fn check_os_error(err: Result) -> i32 { } } -trait FromSgxResult { +/// Translate the raw result of an SGX usercall. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait FromSgxResult { + /// Return type type Return; + /// Translate the raw result of an SGX usercall. fn from_sgx_result(self) -> IoResult; } +#[unstable(feature = "sgx_platform", issue = "56975")] impl FromSgxResult for (Result, T) { type Return = T; @@ -310,6 +315,7 @@ impl FromSgxResult for (Result, T) { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl FromSgxResult for Result { type Return = (); diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs index 4267b96cc..10c1456d4 100644 --- a/library/std/src/sys/sgx/abi/usercalls/raw.rs +++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs @@ -37,14 +37,23 @@ pub unsafe fn do_usercall( (a, b) } -type Register = u64; +/// A value passed or returned in a CPU register. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub type Register = u64; -trait RegisterArgument { +/// Translate a type from/to Register to be used as an argument. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait RegisterArgument { + /// Translate a Register to Self. fn from_register(_: Register) -> Self; + /// Translate self to a Register. fn into_register(self) -> Register; } -trait ReturnValue { +/// Translate a pair of Registers to the raw usercall return value. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait ReturnValue { + /// Translate a pair of Registers to the raw usercall return value. fn from_registers(call: &'static str, regs: (Register, Register)) -> Self; } @@ -68,6 +77,7 @@ macro_rules! define_usercalls { macro_rules! define_ra { (< $i:ident > $t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl<$i> RegisterArgument for $t { fn from_register(a: Register) -> Self { a as _ @@ -78,6 +88,7 @@ macro_rules! define_ra { } }; ($i:ty as $t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for $t { fn from_register(a: Register) -> Self { a as $i as _ @@ -88,6 +99,7 @@ macro_rules! define_ra { } }; ($t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for $t { fn from_register(a: Register) -> Self { a as _ @@ -112,6 +124,7 @@ define_ra!(usize as isize); define_ra!( *const T); define_ra!( *mut T); +#[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for bool { fn from_register(a: Register) -> bool { if a != 0 { true } else { false } @@ -121,6 +134,7 @@ impl RegisterArgument for bool { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for Option> { fn from_register(a: Register) -> Option> { NonNull::new(a as _) @@ -130,12 +144,14 @@ impl RegisterArgument for Option> { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for ! { fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { rtabort!("Usercall {call}: did not expect to be re-entered"); } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for () { fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { rtassert!(usercall_retval.0 == 0); @@ -144,6 +160,7 @@ impl ReturnValue for () { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for T { fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { rtassert!(usercall_retval.1 == 0); @@ -151,6 +168,7 @@ impl ReturnValue for T { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for (T, U) { fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self { (T::from_register(regs.0), U::from_register(regs.1)) diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs index cbf7d7d54..58b8eb215 100644 --- a/library/std/src/sys/sgx/abi/usercalls/tests.rs +++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs @@ -1,8 +1,8 @@ -use super::alloc::copy_to_userspace; use super::alloc::User; +use super::alloc::{copy_from_userspace, copy_to_userspace}; #[test] -fn test_copy_function() { +fn test_copy_to_userspace_function() { let mut src = [0u8; 100]; let mut dst = User::<[u8]>::uninitialized(100); @@ -17,12 +17,38 @@ fn test_copy_function() { dst.copy_from_enclave(&[0u8; 100]); // Copy src[0..size] to dst + offset - unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().offset(offset), size) }; + unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().add(offset), size) }; // Verify copy for byte in 0..size { unsafe { - assert_eq!(*dst.as_ptr().offset(offset + byte as isize), src[byte as usize]); + assert_eq!(*dst.as_ptr().add(offset + byte), src[byte as usize]); + } + } + } + } +} + +#[test] +fn test_copy_from_userspace_function() { + let mut dst = [0u8; 100]; + let mut src = User::<[u8]>::uninitialized(100); + + src.copy_from_enclave(&[0u8; 100]); + + for size in 0..48 { + // For all possible alignment + for offset in 0..8 { + // overwrite complete dst + dst = [0u8; 100]; + + // Copy src[0..size] to dst + offset + unsafe { copy_from_userspace(src.as_ptr().offset(offset), dst.as_mut_ptr(), size) }; + + // Verify copy + for byte in 0..size { + unsafe { + assert_eq!(dst[byte as usize], *src.as_ptr().offset(offset + byte as isize)); } } } diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 696400670..b1d32929e 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -47,7 +47,7 @@ pub mod locks { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(argc: isize, argv: *const *const u8) { +pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { args::init(argc, argv); } diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 513cd77fd..aa747d56b 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -20,9 +20,6 @@ impl Mutex { Mutex { inner: SpinMutex::new(WaitVariable::new(false)) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { let mut guard = self.inner.lock(); diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs index a2cbee4dc..969222253 100644 --- a/library/std/src/sys/solid/fs.rs +++ b/library/std/src/sys/solid/fs.rs @@ -2,7 +2,7 @@ use super::{abi, error}; use crate::{ ffi::{CStr, CString, OsStr, OsString}, fmt, - io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}, + io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}, mem::MaybeUninit, os::raw::{c_int, c_short}, os::solid::ffi::OsStrExt, @@ -77,6 +77,9 @@ pub struct OpenOptions { custom_flags: i32, } +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions(c_short); @@ -126,6 +129,11 @@ impl FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + impl FileType { pub fn is_dir(&self) -> bool { self.is(abi::S_IFDIR) @@ -358,13 +366,13 @@ impl File { } } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { unsafe { - let len = buf.remaining(); + let len = cursor.capacity(); let mut out_num_bytes = MaybeUninit::uninit(); error::SolidError::err_if_negative(abi::SOLID_FS_Read( self.fd.raw(), - buf.unfilled_mut().as_mut_ptr() as *mut u8, + cursor.as_mut().as_mut_ptr() as *mut u8, len, out_num_bytes.as_mut_ptr(), )) @@ -376,9 +384,7 @@ impl File { // Safety: `num_bytes_read` bytes were written to the unfilled // portion of the buffer - buf.assume_init(num_bytes_read); - - buf.add_filled(num_bytes_read); + cursor.advance(num_bytes_read); Ok(()) } @@ -452,6 +458,10 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { unsupported() } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + unsupported() + } } impl Drop for File { diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 778a589d1..5867979a2 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -56,7 +56,7 @@ pub mod locks { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 30812dabb..dbaa3c33e 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -131,20 +131,19 @@ impl FileDesc { } } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let ret = cvt(unsafe { libc::read( self.as_raw_fd(), - buf.unfilled_mut().as_mut_ptr() as *mut libc::c_void, - cmp::min(buf.remaining(), READ_LIMIT), + cursor.as_mut().as_mut_ptr() as *mut libc::c_void, + cmp::min(cursor.capacity(), READ_LIMIT), ) })?; // Safety: `ret` bytes were written to the initialized portion of the buffer unsafe { - buf.assume_init(ret as usize); + cursor.advance(ret as usize); } - buf.add_filled(ret as usize); Ok(()) } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index b5cc8038c..cc347e358 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; +use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; @@ -544,11 +544,11 @@ impl Default for FileTimes { fn default() -> Self { // Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return // an error in `set_times`. - // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore + // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. - #[cfg(any(target_os = "redox", target_os = "espidf"))] + #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] let omit = libc::timespec { tv_sec: 0, tv_nsec: 0 }; - #[cfg(not(any(target_os = "redox", target_os = "espidf")))] + #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))] let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }; Self([omit; 2]) } @@ -687,7 +687,11 @@ impl Iterator for ReadDir { impl Drop for Dir { fn drop(&mut self) { let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); + assert!( + r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted, + "unexpected error during closedir: {:?}", + crate::io::Error::last_os_error() + ); } } @@ -825,6 +829,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox" )))] + #[cfg_attr(miri, allow(unused))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } } @@ -836,6 +841,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox" ))] + #[cfg_attr(miri, allow(unused))] fn name_cstr(&self) -> &CStr { &self.name } @@ -1031,8 +1037,8 @@ impl File { self.0.read_at(buf, offset) } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - self.0.read_buf(buf) + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(cursor) } pub fn write(&self, buf: &[u8]) -> io::Result { @@ -1079,9 +1085,9 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { cfg_if::cfg_if! { - if #[cfg(any(target_os = "redox", target_os = "espidf"))] { + if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] { // Redox doesn't appear to support `UTIME_OMIT`. - // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore + // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. drop(times); Err(io::const_io_error!( diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs index ce427599c..117611ce4 100644 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs @@ -85,9 +85,6 @@ impl Mutex { Mutex { futex: AtomicU32::new(UNLOCKED) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { let thread_self = zx_thread_self(); @@ -138,7 +135,7 @@ impl Mutex { } } - // The state has changed or a wakeup occured, try to lock the mutex. + // The state has changed or a wakeup occurred, try to lock the mutex. match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) { Ok(_) => return, Err(updated) => state = updated, diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs index 99ba86e5f..33b13dad4 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex_mutex.rs @@ -19,9 +19,6 @@ impl Mutex { Self { futex: AtomicU32::new(0) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() @@ -53,7 +50,7 @@ impl Mutex { // We avoid an unnecessary write if it as already set to 2, // to be friendlier for the caches. if state != 2 && self.futex.swap(2, Acquire) == 0 { - // We changed it from 0 to 2, so we just succesfully locked it. + // We changed it from 0 to 2, so we just successfully locked it. return; } diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index b3bbbf743..0cc92244e 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -54,7 +54,7 @@ fn is_read_lockable(state: u32) -> bool { // We don't allow read-locking if there's readers waiting, even if the lock is unlocked // and there's no writers waiting. The only situation when this happens is after unlocking, // at which point the unlocking thread might be waking up writers, which have priority over readers. - // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary. + // The unlocking thread will clear the readers waiting bit and wake up readers, if necessary. state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state) } diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index abf27e7db..4741c0c67 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -172,7 +172,7 @@ impl Condvar { let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; let stable_now = Instant::now(); let r = libc::gettimeofday(&mut sys_now, ptr::null_mut()); - debug_assert_eq!(r, 0); + assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error()); let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long; let extra = (nsec / 1_000_000_000) as libc::time_t; diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 98afee69b..5964935dd 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -52,7 +52,7 @@ impl Mutex { Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { // Issue #33770 // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 3d0d91460..c84e292ea 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -44,12 +44,13 @@ pub mod thread_parker; pub mod time; #[cfg(target_os = "espidf")] -pub fn init(argc: isize, argv: *const *const u8) {} +pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(argc: isize, argv: *const *const u8) { +// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. +pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file // resources opened later, we reopen standards streams when they are closed. @@ -61,8 +62,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { // want! // // Hence, we set SIGPIPE to ignore when the program starts up in order - // to prevent this problem. - reset_sigpipe(); + // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to + // alter this behavior. + reset_sigpipe(sigpipe); stack_overflow::init(); args::init(argc, argv); @@ -151,9 +153,31 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } } - unsafe fn reset_sigpipe() { + unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) { #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))] - rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); + { + // We don't want to add this as a public type to libstd, nor do we + // want to `include!` a file from the compiler (which would break + // Miri and xargo for example), so we choose to duplicate these + // constants from `compiler/rustc_session/src/config/sigpipe.rs`. + // See the other file for docs. NOTE: Make sure to keep them in + // sync! + mod sigpipe { + pub const INHERIT: u8 = 1; + pub const SIG_IGN: u8 = 2; + pub const SIG_DFL: u8 = 3; + } + + let handler = match sigpipe { + sigpipe::INHERIT => None, + sigpipe::SIG_IGN => Some(libc::SIG_IGN), + sigpipe::SIG_DFL => Some(libc::SIG_DFL), + _ => unreachable!(), + }; + if let Some(handler) = handler { + rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR); + } + } } } @@ -295,8 +319,10 @@ pub fn abort_internal() -> ! { cfg_if::cfg_if! { if #[cfg(target_os = "android")] { - #[link(name = "dl")] - #[link(name = "log")] + #[link(name = "dl", kind = "static", modifiers = "-bundle", + cfg(target_feature = "crt-static"))] + #[link(name = "dl", cfg(not(target_feature = "crt-static")))] + #[link(name = "log", cfg(not(target_feature = "crt-static")))] extern "C" {} } else if #[cfg(target_os = "freebsd")] { #[link(name = "execinfo")] diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 462a45b01..b84bf8f92 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -392,6 +392,17 @@ impl Socket { Ok(raw != 0) } + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn set_quickack(&self, quickack: bool) -> io::Result<()> { + setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int) + } + + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn quickack(&self) -> io::Result { + let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?; + Ok(raw != 0) + } + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) @@ -427,6 +438,17 @@ impl Socket { self.0.set_nonblocking(nonblocking) } + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + pub fn set_mark(&self, mark: u32) -> io::Result<()> { + #[cfg(target_os = "linux")] + let option = libc::SO_MARK; + #[cfg(target_os = "freebsd")] + let option = libc::SO_USER_COOKIE; + #[cfg(target_os = "openbsd")] + let option = libc::SO_RTABLE; + setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int) + } + pub fn take_error(&self) -> io::Result> { let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index ccbc18224..017e2af29 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -11,7 +11,7 @@ use crate::str; use crate::sync::Arc; use crate::sys_common::{AsInner, IntoInner}; -use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::Utf8Chunks; #[cfg(test)] #[path = "../unix/os_str/tests.rs"] @@ -29,26 +29,32 @@ pub struct Slice { } impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - // Writes out a valid unicode string with the correct escape sequences - - formatter.write_str("\"")?; - for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(&self.inner).chunks() { - for c in valid.chars().flat_map(|c| c.escape_debug()) { - formatter.write_char(c)? - } - - for b in broken { - write!(formatter, "\\x{:02X}", b)?; - } - } - formatter.write_str("\"") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&Utf8Chunks::new(&self.inner).debug(), f) } } impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If we're the empty string then our iterator won't actually yield + // anything, so perform the formatting manually + if self.inner.is_empty() { + return "".fmt(f); + } + + for chunk in Utf8Chunks::new(&self.inner) { + let valid = chunk.valid(); + // If we successfully decoded the whole chunk as a valid string then + // we can return a direct formatting of the string which will also + // respect various formatting flags if possible. + if chunk.invalid().is_empty() { + return valid.fmt(f); + } + + f.write_str(valid)?; + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + Ok(()) } } diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 213277f01..22ba0c923 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -8,3 +8,11 @@ fn slice_debug_output() { assert_eq!(output, expected); } + +#[test] +fn display() { + assert_eq!( + "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", + Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(), + ); +} diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index bca1b65a7..2834ee0ac 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -45,11 +45,31 @@ cfg_if::cfg_if! { } #[allow(dead_code)] pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { - use crate::{slice, mem}; + use crate::{ + mem::{align_of, size_of}, + slice, + }; + use libc::{c_ulong, sigset_t}; + + // The implementations from bionic (android libc) type pun `sigset_t` as an + // array of `c_ulong`. This works, but lets add a smoke check to make sure + // that doesn't change. + const _: () = assert!( + align_of::() == align_of::() + && (size_of::() % size_of::()) == 0 + ); - let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); let bit = (signum - 1) as usize; - raw[bit / 8] |= 1 << (bit % 8); + if set.is_null() || bit >= (8 * size_of::()) { + crate::sys::unix::os::set_errno(libc::EINVAL); + return -1; + } + let raw = slice::from_raw_parts_mut( + set as *mut c_ulong, + size_of::() / size_of::(), + ); + const LONG_BIT: usize = size_of::() * 8; + raw[bit / LONG_BIT] |= 1 << (bit % LONG_BIT); return 0; } } else { @@ -72,6 +92,7 @@ pub struct Command { argv: Argv, env: CommandEnv, + program_kind: ProgramKind, cwd: Option, uid: Option, gid: Option, @@ -128,15 +149,40 @@ pub enum Stdio { Fd(FileDesc), } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ProgramKind { + /// A program that would be looked up on the PATH (e.g. `ls`) + PathLookup, + /// A relative path (e.g. `my-dir/foo`, `../foo`, `./foo`) + Relative, + /// An absolute path. + Absolute, +} + +impl ProgramKind { + fn new(program: &OsStr) -> Self { + if program.bytes().starts_with(b"/") { + Self::Absolute + } else if program.bytes().contains(&b'/') { + // If the program has more than one component in it, it is a relative path. + Self::Relative + } else { + Self::PathLookup + } + } +} + impl Command { #[cfg(not(target_os = "linux"))] pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; + let program_kind = ProgramKind::new(program.as_ref()); let program = os2c(program, &mut saw_nul); Command { argv: Argv(vec![program.as_ptr(), ptr::null()]), args: vec![program.clone()], program, + program_kind, env: Default::default(), cwd: None, uid: None, @@ -154,11 +200,13 @@ impl Command { #[cfg(target_os = "linux")] pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; + let program_kind = ProgramKind::new(program.as_ref()); let program = os2c(program, &mut saw_nul); Command { argv: Argv(vec![program.as_ptr(), ptr::null()]), args: vec![program.clone()], program, + program_kind, env: Default::default(), cwd: None, uid: None, @@ -234,6 +282,11 @@ impl Command { OsStr::from_bytes(self.program.as_bytes()) } + #[allow(dead_code)] + pub fn get_program_kind(&self) -> ProgramKind { + self.program_kind + } + pub fn get_args(&self) -> CommandArgs<'_> { let mut iter = self.args.iter(); iter.next(); diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs index 1956b3692..d176b3401 100644 --- a/library/std/src/sys/unix/process/process_common/tests.rs +++ b/library/std/src/sys/unix/process/process_common/tests.rs @@ -122,3 +122,27 @@ fn test_process_group_no_posix_spawn() { t!(cat.wait()); } } + +#[test] +fn test_program_kind() { + let vectors = &[ + ("foo", ProgramKind::PathLookup), + ("foo.out", ProgramKind::PathLookup), + ("./foo", ProgramKind::Relative), + ("../foo", ProgramKind::Relative), + ("dir/foo", ProgramKind::Relative), + // Note that paths on Unix can't contain / in them, so this is actually the directory "fo\\" + // followed by the file "o". + ("fo\\/o", ProgramKind::Relative), + ("/foo", ProgramKind::Absolute), + ("/dir/../foo", ProgramKind::Absolute), + ]; + + for (program, expected_kind) in vectors { + assert_eq!( + ProgramKind::new(program.as_ref()), + *expected_kind, + "actual != expected program kind for input {program}", + ); + } +} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 75bb92437..26ae62817 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -453,7 +453,9 @@ impl Command { // successfully launch the program, but erroneously return // ENOENT when used with posix_spawn_file_actions_addchdir_np // which was introduced in macOS 10.15. - return Ok(None); + if self.get_program_kind() == ProgramKind::Relative { + return Ok(None); + } } match posix_spawn_file_actions_addchdir_np.get() { Some(f) => Some((f, cwd)), diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index bf4920488..a6fe07873 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -1,13 +1,13 @@ -use crate::mem; -use crate::slice; - pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - unsafe { - let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v)); - imp::fill_bytes(view); - } - v + const KEY_LEN: usize = core::mem::size_of::(); + + let mut v = [0u8; KEY_LEN * 2]; + imp::fill_bytes(&mut v); + + let key1 = v[0..KEY_LEN].try_into().unwrap(); + let key2 = v[KEY_LEN..].try_into().unwrap(); + + (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) } #[cfg(all( diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 36a3fa602..f6b627afc 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -116,11 +116,9 @@ impl Thread { debug_assert_eq!(ret, 0); } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(target_os = "android")] pub fn set_name(name: &CStr) { const PR_SET_NAME: libc::c_int = 15; - // pthread wrapper only appeared in glibc 2.12, so we use syscall - // directly. unsafe { libc::prctl( PR_SET_NAME, @@ -132,6 +130,17 @@ impl Thread { } } + #[cfg(target_os = "linux")] + pub fn set_name(name: &CStr) { + const TASK_COMM_LEN: usize = 16; + + unsafe { + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. + let name = truncate_cstr(name, TASK_COMM_LEN); + libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); + } + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] pub fn set_name(name: &CStr) { unsafe { @@ -142,6 +151,7 @@ impl Thread { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { + let name = truncate_cstr(name, libc::MAXTHREADNAMESIZE); libc::pthread_setname_np(name.as_ptr()); } } @@ -271,6 +281,20 @@ impl Drop for Thread { } } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +fn truncate_cstr(cstr: &CStr, max_with_nul: usize) -> crate::borrow::Cow<'_, CStr> { + use crate::{borrow::Cow, ffi::CString}; + + if cstr.to_bytes_with_nul().len() > max_with_nul { + let bytes = cstr.to_bytes()[..max_with_nul - 1].to_vec(); + // SAFETY: the non-nul bytes came straight from a CStr. + // (CString will add the terminating nul.) + Cow::Owned(unsafe { CString::from_vec_unchecked(bytes) }) + } else { + Cow::Borrowed(cstr) + } +} + pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( @@ -423,7 +447,7 @@ mod cgroups { Some(b"") => Cgroup::V2, Some(controllers) if from_utf8(controllers) - .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) => + .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) => { Cgroup::V1 } diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs deleted file mode 100644 index ca1a7138f..000000000 --- a/library/std/src/sys/unix/thread_parker.rs +++ /dev/null @@ -1,281 +0,0 @@ -//! Thread parking without `futex` using the `pthread` synchronization primitives. - -#![cfg(not(any( - target_os = "linux", - target_os = "android", - all(target_os = "emscripten", target_feature = "atomics"), - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "fuchsia", -)))] - -use crate::cell::UnsafeCell; -use crate::marker::PhantomPinned; -use crate::pin::Pin; -use crate::ptr::addr_of_mut; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::time::Duration; - -const EMPTY: usize = 0; -const PARKED: usize = 1; -const NOTIFIED: usize = 2; - -unsafe fn lock(lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_mutex_lock(lock); - debug_assert_eq!(r, 0); -} - -unsafe fn unlock(lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_mutex_unlock(lock); - debug_assert_eq!(r, 0); -} - -unsafe fn notify_one(cond: *mut libc::pthread_cond_t) { - let r = libc::pthread_cond_signal(cond); - debug_assert_eq!(r, 0); -} - -unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_cond_wait(cond, lock); - debug_assert_eq!(r, 0); -} - -const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; - -unsafe fn wait_timeout( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - dur: Duration, -) { - // Use the system clock on systems that do not support pthread_condattr_setclock. - // This unfortunately results in problems when the system time changes. - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "espidf" - ))] - let (now, dur) = { - use super::time::SystemTime; - use crate::cmp::min; - - // OSX implementation of `pthread_cond_timedwait` is buggy - // with super long durations. When duration is greater than - // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` - // in macOS Sierra return error 316. - // - // This program demonstrates the issue: - // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c - // - // To work around this issue, and possible bugs of other OSes, timeout - // is clamped to 1000 years, which is allowable per the API of `park_timeout` - // because of spurious wakeups. - let dur = min(dur, Duration::from_secs(1000 * 365 * 86400)); - let now = SystemTime::now().t; - (now, dur) - }; - // Use the monotonic clock on other systems. - #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "espidf" - )))] - let (now, dur) = { - use super::time::Timespec; - - (Timespec::now(libc::CLOCK_MONOTONIC), dur) - }; - - let timeout = - now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX); - let r = libc::pthread_cond_timedwait(cond, lock, &timeout); - debug_assert!(r == libc::ETIMEDOUT || r == 0); -} - -pub struct Parker { - state: AtomicUsize, - lock: UnsafeCell, - cvar: UnsafeCell, - // The `pthread` primitives require a stable address, so make this struct `!Unpin`. - _pinned: PhantomPinned, -} - -impl Parker { - /// Construct the UNIX parker in-place. - /// - /// # Safety - /// The constructed parker must never be moved. - pub unsafe fn new(parker: *mut Parker) { - // Use the default mutex implementation to allow for simpler initialization. - // This could lead to undefined behaviour when deadlocking. This is avoided - // by not deadlocking. Note in particular the unlocking operation before any - // panic, as code after the panic could try to park again. - addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); - addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); - - cfg_if::cfg_if! { - if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "l4re", - target_os = "android", - target_os = "redox" - ))] { - addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); - } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); - assert_eq!(r, 0); - } else { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } - } - } - - // This implementation doesn't require `unsafe`, but other implementations - // may assume this is only called by the thread that owns the Parker. - pub unsafe fn park(self: Pin<&Self>) { - // If we were previously notified then we consume this notification and - // return quickly. - if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - - // Otherwise we need to coordinate going to sleep - lock(self.lock.get()); - match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - // We must read here, even though we know it will be `NOTIFIED`. - // This is because `unpark` may have been called again since we read - // `NOTIFIED` in the `compare_exchange` above. We must perform an - // acquire operation that synchronizes with that `unpark` to observe - // any writes it made before the call to unpark. To do that we must - // read from the write it made to `state`. - let old = self.state.swap(EMPTY, SeqCst); - - unlock(self.lock.get()); - - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => { - unlock(self.lock.get()); - - panic!("inconsistent park state") - } - } - - loop { - wait(self.cvar.get(), self.lock.get()); - - match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { - Ok(_) => break, // got a notification - Err(_) => {} // spurious wakeup, go back to sleep - } - } - - unlock(self.lock.get()); - } - - // This implementation doesn't require `unsafe`, but other implementations - // may assume this is only called by the thread that owns the Parker. Use - // `Pin` to guarantee a stable address for the mutex and condition variable. - pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { - // Like `park` above we have a fast path for an already-notified thread, and - // afterwards we start coordinating for a sleep. - // return quickly. - if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - - lock(self.lock.get()); - match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - // We must read again here, see `park`. - let old = self.state.swap(EMPTY, SeqCst); - unlock(self.lock.get()); - - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => { - unlock(self.lock.get()); - panic!("inconsistent park_timeout state") - } - } - - // Wait with a timeout, and if we spuriously wake up or otherwise wake up - // from a notification we just want to unconditionally set the state back to - // empty, either consuming a notification or un-flagging ourselves as - // parked. - wait_timeout(self.cvar.get(), self.lock.get(), dur); - - match self.state.swap(EMPTY, SeqCst) { - NOTIFIED => unlock(self.lock.get()), // got a notification, hurray! - PARKED => unlock(self.lock.get()), // no notification, alas - n => { - unlock(self.lock.get()); - panic!("inconsistent park_timeout state: {n}") - } - } - } - - pub fn unpark(self: Pin<&Self>) { - // To ensure the unparked thread will observe any writes we made - // before this call, we must perform a release operation that `park` - // can synchronize with. To do that we must write `NOTIFIED` even if - // `state` is already `NOTIFIED`. That is why this must be a swap - // rather than a compare-and-swap that returns if it reads `NOTIFIED` - // on failure. - match self.state.swap(NOTIFIED, SeqCst) { - EMPTY => return, // no one was waiting - NOTIFIED => return, // already unparked - PARKED => {} // gotta go wake someone up - _ => panic!("inconsistent state in unpark"), - } - - // There is a period between when the parked thread sets `state` to - // `PARKED` (or last checked `state` in the case of a spurious wake - // up) and when it actually waits on `cvar`. If we were to notify - // during this period it would be ignored and then when the parked - // thread went to sleep it would never wake up. Fortunately, it has - // `lock` locked at this stage so we can acquire `lock` to wait until - // it is ready to receive the notification. - // - // Releasing `lock` before the call to `notify_one` means that when the - // parked thread wakes it doesn't get woken only to have to wait for us - // to release `lock`. - unsafe { - lock(self.lock.get()); - unlock(self.lock.get()); - notify_one(self.cvar.get()); - } - } -} - -impl Drop for Parker { - fn drop(&mut self) { - unsafe { - libc::pthread_cond_destroy(self.cvar.get_mut()); - libc::pthread_mutex_destroy(self.lock.get_mut()); - } - } -} - -unsafe impl Sync for Parker {} -unsafe impl Send for Parker {} diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs new file mode 100644 index 000000000..e2453580d --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -0,0 +1,21 @@ +//! Thread parking on systems without futex support. + +#![cfg(not(any( + target_os = "linux", + target_os = "android", + all(target_os = "emscripten", target_feature = "atomics"), + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "fuchsia", +)))] + +cfg_if::cfg_if! { + if #[cfg(target_os = "netbsd")] { + mod netbsd; + pub use netbsd::Parker; + } else { + mod pthread; + pub use pthread::Parker; + } +} diff --git a/library/std/src/sys/unix/thread_parker/netbsd.rs b/library/std/src/sys/unix/thread_parker/netbsd.rs new file mode 100644 index 000000000..7657605b5 --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/netbsd.rs @@ -0,0 +1,113 @@ +use crate::ffi::{c_int, c_void}; +use crate::pin::Pin; +use crate::ptr::{null, null_mut}; +use crate::sync::atomic::{ + AtomicU64, + Ordering::{Acquire, Relaxed, Release}, +}; +use crate::time::Duration; +use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC}; + +extern "C" { + fn ___lwp_park60( + clock_id: clockid_t, + flags: c_int, + ts: *mut timespec, + unpark: lwpid_t, + hint: *const c_void, + unparkhint: *const c_void, + ) -> c_int; + fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int; +} + +/// The thread is not parked and the token is not available. +/// +/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark +/// argument in _lwp_park. +const EMPTY: u64 = 0; +/// The token is available. Do not park anymore. +const NOTIFIED: u64 = u64::MAX; + +pub struct Parker { + /// The parker state. Contains either one of the two state values above or the LWP + /// id of the parked thread. + state: AtomicU64, +} + +impl Parker { + pub unsafe fn new(parker: *mut Parker) { + parker.write(Parker { state: AtomicU64::new(EMPTY) }) + } + + // Does not actually need `unsafe` or `Pin`, but the pthread implementation does. + pub unsafe fn park(self: Pin<&Self>) { + // If the token has already been made available, we can skip + // a bit of work, so check for it here. + if self.state.load(Acquire) != NOTIFIED { + let parked = _lwp_self() as u64; + let hint = self.state.as_mut_ptr().cast(); + if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() { + // Loop to guard against spurious wakeups. + loop { + ___lwp_park60(0, 0, null_mut(), 0, hint, null()); + if self.state.load(Acquire) == NOTIFIED { + break; + } + } + } + } + + // At this point, the change to NOTIFIED has always been observed with acquire + // ordering, so we can just use a relaxed store here (instead of a swap). + self.state.store(EMPTY, Relaxed); + } + + // Does not actually need `unsafe` or `Pin`, but the pthread implementation does. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + if self.state.load(Acquire) != NOTIFIED { + let parked = _lwp_self() as u64; + let hint = self.state.as_mut_ptr().cast(); + let mut timeout = timespec { + // Saturate so that the operation will definitely time out + // (even if it is after the heat death of the universe). + tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX), + tv_nsec: dur.subsec_nanos().into(), + }; + + if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() { + // Timeout needs to be mutable since it is modified on NetBSD 9.0 and + // above. + ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null()); + // Use a swap to get acquire ordering even if the token was set after + // the timeout occurred. + self.state.swap(EMPTY, Acquire); + return; + } + } + + self.state.store(EMPTY, Relaxed); + } + + // Does not actually need `Pin`, but the pthread implementation does. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + if !matches!(state, EMPTY | NOTIFIED) { + let lwp = state as lwpid_t; + let hint = self.state.as_mut_ptr().cast(); + + // If the parking thread terminated and did not actually park, this will + // probably return an error, which is OK. In the worst case, another + // thread has received the same LWP id. It will then receive a spurious + // wakeup, but those are allowable per the API contract. The same reasoning + // applies if a timeout occurred before this call, but the state was not + // yet reset. + + // SAFETY: + // The syscall has no invariants to hold. Only unsafe because it is an + // extern function. + unsafe { + _lwp_unpark(lwp, hint); + } + } + } +} diff --git a/library/std/src/sys/unix/thread_parker/pthread.rs b/library/std/src/sys/unix/thread_parker/pthread.rs new file mode 100644 index 000000000..3dfc0026e --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/pthread.rs @@ -0,0 +1,271 @@ +//! Thread parking without `futex` using the `pthread` synchronization primitives. + +use crate::cell::UnsafeCell; +use crate::marker::PhantomPinned; +use crate::pin::Pin; +use crate::ptr::addr_of_mut; +use crate::sync::atomic::AtomicUsize; +use crate::sync::atomic::Ordering::SeqCst; +use crate::time::Duration; + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +unsafe fn lock(lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_mutex_lock(lock); + debug_assert_eq!(r, 0); +} + +unsafe fn unlock(lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_mutex_unlock(lock); + debug_assert_eq!(r, 0); +} + +unsafe fn notify_one(cond: *mut libc::pthread_cond_t) { + let r = libc::pthread_cond_signal(cond); + debug_assert_eq!(r, 0); +} + +unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) { + let r = libc::pthread_cond_wait(cond, lock); + debug_assert_eq!(r, 0); +} + +const TIMESPEC_MAX: libc::timespec = + libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; + +unsafe fn wait_timeout( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + dur: Duration, +) { + // Use the system clock on systems that do not support pthread_condattr_setclock. + // This unfortunately results in problems when the system time changes. + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "espidf" + ))] + let (now, dur) = { + use crate::cmp::min; + use crate::sys::time::SystemTime; + + // OSX implementation of `pthread_cond_timedwait` is buggy + // with super long durations. When duration is greater than + // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` + // in macOS Sierra return error 316. + // + // This program demonstrates the issue: + // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c + // + // To work around this issue, and possible bugs of other OSes, timeout + // is clamped to 1000 years, which is allowable per the API of `park_timeout` + // because of spurious wakeups. + let dur = min(dur, Duration::from_secs(1000 * 365 * 86400)); + let now = SystemTime::now().t; + (now, dur) + }; + // Use the monotonic clock on other systems. + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "espidf" + )))] + let (now, dur) = { + use crate::sys::time::Timespec; + + (Timespec::now(libc::CLOCK_MONOTONIC), dur) + }; + + let timeout = + now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX); + let r = libc::pthread_cond_timedwait(cond, lock, &timeout); + debug_assert!(r == libc::ETIMEDOUT || r == 0); +} + +pub struct Parker { + state: AtomicUsize, + lock: UnsafeCell, + cvar: UnsafeCell, + // The `pthread` primitives require a stable address, so make this struct `!Unpin`. + _pinned: PhantomPinned, +} + +impl Parker { + /// Construct the UNIX parker in-place. + /// + /// # Safety + /// The constructed parker must never be moved. + pub unsafe fn new(parker: *mut Parker) { + // Use the default mutex implementation to allow for simpler initialization. + // This could lead to undefined behaviour when deadlocking. This is avoided + // by not deadlocking. Note in particular the unlocking operation before any + // panic, as code after the panic could try to park again. + addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); + addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "l4re", + target_os = "android", + target_os = "redox" + ))] { + addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); + } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { + let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); + assert_eq!(r, 0); + } else { + use crate::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); + assert_eq!(r, 0); + let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); + assert_eq!(r, 0); + let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); + assert_eq!(r, 0); + let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); + assert_eq!(r, 0); + } + } + } + + // This implementation doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. + pub unsafe fn park(self: Pin<&Self>) { + // If we were previously notified then we consume this notification and + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + // Otherwise we need to coordinate going to sleep + lock(self.lock.get()); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read here, even though we know it will be `NOTIFIED`. + // This is because `unpark` may have been called again since we read + // `NOTIFIED` in the `compare_exchange` above. We must perform an + // acquire operation that synchronizes with that `unpark` to observe + // any writes it made before the call to unpark. To do that we must + // read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + + unlock(self.lock.get()); + + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => { + unlock(self.lock.get()); + + panic!("inconsistent park state") + } + } + + loop { + wait(self.cvar.get(), self.lock.get()); + + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => break, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + + unlock(self.lock.get()); + } + + // This implementation doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. Use + // `Pin` to guarantee a stable address for the mutex and condition variable. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + // Like `park` above we have a fast path for an already-notified thread, and + // afterwards we start coordinating for a sleep. + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + lock(self.lock.get()); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read again here, see `park`. + let old = self.state.swap(EMPTY, SeqCst); + unlock(self.lock.get()); + + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => { + unlock(self.lock.get()); + panic!("inconsistent park_timeout state") + } + } + + // Wait with a timeout, and if we spuriously wake up or otherwise wake up + // from a notification we just want to unconditionally set the state back to + // empty, either consuming a notification or un-flagging ourselves as + // parked. + wait_timeout(self.cvar.get(), self.lock.get(), dur); + + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => unlock(self.lock.get()), // got a notification, hurray! + PARKED => unlock(self.lock.get()), // no notification, alas + n => { + unlock(self.lock.get()); + panic!("inconsistent park_timeout state: {n}") + } + } + } + + pub fn unpark(self: Pin<&Self>) { + // To ensure the unparked thread will observe any writes we made + // before this call, we must perform a release operation that `park` + // can synchronize with. To do that we must write `NOTIFIED` even if + // `state` is already `NOTIFIED`. That is why this must be a swap + // rather than a compare-and-swap that returns if it reads `NOTIFIED` + // on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to + // `PARKED` (or last checked `state` in the case of a spurious wake + // up) and when it actually waits on `cvar`. If we were to notify + // during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has + // `lock` locked at this stage so we can acquire `lock` to wait until + // it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the + // parked thread wakes it doesn't get woken only to have to wait for us + // to release `lock`. + unsafe { + lock(self.lock.get()); + unlock(self.lock.get()); + notify_one(self.cvar.get()); + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + unsafe { + libc::pthread_cond_destroy(self.cvar.get_mut()); + libc::pthread_mutex_destroy(self.lock.get_mut()); + } + } +} + +unsafe impl Sync for Parker {} +unsafe impl Send for Parker {} diff --git a/library/std/src/sys/unsupported/alloc.rs b/library/std/src/sys/unsupported/alloc.rs index 8d5d0a2f5..d715ae454 100644 --- a/library/std/src/sys/unsupported/alloc.rs +++ b/library/std/src/sys/unsupported/alloc.rs @@ -1,15 +1,16 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr::null_mut; #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] @@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 { - 0 as *mut u8 + null_mut() } } diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 4c9ade4a8..5cd9e57de 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -6,7 +6,7 @@ pub mod memchr { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index 0e1a6257e..6ac1b5d2b 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; @@ -214,7 +214,7 @@ impl File { self.0 } - pub fn read_buf(&self, _buf: &mut ReadBuf<'_>) -> io::Result<()> { + pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { self.0 } diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index d7cb12e0c..2be0b34b9 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -16,9 +16,6 @@ impl Mutex { Mutex { locked: Cell::new(false) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 42a1ff730..633f17c05 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -200,6 +200,9 @@ impl<'a> Iterator for CommandArgs<'a> { fn next(&mut self) -> Option<&'a OsStr> { None } + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } } impl<'a> ExactSizeIterator for CommandArgs<'a> {} diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 6614ae397..510cf36b1 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -3,7 +3,7 @@ use super::fd::WasiFd; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::iter; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; @@ -439,8 +439,8 @@ impl File { true } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - crate::io::default_read_buf(|buf| self.read(buf), buf) + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } pub fn write(&self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 4cc0e4ed5..d2081771b 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -4,7 +4,7 @@ use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; -use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd}; pub struct Stdin; pub struct Stdout; @@ -23,6 +23,13 @@ impl AsRawFd for Stdin { } } +impl AsFd for Stdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(0) } + } +} + impl io::Read for Stdin { fn read(&mut self, data: &mut [u8]) -> io::Result { self.read_vectored(&mut [IoSliceMut::new(data)]) @@ -51,6 +58,13 @@ impl AsRawFd for Stdout { } } +impl AsFd for Stdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(1) } + } +} + impl io::Write for Stdout { fn write(&mut self, data: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(data)]) @@ -82,6 +96,13 @@ impl AsRawFd for Stderr { } } +impl AsFd for Stderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(2) } + } +} + impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(data)]) diff --git a/library/std/src/sys/windows/alloc.rs b/library/std/src/sys/windows/alloc.rs index fdc81cdea..d53ea1600 100644 --- a/library/std/src/sys/windows/alloc.rs +++ b/library/std/src/sys/windows/alloc.rs @@ -16,6 +16,7 @@ mod tests; // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed. const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008; +#[link(name = "kernel32")] extern "system" { // Get a handle to the default heap of the current process, or null if the operation fails. // @@ -168,7 +169,7 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { // SAFETY: Because the size and alignment of a header is <= `MIN_ALIGN` and `aligned` // is aligned to at least `MIN_ALIGN` and has at least `MIN_ALIGN` bytes of padding before // it, it is safe to write a header directly before it. - unsafe { ptr::write((aligned as *mut Header).offset(-1), Header(ptr)) }; + unsafe { ptr::write((aligned as *mut Header).sub(1), Header(ptr)) }; // SAFETY: The returned pointer does not point to the to the start of an allocated block, // but there is a header readable directly before it containing the location of the start @@ -213,7 +214,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: Because of the contract of `System`, `ptr` is guaranteed to be non-null // and have a header readable directly before it. - unsafe { ptr::read((ptr as *mut Header).offset(-1)).0 } + unsafe { ptr::read((ptr as *mut Header).sub(1)).0 } } }; diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 478068c73..89d0ab59b 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -66,6 +66,7 @@ pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; pub type LPWSABUF = *mut WSABUF; pub type LPWSAOVERLAPPED = *mut c_void; pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; +pub type BCRYPT_ALG_HANDLE = LPVOID; pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PLARGE_INTEGER = *mut c_longlong; @@ -278,6 +279,7 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; +pub const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC00000BB_u32 as _; // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -285,7 +287,8 @@ pub fn nt_success(status: NTSTATUS) -> bool { status >= 0 } -pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; +// "RNG\0" +pub const BCRYPT_RNG_ALGORITHM: &[u16] = &[b'R' as u16, b'N' as u16, b'G' as u16, 0]; #[repr(C)] pub struct UNICODE_STRING { @@ -454,6 +457,12 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { MaximumFileInfoByHandlesClass, } +#[repr(C)] +pub struct FILE_ATTRIBUTE_TAG_INFO { + pub FileAttributes: DWORD, + pub ReparseTag: DWORD, +} + #[repr(C)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: BOOLEAN, @@ -501,6 +510,8 @@ pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: LARGE_INTEGER, } +/// NB: Use carefully! In general using this as a reference is likely to get the +/// provenance wrong for the `rest` field! #[repr(C)] pub struct REPARSE_DATA_BUFFER { pub ReparseTag: c_uint, @@ -509,6 +520,8 @@ pub struct REPARSE_DATA_BUFFER { pub rest: (), } +/// NB: Use carefully! In general using this as a reference is likely to get the +/// provenance wrong for the `PathBuffer` field! #[repr(C)] pub struct SYMBOLIC_LINK_REPARSE_BUFFER { pub SubstituteNameOffset: c_ushort, @@ -519,6 +532,8 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER { pub PathBuffer: WCHAR, } +/// NB: Use carefully! In general using this as a reference is likely to get the +/// provenance wrong for the `PathBuffer` field! #[repr(C)] pub struct MOUNT_POINT_REPARSE_BUFFER { pub SubstituteNameOffset: c_ushort, @@ -1217,11 +1232,18 @@ extern "system" { // >= Vista / Server 2008 // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom pub fn BCryptGenRandom( - hAlgorithm: LPVOID, + hAlgorithm: BCRYPT_ALG_HANDLE, pBuffer: *mut u8, cbBuffer: ULONG, dwFlags: ULONG, ) -> NTSTATUS; + pub fn BCryptOpenAlgorithmProvider( + phalgorithm: *mut BCRYPT_ALG_HANDLE, + pszAlgId: LPCWSTR, + pszimplementation: LPCWSTR, + dwflags: ULONG, + ) -> NTSTATUS; + pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS; } // Functions that aren't available on every version of Windows that we support, @@ -1251,17 +1273,14 @@ compat_fn_with_fallback! { } compat_fn_optional! { - pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); - - // >= Windows 8 / Server 2012 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress + crate::sys::compat::load_synch_functions(); pub fn WaitOnAddress( Address: LPVOID, CompareAddress: LPVOID, AddressSize: SIZE_T, dwMilliseconds: DWORD - ) -> BOOL; - pub fn WakeByAddressSingle(Address: LPVOID) -> (); + ); + pub fn WakeByAddressSingle(Address: LPVOID); } compat_fn_with_fallback! { diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs index 1a5421fac..43ab8c7ee 100644 --- a/library/std/src/sys/windows/cmath.rs +++ b/library/std/src/sys/windows/cmath.rs @@ -44,7 +44,7 @@ mod shims { } // On 32-bit x86 MSVC these functions aren't defined, so we just define shims -// which promote everything fo f64, perform the calculation, and then demote +// which promote everything to f64, perform the calculation, and then demote // back to f32. While not precisely correct should be "correct enough" for now. #[cfg(all(target_env = "msvc", target_arch = "x86"))] mod shims { diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index ccc90177a..7dff81ecb 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -7,52 +7,66 @@ //! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at //! runtime. //! -//! This implementation uses a static initializer to look up the DLL entry -//! points. The CRT (C runtime) executes static initializers before `main` -//! is called (for binaries) and before `DllMain` is called (for DLLs). -//! This is the ideal time to look up DLL imports, because we are guaranteed -//! that no other threads will attempt to call these entry points. Thus, -//! we can look up the imports and store them in `static mut` fields -//! without any synchronization. +//! This is implemented simply by storing a function pointer in an atomic. +//! Loading and calling this function will have little or no overhead +//! compared with calling any other dynamically imported function. //! -//! This has an additional advantage: Because the DLL import lookup happens -//! at module initialization, the cost of these lookups is deterministic, -//! and is removed from the code paths that actually call the DLL imports. -//! That is, there is no unpredictable "cache miss" that occurs when calling -//! a DLL import. For applications that benefit from predictable delays, -//! this is a benefit. This also eliminates the comparison-and-branch -//! from the hot path. -//! -//! Currently, the standard library uses only a small number of dynamic -//! DLL imports. If this number grows substantially, then the cost of -//! performing all of the lookups at initialization time might become -//! substantial. -//! -//! The mechanism of registering a static initializer with the CRT is -//! documented in -//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160). -//! It works by contributing a global symbol to the `.CRT$XCU` section. -//! The linker builds a table of all static initializer functions. -//! The CRT startup code then iterates that table, calling each -//! initializer function. -//! -//! # **WARNING!!* -//! The environment that a static initializer function runs in is highly -//! constrained. There are **many** restrictions on what static initializers -//! can safely do. Static initializer functions **MUST NOT** do any of the -//! following (this list is not comprehensive): -//! * touch any other static field that is used by a different static -//! initializer, because the order that static initializers run in -//! is not defined. -//! * call `LoadLibrary` or any other function that acquires the DLL -//! loader lock. -//! * call any Rust function or CRT function that touches any static -//! (global) state. +//! The stored function pointer starts out as an importer function which will +//! swap itself with the real function when it's called for the first time. If +//! the real function can't be imported then a fallback function is used in its +//! place. While this is low cost for the happy path (where the function is +//! already loaded) it does mean there's some overhead the first time the +//! function is called. In the worst case, multiple threads may all end up +//! importing the same function unnecessarily. use crate::ffi::{c_void, CStr}; use crate::ptr::NonNull; +use crate::sync::atomic::Ordering; use crate::sys::c; +// This uses a static initializer to preload some imported functions. +// The CRT (C runtime) executes static initializers before `main` +// is called (for binaries) and before `DllMain` is called (for DLLs). +// +// It works by contributing a global symbol to the `.CRT$XCT` section. +// The linker builds a table of all static initializer functions. +// The CRT startup code then iterates that table, calling each +// initializer function. +// +// NOTE: User code should instead use .CRT$XCU to reliably run after std's initializer. +// If you're reading this and would like a guarantee here, please +// file an issue for discussion; currently we don't guarantee any functionality +// before main. +// See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170 +#[used] +#[link_section = ".CRT$XCT"] +static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; + +/// Preload some imported functions. +/// +/// Note that any functions included here will be unconditionally loaded in +/// the final binary, regardless of whether or not they're actually used. +/// +/// Therefore, this should be limited to `compat_fn_optional` functions which +/// must be preloaded or any functions where lazier loading demonstrates a +/// negative performance impact in practical situations. +/// +/// Currently we only preload `WaitOnAddress` and `WakeByAddressSingle`. +unsafe extern "C" fn init() { + // In an exe this code is executed before main() so is single threaded. + // In a DLL the system's loader lock will be held thereby synchronizing + // access. So the same best practices apply here as they do to running in DllMain: + // https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices + // + // DO NOT do anything interesting or complicated in this function! DO NOT call + // any Rust functions or CRT functions if those functions touch any global state, + // because this function runs during global initialization. For example, DO NOT + // do any dynamic allocation, don't call LoadLibrary, etc. + + // Attempt to preload the synch functions. + load_synch_functions(); +} + /// Helper macro for creating CStrs from literals and symbol names. macro_rules! ansi_str { (sym $ident:ident) => {{ @@ -85,39 +99,6 @@ pub(crate) const fn const_cstr_from_bytes(bytes: &'static [u8]) -> &'static CStr unsafe { crate::ffi::CStr::from_bytes_with_nul_unchecked(bytes) } } -#[used] -#[link_section = ".CRT$XCU"] -static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; - -/// This is where the magic preloading of symbols happens. -/// -/// Note that any functions included here will be unconditionally included in -/// the final binary, regardless of whether or not they're actually used. -/// -/// Therefore, this is limited to `compat_fn_optional` functions which must be -/// preloaded and any functions which may be more time sensitive, even for the first call. -unsafe extern "C" fn init() { - // There is no locking here. This code is executed before main() is entered, and - // is guaranteed to be single-threaded. - // - // DO NOT do anything interesting or complicated in this function! DO NOT call - // any Rust functions or CRT functions if those functions touch any global state, - // because this function runs during global initialization. For example, DO NOT - // do any dynamic allocation, don't call LoadLibrary, etc. - - if let Some(synch) = Module::new(c::SYNCH_API) { - // These are optional and so we must manually attempt to load them - // before they can be used. - c::WaitOnAddress::preload(synch); - c::WakeByAddressSingle::preload(synch); - } - - if let Some(kernel32) = Module::new(c::KERNEL32) { - // Preloading this means getting a precise time will be as fast as possible. - c::GetSystemTimePreciseAsFileTime::preload(kernel32); - } -} - /// Represents a loaded module. /// /// Note that the modules std depends on must not be unloaded. @@ -151,7 +132,7 @@ impl Module { macro_rules! compat_fn_with_fallback { (pub static $module:ident: &CStr = $name:expr; $( $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block + $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block )*) => ( pub static $module: &CStr = $name; $( @@ -196,11 +177,6 @@ macro_rules! compat_fn_with_fallback { $fallback_body } - #[allow(unused)] - pub(in crate::sys) fn preload(module: Module) { - load_from_module(Some(module)); - } - #[inline(always)] pub unsafe fn call($($argname: $argtype),*) -> $rettype { let func: F = mem::transmute(PTR.load(Ordering::Relaxed)); @@ -208,66 +184,60 @@ macro_rules! compat_fn_with_fallback { } } $(#[$meta])* - pub use $symbol::call as $symbol; + $vis use $symbol::call as $symbol; )*) } -/// A function that either exists or doesn't. +/// Optionally loaded functions. /// -/// NOTE: Optional functions must be preloaded in the `init` function above, or they will always be None. +/// Actual loading of the function defers to $load_functions. macro_rules! compat_fn_optional { - (pub static $module:ident: &CStr = $name:expr; $( - $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty; - )*) => ( - pub static $module: &CStr = $name; + ($load_functions:expr; $( - $(#[$meta])* - pub mod $symbol { - #[allow(unused_imports)] - use super::*; - use crate::mem; - use crate::sync::atomic::{AtomicPtr, Ordering}; - use crate::sys::compat::Module; - use crate::ptr::{self, NonNull}; - - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; - - /// `PTR` will either be `null()` or set to the loaded function. - static PTR: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - - /// Only allow access to the function if it has loaded successfully. - #[inline(always)] - #[cfg(not(miri))] - pub fn option() -> Option { - unsafe { - NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| mem::transmute(f)) + $(#[$meta:meta])* + $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?; + )+) => ( + $( + pub mod $symbol { + use super::*; + use crate::ffi::c_void; + use crate::mem; + use crate::ptr::{self, NonNull}; + use crate::sync::atomic::{AtomicPtr, Ordering}; + + pub(in crate::sys) static PTR: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?; + + #[inline(always)] + pub fn option() -> Option { + // Miri does not understand the way we do preloading + // therefore load the function here instead. + #[cfg(miri)] $load_functions; + NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) }) } } + )+ + ) +} - // Miri does not understand the way we do preloading - // therefore load the function here instead. - #[cfg(miri)] - pub fn option() -> Option { - let mut func = NonNull::new(PTR.load(Ordering::Relaxed)); - if func.is_none() { - unsafe { Module::new($module).map(preload) }; - func = NonNull::new(PTR.load(Ordering::Relaxed)); - } - unsafe { - func.map(|f| mem::transmute(f)) - } - } +/// Load all needed functions from "api-ms-win-core-synch-l1-2-0". +pub(super) fn load_synch_functions() { + fn try_load() -> Option<()> { + const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); + const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress"); + const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle"); + + // Try loading the library and all the required functions. + // If any step fails, then they all fail. + let library = unsafe { Module::new(MODULE_NAME) }?; + let wait_on_address = library.proc_address(WAIT_ON_ADDRESS)?; + let wake_by_address_single = library.proc_address(WAKE_BY_ADDRESS_SINGLE)?; + + c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Relaxed); + c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Relaxed); + Some(()) + } - #[allow(unused)] - pub(in crate::sys) fn preload(module: Module) { - unsafe { - static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol); - if let Some(f) = module.proc_address(SYMBOL_NAME) { - PTR.store(f.as_ptr(), Ordering::Relaxed); - } - } - } - } - )*) + try_load(); } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index aed082b3e..155d0297e 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -2,8 +2,8 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; -use crate::mem; +use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem::{self, MaybeUninit}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -11,7 +11,7 @@ use crate::slice; use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::time::SystemTime; -use crate::sys::{c, cvt}; +use crate::sys::{c, cvt, Align8}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::thread; @@ -326,9 +326,15 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - reparse_tag = buf.ReparseTag; + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + ptr::addr_of_mut!(attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; } } Ok(FileAttr { @@ -389,9 +395,15 @@ impl File { attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); if attr.file_type().is_reparse_point() { - let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - attr.reparse_tag = buf.ReparseTag; + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + ptr::addr_of_mut!(attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + attr.reparse_tag = attr_tag.ReparseTag; } } Ok(attr) @@ -415,8 +427,8 @@ impl File { self.handle.read_at(buf, offset) } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - self.handle.read_buf(buf) + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.handle.read_buf(cursor) } pub fn write(&self, buf: &[u8]) -> io::Result { @@ -458,38 +470,46 @@ impl File { Ok(Self { handle: self.handle.try_clone()? }) } - fn reparse_point<'a>( + // NB: returned pointer is derived from `space`, and has provenance to + // match. A raw pointer is returned rather than a reference in order to + // avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`. + fn reparse_point( &self, - space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE], - ) -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> { + space: &mut Align8<[MaybeUninit]>, + ) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> { unsafe { let mut bytes = 0; cvt({ + // Grab this in advance to avoid it invalidating the pointer + // we get from `space.0.as_mut_ptr()`. + let len = space.0.len(); c::DeviceIoControl( self.handle.as_raw_handle(), c::FSCTL_GET_REPARSE_POINT, ptr::null_mut(), 0, - space.as_mut_ptr() as *mut _, - space.len() as c::DWORD, + space.0.as_mut_ptr().cast(), + len as c::DWORD, &mut bytes, ptr::null_mut(), ) })?; - Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER))) + const _: () = assert!(core::mem::align_of::() <= 8); + Ok((bytes, space.0.as_ptr().cast::())) } } fn readlink(&self) -> io::Result { - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut space = Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); let (_bytes, buf) = self.reparse_point(&mut space)?; unsafe { - let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag { + let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { c::IO_REPARSE_TAG_SYMLINK => { let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; + ptr::addr_of!((*buf).rest).cast(); + assert!(info.is_aligned()); ( - &(*info).PathBuffer as *const _ as *const u16, + ptr::addr_of!((*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, @@ -497,9 +517,10 @@ impl File { } c::IO_REPARSE_TAG_MOUNT_POINT => { let info: *const c::MOUNT_POINT_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; + ptr::addr_of!((*buf).rest).cast(); + assert!(info.is_aligned()); ( - &(*info).PathBuffer as *const _ as *const u16, + ptr::addr_of!((*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, false, @@ -512,7 +533,7 @@ impl File { )); } }; - let subst_ptr = path_buffer.offset(subst_off as isize); + let subst_ptr = path_buffer.add(subst_off.into()); let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize); // Absolute paths start with an NT internal namespace prefix `\??\` // We should not let it leak through. @@ -649,27 +670,31 @@ impl File { /// A buffer for holding directory entries. struct DirBuff { - buffer: Vec, + buffer: Box; Self::BUFFER_SIZE]>>, } impl DirBuff { + const BUFFER_SIZE: usize = 1024; fn new() -> Self { - const BUFFER_SIZE: usize = 1024; - Self { buffer: vec![0_u8; BUFFER_SIZE] } + Self { + // Safety: `Align8<[MaybeUninit; N]>` does not need + // initialization. + buffer: unsafe { Box::new_uninit().assume_init() }, + } } fn capacity(&self) -> usize { - self.buffer.len() + self.buffer.0.len() } fn as_mut_ptr(&mut self) -> *mut u8 { - self.buffer.as_mut_ptr().cast() + self.buffer.0.as_mut_ptr().cast() } /// Returns a `DirBuffIter`. fn iter(&self) -> DirBuffIter<'_> { DirBuffIter::new(self) } } -impl AsRef<[u8]> for DirBuff { - fn as_ref(&self) -> &[u8] { - &self.buffer +impl AsRef<[MaybeUninit]> for DirBuff { + fn as_ref(&self) -> &[MaybeUninit] { + &self.buffer.0 } } @@ -677,7 +702,7 @@ impl AsRef<[u8]> for DirBuff { /// /// Currently only returns file names (UTF-16 encoded). struct DirBuffIter<'a> { - buffer: Option<&'a [u8]>, + buffer: Option<&'a [MaybeUninit]>, cursor: usize, } impl<'a> DirBuffIter<'a> { @@ -692,14 +717,21 @@ impl<'a> Iterator for DirBuffIter<'a> { let buffer = &self.buffer?[self.cursor..]; // Get the name and next entry from the buffer. - // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the - // last field (the file name) is unsized. So an offset has to be - // used to get the file name slice. + // SAFETY: + // - The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the last + // field (the file name) is unsized. So an offset has to be used to + // get the file name slice. + // - The OS has guaranteed initialization of the fields of + // `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least + // `FileNameLength` bytes) let (name, is_directory, next_entry) = unsafe { let info = buffer.as_ptr().cast::(); + // Guaranteed to be aligned in documentation for + // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info + assert!(info.is_aligned()); let next_entry = (*info).NextEntryOffset as usize; let name = crate::slice::from_raw_parts( - (*info).FileName.as_ptr().cast::(), + ptr::addr_of!((*info).FileName).cast::(), (*info).FileNameLength as usize / size_of::(), ); let is_directory = ((*info).FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -1337,18 +1369,19 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { let h = f.as_inner().as_raw_handle(); unsafe { - let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let db = data.as_mut_ptr() as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut c::WCHAR; + let mut data = Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + let data_ptr = data.0.as_mut_ptr(); + let db = data_ptr.cast::(); + let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::(); let mut i = 0; // FIXME: this conversion is very hacky let v = br"\??\"; let v = v.iter().map(|x| *x as u16); for c in v.chain(original.as_os_str().encode_wide()) { - *buf.offset(i) = c; + *buf.add(i) = c; i += 1; } - *buf.offset(i) = 0; + *buf.add(i) = 0; i += 1; (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; (*db).ReparseTargetMaximumLength = (i * 2) as c::WORD; @@ -1359,7 +1392,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { cvt(c::DeviceIoControl( h as *mut _, c::FSCTL_SET_REPARSE_POINT, - data.as_ptr() as *mut _, + data_ptr.cast(), (*db).ReparseDataLength + 8, ptr::null_mut(), 0, diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index e24b09cc9..ae33d48c6 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; +use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, @@ -112,18 +112,16 @@ impl Handle { } } - pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> { - let res = unsafe { - self.synchronous_read(buf.unfilled_mut().as_mut_ptr(), buf.remaining(), None) - }; + pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + let res = + unsafe { self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), None) }; match res { Ok(read) => { // Safety: `read` bytes were written to the initialized portion of the buffer unsafe { - buf.assume_init(read as usize); + cursor.advance(read as usize); } - buf.add_filled(read as usize); Ok(()) } diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index f91e8f9f5..91207f5f4 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -37,8 +37,6 @@ impl Mutex { pub const fn new() -> Mutex { Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } } - #[inline] - pub unsafe fn init(&mut self) {} #[inline] pub unsafe fn lock(&self) { diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index b3f6d2d0a..eab9b9612 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -2,6 +2,7 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::io::ErrorKind; +use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::path::PathBuf; use crate::time::Duration; @@ -47,7 +48,7 @@ cfg_if::cfg_if! { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { stack_overflow::init(); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already @@ -204,8 +205,8 @@ where // This initial size also works around `GetFullPathNameW` returning // incorrect size hints for some short paths: // https://github.com/dylni/normpath/issues/5 - let mut stack_buf = [0u16; 512]; - let mut heap_buf = Vec::new(); + let mut stack_buf: [MaybeUninit; 512] = MaybeUninit::uninit_array(); + let mut heap_buf: Vec> = Vec::new(); unsafe { let mut n = stack_buf.len(); loop { @@ -214,6 +215,11 @@ where } else { let extra = n - heap_buf.len(); heap_buf.reserve(extra); + // We used `reserve` and not `reserve_exact`, so in theory we + // may have gotten more than requested. If so, we'd like to use + // it... so long as we won't cause overflow. + n = heap_buf.capacity().min(c::DWORD::MAX as usize); + // Safety: MaybeUninit does not need initialization heap_buf.set_len(n); &mut heap_buf[..] }; @@ -228,13 +234,13 @@ where // error" is still 0 then we interpret it as a 0 length buffer and // not an actual error. c::SetLastError(0); - let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { + let k = match f1(buf.as_mut_ptr().cast::(), n as c::DWORD) { 0 if c::GetLastError() == 0 => 0, 0 => return Err(crate::io::Error::last_os_error()), n => n, } as usize; if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { - n *= 2; + n = n.saturating_mul(2).min(c::DWORD::MAX as usize); } else if k > n { n = k; } else if k == n { @@ -244,7 +250,9 @@ where // Therefore k never equals n. unreachable!(); } else { - return Ok(f2(&buf[..k])); + // Safety: First `k` values are initialized. + let slice: &[u16] = MaybeUninit::slice_assume_init_ref(&buf[..k]); + return Ok(f2(slice)); } } } @@ -321,3 +329,11 @@ pub fn abort_internal() -> ! { } crate::intrinsics::abort(); } + +/// Align the inner value to 8 bytes. +/// +/// This is enough for almost all of the buffers we're likely to work with in +/// the Windows APIs we use. +#[repr(C, align(8))] +#[derive(Copy, Clone)] +pub(crate) struct Align8(pub T); diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index bcac996c0..352337ba3 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -99,11 +99,11 @@ impl Iterator for Env { } let p = self.cur as *const u16; let mut len = 0; - while *p.offset(len) != 0 { + while *p.add(len) != 0 { len += 1; } - let s = slice::from_raw_parts(p, len as usize); - self.cur = self.cur.offset(len + 1); + let s = slice::from_raw_parts(p, len); + self.cur = self.cur.add(len + 1); // Windows allows environment variables to start with an equals // symbol (in any other position, this is the separator between diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 11883f150..4bdd8c505 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -164,9 +164,7 @@ impl Slice { } pub fn to_owned(&self) -> Buf { - let mut buf = Wtf8Buf::with_capacity(self.inner.len()); - buf.push_wtf8(&self.inner); - Buf { inner: buf } + Buf { inner: self.inner.to_owned() } } pub fn clone_into(&self, buf: &mut Buf) { diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index 6eab38cab..623c62361 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -105,7 +105,7 @@ fn test_parse_prefix_verbatim_device() { assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe")); } -// See #93586 for more infomation. +// See #93586 for more information. #[test] fn test_windows_prefix_components() { use crate::path::Path; diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index f8fd93a73..d6cd8f802 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -1,35 +1,126 @@ -use crate::io; +//! # Random key generation +//! +//! This module wraps the RNG provided by the OS. There are a few different +//! ways to interface with the OS RNG so it's worth exploring each of the options. +//! Note that at the time of writing these all go through the (undocumented) +//! `bcryptPrimitives.dll` but they use different route to get there. +//! +//! Originally we were using [`RtlGenRandom`], however that function is +//! deprecated and warns it "may be altered or unavailable in subsequent versions". +//! +//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG` +//! flag to query and find the system configured RNG. However, this change caused a small +//! but significant number of users to experience panics caused by a failure of +//! this function. See [#94098]. +//! +//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE` +//! [Pseudo-handle], which gets the default RNG algorithm without querying the +//! system preference thus hopefully avoiding the previous issue. +//! This is only supported on Windows 10+ so a fallback is used for older versions. +//! +//! [#94098]: https://github.com/rust-lang/rust/issues/94098 +//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom +//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom +//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles use crate::mem; use crate::ptr; use crate::sys::c; +/// Generates high quality secure random keys for use by [`HashMap`]. +/// +/// This is used to seed the default [`RandomState`]. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`RandomState`]: crate::collections::hash_map::RandomState pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = unsafe { - c::BCryptGenRandom( - ptr::null_mut(), - &mut v as *mut _ as *mut u8, - mem::size_of_val(&v) as c::ULONG, - c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - if ret != 0 { fallback_rng() } else { v } + Rng::open().and_then(|rng| rng.gen_random_keys()).unwrap_or_else(fallback_rng) +} + +struct Rng(c::BCRYPT_ALG_HANDLE); +impl Rng { + #[cfg(miri)] + fn open() -> Result { + const BCRYPT_RNG_ALG_HANDLE: c::BCRYPT_ALG_HANDLE = ptr::invalid_mut(0x81); + let _ = ( + c::BCryptOpenAlgorithmProvider, + c::BCryptCloseAlgorithmProvider, + c::BCRYPT_RNG_ALGORITHM, + c::STATUS_NOT_SUPPORTED, + ); + Ok(Self(BCRYPT_RNG_ALG_HANDLE)) + } + #[cfg(not(miri))] + // Open a handle to the RNG algorithm. + fn open() -> Result { + use crate::sync::atomic::AtomicPtr; + use crate::sync::atomic::Ordering::{Acquire, Release}; + const ERROR_VALUE: c::LPVOID = ptr::invalid_mut(usize::MAX); + + // An atomic is used so we don't need to reopen the handle every time. + static HANDLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + let mut handle = HANDLE.load(Acquire); + // We use a sentinel value to designate an error occurred last time. + if handle == ERROR_VALUE { + Err(c::STATUS_NOT_SUPPORTED) + } else if handle.is_null() { + let status = unsafe { + c::BCryptOpenAlgorithmProvider( + &mut handle, + c::BCRYPT_RNG_ALGORITHM.as_ptr(), + ptr::null(), + 0, + ) + }; + if c::nt_success(status) { + // If another thread opens a handle first then use that handle instead. + let result = HANDLE.compare_exchange(ptr::null_mut(), handle, Release, Acquire); + if let Err(previous_handle) = result { + // Close our handle and return the previous one. + unsafe { c::BCryptCloseAlgorithmProvider(handle, 0) }; + handle = previous_handle; + } + Ok(Self(handle)) + } else { + HANDLE.store(ERROR_VALUE, Release); + Err(status) + } + } else { + Ok(Self(handle)) + } + } + + fn gen_random_keys(self) -> Result<(u64, u64), c::NTSTATUS> { + let mut v = (0, 0); + let status = unsafe { + let size = mem::size_of_val(&v).try_into().unwrap(); + c::BCryptGenRandom(self.0, ptr::addr_of_mut!(v).cast(), size, 0) + }; + if c::nt_success(status) { Ok(v) } else { Err(status) } + } } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] #[inline(never)] -fn fallback_rng() -> (u64, u64) { +fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; - if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } + if ret != 0 { + v + } else { + panic!( + "RNG broken: {rng_status:#x}, fallback RNG broken: {}", + crate::io::Error::last_os_error() + ) + } } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] #[inline(never)] -fn fallback_rng() -> (u64, u64) { - panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); +fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) { + panic!("RNG broken: {rng_status:#x} fallback RNG broken: RtlGenRandom() not supported on UWP"); } diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index a001d6b98..70c9b14a0 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -3,6 +3,7 @@ use crate::char::decode_utf16; use crate::cmp; use crate::io; +use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::ptr; use crate::str; @@ -169,13 +170,14 @@ fn write( } fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result { - let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2]; + let mut utf16 = [MaybeUninit::::uninit(); MAX_BUFFER_SIZE / 2]; let mut len_utf16 = 0; for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) { - *dest = chr; + *dest = MaybeUninit::new(chr); len_utf16 += 1; } - let utf16 = &utf16[..len_utf16]; + // Safety: We've initialized `len_utf16` values. + let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) }; let mut written = write_u16s(handle, &utf16)?; @@ -250,11 +252,14 @@ impl io::Read for Stdin { return Ok(bytes_copied); } else if buf.len() - bytes_copied < 4 { // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. - let mut utf16_buf = [0u16; 1]; + let mut utf16_buf = [MaybeUninit::new(0); 1]; // Read one u16 character. let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. - let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?; + let read_bytes = utf16_to_utf8( + unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) }, + &mut self.incomplete_utf8.bytes, + )?; // Read in the bytes from incomplete_utf8 until the buffer is full. self.incomplete_utf8.len = read_bytes as u8; @@ -262,15 +267,18 @@ impl io::Read for Stdin { bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); Ok(bytes_copied) } else { - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; + let mut utf16_buf = [MaybeUninit::::uninit(); MAX_BUFFER_SIZE / 2]; + // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets // lost. let amount = cmp::min(buf.len() / 3, utf16_buf.len()); let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - match utf16_to_utf8(&utf16_buf[..read], buf) { + // Safety `read_u16s_fixup_surrogates` returns the number of items + // initialized. + let utf16s = unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) }; + match utf16_to_utf8(utf16s, buf) { Ok(value) => return Ok(bytes_copied + value), Err(e) => return Err(e), } @@ -283,14 +291,14 @@ impl io::Read for Stdin { // This is a best effort, and might not work if we are not the only reader on Stdin. fn read_u16s_fixup_surrogates( handle: c::HANDLE, - buf: &mut [u16], + buf: &mut [MaybeUninit], mut amount: usize, surrogate: &mut u16, ) -> io::Result { // Insert possibly remaining unpaired surrogate from last read. let mut start = 0; if *surrogate != 0 { - buf[0] = *surrogate; + buf[0] = MaybeUninit::new(*surrogate); *surrogate = 0; start = 1; if amount == 1 { @@ -303,7 +311,10 @@ fn read_u16s_fixup_surrogates( let mut amount = read_u16s(handle, &mut buf[start..amount])? + start; if amount > 0 { - let last_char = buf[amount - 1]; + // Safety: The returned `amount` is the number of values initialized, + // and it is not 0, so we know that `buf[amount - 1]` have been + // initialized. + let last_char = unsafe { buf[amount - 1].assume_init() }; if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate *surrogate = last_char; @@ -313,7 +324,8 @@ fn read_u16s_fixup_surrogates( Ok(amount) } -fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result { +// Returns `Ok(n)` if it initialized `n` values in `buf`. +fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result { // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the // traditional DOS method to indicate end of character stream / user input (SUB). // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole. @@ -346,8 +358,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result { } break; } - - if amount > 0 && buf[amount as usize - 1] == CTRL_Z { + // Safety: if `amount > 0`, then that many bytes were written, so + // `buf[amount as usize - 1]` has been initialized. + if amount > 0 && unsafe { buf[amount as usize - 1].assume_init() } == CTRL_Z { amount -= 1; } Ok(amount as usize) diff --git a/library/std/src/sys/windows/thread_local_dtor.rs b/library/std/src/sys/windows/thread_local_dtor.rs index 25d1c6e8e..9707a95df 100644 --- a/library/std/src/sys/windows/thread_local_dtor.rs +++ b/library/std/src/sys/windows/thread_local_dtor.rs @@ -8,10 +8,14 @@ #[thread_local] static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); +// Ensure this can never be inlined because otherwise this may break in dylibs. +// See #44391. +#[inline(never)] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { DESTRUCTORS.push((t, dtor)); } +#[inline(never)] // See comment above /// Runs destructors. This should not be called until thread exit. pub unsafe fn run_keyless_dtors() { // Drop all the destructors. diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index d876e0f6f..2f7ae863b 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -197,19 +197,17 @@ impl Parker { // purpose, to make sure every unpark() has a release-acquire ordering // with park(). if self.state.swap(NOTIFIED, Release) == PARKED { - if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() { - unsafe { + unsafe { + if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() { wake_by_address_single(self.ptr()); - } - } else { - // If we run NtReleaseKeyedEvent before the waiting thread runs - // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. - // If the waiting thread wakes up before we run NtReleaseKeyedEvent - // (e.g. due to a timeout), this blocks until we do wake up a thread. - // To prevent this thread from blocking indefinitely in that case, - // park_impl() will, after seeing the state set to NOTIFIED after - // waking up, call NtWaitForKeyedEvent again to unblock us. - unsafe { + } else { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 33d336c43..3ad802afa 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -10,7 +10,7 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::ptr; use crate::sys::net::netc as c; use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket}; -use crate::sys_common::{FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use libc::{c_int, c_void}; @@ -345,6 +345,12 @@ impl TcpStream { } } +impl AsInner for TcpStream { + fn as_inner(&self) -> &Socket { + &self.inner + } +} + impl FromInner for TcpStream { fn from_inner(socket: Socket) -> TcpStream { TcpStream { inner: socket } diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 8921af311..b448ae3a9 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,13 +1,11 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; +use super::mutex as sys; use crate::cell::UnsafeCell; -use crate::marker::PhantomPinned; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -use crate::sys::locks as sys; /// A re-entrant mutual exclusion /// @@ -41,11 +39,10 @@ use crate::sys::locks as sys; /// synchronization is left to the mutex, making relaxed memory ordering for /// the `owner` field fine in all cases. pub struct ReentrantMutex { - mutex: sys::Mutex, + mutex: sys::MovableMutex, owner: AtomicUsize, lock_count: UnsafeCell, data: T, - _pinned: PhantomPinned, } unsafe impl Send for ReentrantMutex {} @@ -68,39 +65,22 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: Pin<&'a ReentrantMutex>, + lock: &'a ReentrantMutex, } impl !Send for ReentrantMutexGuard<'_, T> {} impl ReentrantMutex { /// Creates a new reentrant mutex in an unlocked state. - /// - /// # Unsafety - /// - /// This function is unsafe because it is required that `init` is called - /// once this mutex is in its final resting place, and only then are the - /// lock/unlock methods safe. - pub const unsafe fn new(t: T) -> ReentrantMutex { + pub const fn new(t: T) -> ReentrantMutex { ReentrantMutex { - mutex: sys::Mutex::new(), + mutex: sys::MovableMutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0), data: t, - _pinned: PhantomPinned, } } - /// Initializes this mutex so it's ready for use. - /// - /// # Unsafety - /// - /// Unsafe to call more than once, and must be called after this will no - /// longer move in memory. - pub unsafe fn init(self: Pin<&mut Self>) { - self.get_unchecked_mut().mutex.init() - } - /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the caller until it is available to acquire the mutex. @@ -113,15 +93,14 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> { + pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the lock() on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); } else { - self.mutex.lock(); + self.mutex.raw_lock(); self.owner.store(this_thread, Relaxed); debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; @@ -142,10 +121,9 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(self: Pin<&Self>) -> Option> { + pub fn try_lock(&self) -> Option> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the try_lock on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); @@ -179,12 +157,12 @@ impl Deref for ReentrantMutexGuard<'_, T> { impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { - // Safety: We own the lock, and the lock is pinned. + // Safety: We own the lock. unsafe { *self.lock.lock_count.get() -= 1; if *self.lock.lock_count.get() == 0 { self.lock.owner.store(0, Relaxed); - self.lock.mutex.unlock(); + self.lock.mutex.raw_unlock(); } } } diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs index 64873b850..8e97ce11c 100644 --- a/library/std/src/sys_common/remutex/tests.rs +++ b/library/std/src/sys_common/remutex/tests.rs @@ -1,18 +1,11 @@ -use crate::boxed::Box; use crate::cell::RefCell; -use crate::pin::Pin; use crate::sync::Arc; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread; #[test] fn smoke() { - let m = unsafe { - let mut m = Box::pin(ReentrantMutex::new(())); - m.as_mut().init(); - m - }; - let m = m.as_ref(); + let m = ReentrantMutex::new(()); { let a = m.lock(); { @@ -29,20 +22,15 @@ fn smoke() { #[test] fn is_mutex() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an Arc::get_pin_mut. - let mut m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); - Pin::new_unchecked(m) - }; + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); let m2 = m.clone(); - let lock = m.as_ref().lock(); + let lock = m.lock(); let child = thread::spawn(move || { - let lock = m2.as_ref().lock(); + let lock = m2.lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.as_ref().lock(); + let lock = m.lock(); *lock.borrow_mut() += i; } drop(lock); @@ -51,22 +39,17 @@ fn is_mutex() { #[test] fn trylock_works() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an Arc::get_pin_mut. - let mut m = Arc::new(ReentrantMutex::new(())); - Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); - Pin::new_unchecked(m) - }; + let m = Arc::new(ReentrantMutex::new(())); let m2 = m.clone(); - let _lock = m.as_ref().try_lock(); - let _lock2 = m.as_ref().try_lock(); + let _lock = m.try_lock(); + let _lock2 = m.try_lock(); thread::spawn(move || { - let lock = m2.as_ref().try_lock(); + let lock = m2.try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.as_ref().try_lock(); + let _lock3 = m.try_lock(); } pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 70beebe86..032bf604d 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -69,8 +69,10 @@ use crate::sys_common::mutex::StaticMutex; /// ```ignore (cannot-doctest-private-modules) /// use tls::os::{StaticKey, INIT}; /// +/// // Use a regular global static to store the key. /// static KEY: StaticKey = INIT; /// +/// // The state provided via `get` and `set` is thread-local. /// unsafe { /// assert!(KEY.get().is_null()); /// KEY.set(1 as *mut u8); diff --git a/library/std/src/sys_common/thread_local_key/tests.rs b/library/std/src/sys_common/thread_local_key/tests.rs index 968738a41..6f32b858f 100644 --- a/library/std/src/sys_common/thread_local_key/tests.rs +++ b/library/std/src/sys_common/thread_local_key/tests.rs @@ -1,4 +1,5 @@ use super::{Key, StaticKey}; +use core::ptr; fn assert_sync() {} fn assert_send() {} @@ -12,8 +13,8 @@ fn smoke() { let k2 = Key::new(None); assert!(k1.get().is_null()); assert!(k2.get().is_null()); - k1.set(1 as *mut _); - k2.set(2 as *mut _); + k1.set(ptr::invalid_mut(1)); + k2.set(ptr::invalid_mut(2)); assert_eq!(k1.get() as usize, 1); assert_eq!(k2.get() as usize, 2); } @@ -26,8 +27,8 @@ fn statik() { unsafe { assert!(K1.get().is_null()); assert!(K2.get().is_null()); - K1.set(1 as *mut _); - K2.set(2 as *mut _); + K1.set(ptr::invalid_mut(1)); + K2.set(ptr::invalid_mut(2)); assert_eq!(K1.get() as usize, 1); assert_eq!(K2.get() as usize, 2); } diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index cbd7832eb..f86a9a555 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -7,6 +7,7 @@ cfg_if::cfg_if! { target_os = "openbsd", target_os = "dragonfly", target_os = "fuchsia", + target_os = "hermit", ))] { mod futex; pub use futex::Parker; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 57fa49893..dd53767d4 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -89,6 +89,24 @@ impl CodePoint { self.value } + /// Returns the numeric value of the code point if it is a leading surrogate. + #[inline] + pub fn to_lead_surrogate(&self) -> Option { + match self.value { + lead @ 0xD800..=0xDBFF => Some(lead as u16), + _ => None, + } + } + + /// Returns the numeric value of the code point if it is a trailing surrogate. + #[inline] + pub fn to_trail_surrogate(&self) -> Option { + match self.value { + trail @ 0xDC00..=0xDFFF => Some(trail as u16), + _ => None, + } + } + /// Optionally returns a Unicode scalar value for the code point. /// /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). @@ -117,6 +135,14 @@ impl CodePoint { #[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] pub struct Wtf8Buf { bytes: Vec, + + /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily + /// know this if we're constructed from a `String` or `&str`. + /// + /// It is possible for `bytes` to have valid UTF-8 without this being + /// set, such as when we're concatenating `&Wtf8`'s and surrogates become + /// paired, as we don't bother to rescan the entire string. + is_known_utf8: bool, } impl ops::Deref for Wtf8Buf { @@ -147,13 +173,13 @@ impl Wtf8Buf { /// Creates a new, empty WTF-8 string. #[inline] pub fn new() -> Wtf8Buf { - Wtf8Buf { bytes: Vec::new() } + Wtf8Buf { bytes: Vec::new(), is_known_utf8: true } } /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes. #[inline] pub fn with_capacity(capacity: usize) -> Wtf8Buf { - Wtf8Buf { bytes: Vec::with_capacity(capacity) } + Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true } } /// Creates a WTF-8 string from a UTF-8 `String`. @@ -163,7 +189,7 @@ impl Wtf8Buf { /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_string(string: String) -> Wtf8Buf { - Wtf8Buf { bytes: string.into_bytes() } + Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } } /// Creates a WTF-8 string from a UTF-8 `&str` slice. @@ -173,11 +199,12 @@ impl Wtf8Buf { /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_str(str: &str) -> Wtf8Buf { - Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) } + Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()), is_known_utf8: true } } pub fn clear(&mut self) { - self.bytes.clear() + self.bytes.clear(); + self.is_known_utf8 = true; } /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. @@ -193,9 +220,11 @@ impl Wtf8Buf { let surrogate = surrogate.unpaired_surrogate(); // Surrogates are known to be in the code point range. let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) }; + // The string will now contain an unpaired surrogate. + string.is_known_utf8 = false; // Skip the WTF-8 concatenation check, // surrogate pairs are already decoded by decode_utf16 - string.push_code_point_unchecked(code_point) + string.push_code_point_unchecked(code_point); } } } @@ -203,7 +232,7 @@ impl Wtf8Buf { } /// Copied from String::push - /// This does **not** include the WTF-8 concatenation check. + /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { let mut bytes = [0; 4]; let bytes = char::encode_utf8_raw(code_point.value, &mut bytes); @@ -217,6 +246,9 @@ impl Wtf8Buf { #[inline] pub fn as_mut_slice(&mut self) -> &mut Wtf8 { + // Safety: `Wtf8` doesn't expose any way to mutate the bytes that would + // cause them to change from well-formed UTF-8 to ill-formed UTF-8, + // which would break the assumptions of the `is_known_utf8` field. unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } } @@ -236,7 +268,8 @@ impl Wtf8Buf { /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// capacity is already sufficient. This method preserves the contents even + /// if an error occurs. /// /// # Errors /// @@ -313,7 +346,15 @@ impl Wtf8Buf { self.push_char(decode_surrogate_pair(lead, trail)); self.bytes.extend_from_slice(other_without_trail_surrogate); } - _ => self.bytes.extend_from_slice(&other.bytes), + _ => { + // If we'll be pushing a string containing a surrogate, we may + // no longer have UTF-8. + if other.next_surrogate(0).is_some() { + self.is_known_utf8 = false; + } + + self.bytes.extend_from_slice(&other.bytes); + } } } @@ -330,13 +371,19 @@ impl Wtf8Buf { /// like concatenating ill-formed UTF-16 strings effectively would. #[inline] pub fn push(&mut self, code_point: CodePoint) { - if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() { + if let Some(trail) = code_point.to_trail_surrogate() { if let Some(lead) = (&*self).final_lead_surrogate() { let len_without_lead_surrogate = self.len() - 3; self.bytes.truncate(len_without_lead_surrogate); - self.push_char(decode_surrogate_pair(lead, trail as u16)); + self.push_char(decode_surrogate_pair(lead, trail)); return; } + + // We're pushing a trailing surrogate. + self.is_known_utf8 = false; + } else if code_point.to_lead_surrogate().is_some() { + // We're pushing a leading surrogate. + self.is_known_utf8 = false; } // No newly paired surrogates at the boundary. @@ -363,9 +410,10 @@ impl Wtf8Buf { /// (that is, if the string contains surrogates), /// the original WTF-8 string is returned instead. pub fn into_string(self) -> Result { - match self.next_surrogate(0) { - None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }), - Some(_) => Err(self), + if self.is_known_utf8 || self.next_surrogate(0).is_none() { + Ok(unsafe { String::from_utf8_unchecked(self.bytes) }) + } else { + Err(self) } } @@ -375,6 +423,11 @@ impl Wtf8Buf { /// /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�â€) pub fn into_string_lossy(mut self) -> String { + // Fast path: If we already have UTF-8, we can return it immediately. + if self.is_known_utf8 { + return unsafe { String::from_utf8_unchecked(self.bytes) }; + } + let mut pos = 0; loop { match self.next_surrogate(pos) { @@ -397,7 +450,7 @@ impl Wtf8Buf { /// Converts a `Box` into a `Wtf8Buf`. pub fn from_box(boxed: Box) -> Wtf8Buf { let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Wtf8Buf { bytes: bytes.into_vec() } + Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } } } @@ -575,6 +628,11 @@ impl Wtf8 { } } + /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`. + pub fn to_owned(&self) -> Wtf8Buf { + Wtf8Buf { bytes: self.bytes.to_vec(), is_known_utf8: false } + } + /// Lossily converts the string to UTF-8. /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. /// @@ -664,7 +722,8 @@ impl Wtf8 { } pub fn clone_into(&self, buf: &mut Wtf8Buf) { - self.bytes.clone_into(&mut buf.bytes) + buf.is_known_utf8 = false; + self.bytes.clone_into(&mut buf.bytes); } /// Boxes this `Wtf8`. @@ -704,12 +763,12 @@ impl Wtf8 { #[inline] pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } + Wtf8Buf { bytes: self.bytes.to_ascii_lowercase(), is_known_utf8: false } } #[inline] pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } + Wtf8Buf { bytes: self.bytes.to_ascii_uppercase(), is_known_utf8: false } } #[inline] diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs index 931996791..1a302d646 100644 --- a/library/std/src/sys_common/wtf8/tests.rs +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -19,6 +19,36 @@ fn code_point_to_u32() { assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); } +#[test] +fn code_point_to_lead_surrogate() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_lead_surrogate(), None); + assert_eq!(c(0xE9).to_lead_surrogate(), None); + assert_eq!(c(0xD800).to_lead_surrogate(), Some(0xD800)); + assert_eq!(c(0xDBFF).to_lead_surrogate(), Some(0xDBFF)); + assert_eq!(c(0xDC00).to_lead_surrogate(), None); + assert_eq!(c(0xDFFF).to_lead_surrogate(), None); + assert_eq!(c(0x1F4A9).to_lead_surrogate(), None); + assert_eq!(c(0x10FFFF).to_lead_surrogate(), None); +} + +#[test] +fn code_point_to_trail_surrogate() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_trail_surrogate(), None); + assert_eq!(c(0xE9).to_trail_surrogate(), None); + assert_eq!(c(0xD800).to_trail_surrogate(), None); + assert_eq!(c(0xDBFF).to_trail_surrogate(), None); + assert_eq!(c(0xDC00).to_trail_surrogate(), Some(0xDC00)); + assert_eq!(c(0xDFFF).to_trail_surrogate(), Some(0xDFFF)); + assert_eq!(c(0x1F4A9).to_trail_surrogate(), None); + assert_eq!(c(0x10FFFF).to_trail_surrogate(), None); +} + #[test] fn code_point_from_char() { assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); @@ -70,35 +100,66 @@ fn wtf8buf_from_string() { #[test] fn wtf8buf_from_wide() { - assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b""); - assert_eq!( - Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes, - b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9" - ); + let buf = Wtf8Buf::from_wide(&[]); + assert_eq!(buf.bytes, b""); + assert!(buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xDCA9]); + assert_eq!(buf.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]); + assert_eq!(buf.bytes, b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xD800]); + assert_eq!(buf.bytes, b"\xED\xA0\x80"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDBFF]); + assert_eq!(buf.bytes, b"\xED\xAF\xBF"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDC00]); + assert_eq!(buf.bytes, b"\xED\xB0\x80"); + assert!(!buf.is_known_utf8); + + let buf = Wtf8Buf::from_wide(&[0xDFFF]); + assert_eq!(buf.bytes, b"\xED\xBF\xBF"); + assert!(!buf.is_known_utf8); } #[test] fn wtf8buf_push_str() { let mut string = Wtf8Buf::new(); assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); + string.push_str("aé 💩"); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); } #[test] fn wtf8buf_push_char() { let mut string = Wtf8Buf::from_str("aé "); assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert!(string.is_known_utf8); + string.push_char('💩'); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); } #[test] fn wtf8buf_push() { let mut string = Wtf8Buf::from_str("aé "); assert_eq!(string.bytes, b"a\xC3\xA9 "); + assert!(string.is_known_utf8); + string.push(CodePoint::from_char('💩')); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() @@ -106,37 +167,46 @@ fn wtf8buf_push() { let mut string = Wtf8Buf::new(); string.push(c(0xD83D)); // lead + assert!(!string.is_known_utf8); string.push(c(0xDCA9)); // trail assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! let mut string = Wtf8Buf::new(); string.push(c(0xD83D)); // lead + assert!(!string.is_known_utf8); string.push(c(0x20)); // not surrogate string.push(c(0xDCA9)); // trail assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); let mut string = Wtf8Buf::new(); string.push(c(0xD800)); // lead + assert!(!string.is_known_utf8); string.push(c(0xDBFF)); // lead assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); let mut string = Wtf8Buf::new(); string.push(c(0xD800)); // lead + assert!(!string.is_known_utf8); string.push(c(0xE000)); // not surrogate assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); let mut string = Wtf8Buf::new(); string.push(c(0xD7FF)); // not surrogate + assert!(string.is_known_utf8); string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); let mut string = Wtf8Buf::new(); string.push(c(0x61)); // not surrogate, < 3 bytes + assert!(string.is_known_utf8); string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); let mut string = Wtf8Buf::new(); string.push(c(0xDC00)); // trail + assert!(!string.is_known_utf8); assert_eq!(string.bytes, b"\xED\xB0\x80"); } @@ -146,6 +216,7 @@ fn wtf8buf_push_wtf8() { assert_eq!(string.bytes, b"a\xC3\xA9"); string.push_wtf8(Wtf8::from_str(" 💩")); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } @@ -161,37 +232,68 @@ fn wtf8buf_push_wtf8() { string.push_wtf8(w(b" ")); // not surrogate string.push_wtf8(w(b"\xED\xB2\xA9")); // trail assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\x80")); // lead string.push_wtf8(w(b"\xED\xAF\xBF")); // lead assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\x80")); // lead string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate string.push_wtf8(w(b"\xED\xB0\x80")); // trail assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes string.push_wtf8(w(b"\xED\xB0\x80")); // trail assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + assert!(!string.is_known_utf8); let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xB0\x80")); // trail assert_eq!(string.bytes, b"\xED\xB0\x80"); + assert!(!string.is_known_utf8); } #[test] fn wtf8buf_truncate() { let mut string = Wtf8Buf::from_str("aé"); + assert!(string.is_known_utf8); + + string.truncate(3); + assert_eq!(string.bytes, b"a\xC3\xA9"); + assert!(string.is_known_utf8); + string.truncate(1); assert_eq!(string.bytes, b"a"); + assert!(string.is_known_utf8); + + string.truncate(0); + assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); +} + +#[test] +fn wtf8buf_truncate_around_non_bmp() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + + string.truncate(4); + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); + assert!(string.is_known_utf8); + + string.truncate(0); + assert_eq!(string.bytes, b""); + assert!(string.is_known_utf8); } #[test] @@ -208,11 +310,37 @@ fn wtf8buf_truncate_fail_longer() { string.truncate(4); } +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp3() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(3); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp2() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(2); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_splitting_non_bmp1() { + let mut string = Wtf8Buf::from_str("💩"); + assert!(string.is_known_utf8); + string.truncate(1); +} + #[test] fn wtf8buf_into_string() { let mut string = Wtf8Buf::from_str("aé 💩"); + assert!(string.is_known_utf8); assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); string.push(CodePoint::from_u32(0xD800).unwrap()); + assert!(!string.is_known_utf8); assert_eq!(string.clone().into_string(), Err(string)); } @@ -229,15 +357,33 @@ fn wtf8buf_from_iterator() { fn f(values: &[u32]) -> Wtf8Buf { values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() } - assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!( + f(&[0x61, 0xE9, 0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80"); + assert_eq!( + f(&[0xD83D, 0x20, 0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD7FF, 0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0x61, 0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }); } #[test] @@ -251,15 +397,36 @@ fn wtf8buf_extend() { string } - assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + assert_eq!( + e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80"); + assert_eq!( + e(&[0xD83D, 0x20], &[0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD7FF], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0x61], &[0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); } #[test] @@ -407,3 +574,93 @@ fn wtf8_encode_wide_size_hint() { assert_eq!((0, Some(0)), iter.size_hint()); assert!(iter.next().is_none()); } + +#[test] +fn wtf8_clone_into() { + let mut string = Wtf8Buf::new(); + Wtf8::from_str("green").clone_into(&mut string); + assert_eq!(string.bytes, b"green"); + + let mut string = Wtf8Buf::from_str("green"); + Wtf8::from_str("").clone_into(&mut string); + assert_eq!(string.bytes, b""); + + let mut string = Wtf8Buf::from_str("red"); + Wtf8::from_str("green").clone_into(&mut string); + assert_eq!(string.bytes, b"green"); + + let mut string = Wtf8Buf::from_str("green"); + Wtf8::from_str("red").clone_into(&mut string); + assert_eq!(string.bytes, b"red"); + + let mut string = Wtf8Buf::from_str("green"); + assert!(string.is_known_utf8); + unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").clone_into(&mut string) }; + assert_eq!(string.bytes, b"\xED\xA0\x80"); + assert!(!string.is_known_utf8); +} + +#[test] +fn wtf8_to_ascii_lowercase() { + let lowercase = Wtf8::from_str("").to_ascii_lowercase(); + assert_eq!(lowercase.bytes, b""); + + let lowercase = Wtf8::from_str("GrEeN gRaPeS! ðŸ‡").to_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); + + let lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_lowercase() }; + assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); + assert!(!lowercase.is_known_utf8); +} + +#[test] +fn wtf8_to_ascii_uppercase() { + let uppercase = Wtf8::from_str("").to_ascii_uppercase(); + assert_eq!(uppercase.bytes, b""); + + let uppercase = Wtf8::from_str("GrEeN gRaPeS! ðŸ‡").to_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); + + let uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_ascii_uppercase() }; + assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); + assert!(!uppercase.is_known_utf8); +} + +#[test] +fn wtf8_make_ascii_lowercase() { + let mut lowercase = Wtf8Buf::from_str(""); + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b""); + + let mut lowercase = Wtf8Buf::from_str("GrEeN gRaPeS! ðŸ‡"); + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"green grapes! \xf0\x9f\x8d\x87"); + + let mut lowercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + lowercase.make_ascii_lowercase(); + assert_eq!(lowercase.bytes, b"\xED\xA0\x80"); + assert!(!lowercase.is_known_utf8); +} + +#[test] +fn wtf8_make_ascii_uppercase() { + let mut uppercase = Wtf8Buf::from_str(""); + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b""); + + let mut uppercase = Wtf8Buf::from_str("GrEeN gRaPeS! ðŸ‡"); + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"GREEN GRAPES! \xf0\x9f\x8d\x87"); + + let mut uppercase = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + uppercase.make_ascii_uppercase(); + assert_eq!(uppercase.bytes, b"\xED\xA0\x80"); + assert!(!uppercase.is_known_utf8); +} + +#[test] +fn wtf8_to_owned() { + let string = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() }; + assert_eq!(string.bytes, b"\xED\xA0\x80"); + assert!(!string.is_known_utf8); +} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index f4750cdf7..8aedfc4a6 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -1036,6 +1036,7 @@ pub mod fast { } #[doc(hidden)] +#[cfg(not(target_thread_local))] pub mod os { use super::lazy::LazyKeyInner; use crate::cell::Cell; @@ -1044,6 +1045,8 @@ pub mod os { use crate::ptr; use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; + /// Use a regular global static to store this key; the state provided will then be + /// thread-local. pub struct Key { // OS-TLS key that we'll use to key off. os: OsStaticKey, diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 44c8a50fd..ceea6986e 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -116,7 +116,7 @@ //! Threads are able to have associated names for identification purposes. By default, spawned //! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass //! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the -//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used: +//! thread, use [`Thread::name`]. A couple of examples where the name of a thread gets used: //! //! * If a panic occurs in a named thread, the thread name will be printed in the panic message. //! * The thread name is provided to the OS where applicable (e.g., `pthread_setname_np` in @@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut; use crate::str; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::mutex; use crate::sys_common::thread; use crate::sys_common::thread_info; use crate::sys_common::thread_parker::Parker; @@ -193,21 +192,31 @@ pub use scoped::{scope, Scope, ScopedJoinHandle}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{AccessError, LocalKey}; -// The types used by the thread_local! macro to access TLS keys. Note that there -// are two types, the "OS" type and the "fast" type. The OS thread local key -// type is accessed via platform-specific API calls and is slow, while the fast +// Select the type used by the thread_local! macro to access TLS keys. There +// are three types: "static", "fast", "OS". The "OS" thread local key +// type is accessed via platform-specific API calls and is slow, while the "fast" // key type is accessed via code generated via LLVM, where TLS keys are set up -// by the elf linker. Note that the OS TLS type is always available: on macOS -// the standard library is compiled with support for older platform versions -// where fast TLS was not available; end-user code is compiled with fast TLS -// where available, but both are needed. +// by the elf linker. "static" is for single-threaded platforms where a global +// static is sufficient. #[unstable(feature = "libstd_thread_internals", issue = "none")] #[cfg(target_thread_local)] +#[cfg(not(test))] #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; +#[unstable(feature = "libstd_thread_internals", issue = "none")] +#[cfg(target_thread_local)] +#[cfg(test)] // when building for tests, use real std's key +pub use realstd::thread::__FastLocalKeyInner; + +#[unstable(feature = "libstd_thread_internals", issue = "none")] +#[cfg(target_thread_local)] +#[cfg(test)] +pub use self::local::fast::Key as __FastLocalKeyInnerUnused; // we import this anyway to silence 'unused' warnings + #[unstable(feature = "libstd_thread_internals", issue = "none")] #[doc(hidden)] +#[cfg(not(target_thread_local))] pub use self::local::os::Key as __OsLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "none")] #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] @@ -1033,24 +1042,48 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // It is UB to attempt to acquire this mutex reentrantly! - static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); - static mut COUNTER: u64 = 1; - - unsafe { - let guard = GUARD.lock(); - - // If we somehow use up all our bits, panic so that we're not - // covering up subtle bugs of IDs being reused. - if COUNTER == u64::MAX { - drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. - panic!("failed to generate unique thread ID: bitspace exhausted"); - } - - let id = COUNTER; - COUNTER += 1; + #[cold] + fn exhausted() -> ! { + panic!("failed to generate unique thread ID: bitspace exhausted") + } - ThreadId(NonZeroU64::new(id).unwrap()) + cfg_if::cfg_if! { + if #[cfg(target_has_atomic = "64")] { + use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + + static COUNTER: AtomicU64 = AtomicU64::new(0); + + let mut last = COUNTER.load(Relaxed); + loop { + let Some(id) = last.checked_add(1) else { + exhausted(); + }; + + match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()), + Err(id) => last = id, + } + } + } else { + use crate::sys_common::mutex::StaticMutex; + + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: StaticMutex = StaticMutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + let guard = GUARD.lock(); + + let Some(id) = COUNTER.checked_add(1) else { + drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. + exhausted(); + }; + + COUNTER = id; + drop(guard); + ThreadId(NonZeroU64::new(id).unwrap()) + } + } } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index ec68b5291..777964f04 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -37,6 +37,37 @@ fn test_named_thread() { .unwrap(); } +#[cfg(any( + // Note: musl didn't add pthread_getname_np until 1.2.3 + all(target_os = "linux", target_env = "gnu"), + target_os = "macos", + target_os = "ios", + target_os = "watchos" +))] +#[test] +fn test_named_thread_truncation() { + use crate::ffi::CStr; + + let long_name = crate::iter::once("test_named_thread_truncation") + .chain(crate::iter::repeat(" yada").take(100)) + .collect::(); + + let result = Builder::new().name(long_name.clone()).spawn(move || { + // Rust remembers the full thread name itself. + assert_eq!(thread::current().name(), Some(long_name.as_str())); + + // But the system is limited -- make sure we successfully set a truncation. + let mut buf = vec![0u8; long_name.len() + 1]; + unsafe { + libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); + } + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert!(cstr.to_bytes().len() > 0); + assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); + }); + result.unwrap().join().unwrap(); +} + #[test] #[should_panic] fn test_invalid_named_thread() { @@ -329,3 +360,22 @@ fn test_scoped_threads_nll() { let x = 42_u8; foo(&x); } + +// Regression test for https://github.com/rust-lang/rust/issues/98498. +#[test] +#[cfg(miri)] // relies on Miri's data race detector +fn scope_join_race() { + for _ in 0..100 { + let a_bool = AtomicBool::new(false); + + thread::scope(|s| { + for _ in 0..5 { + s.spawn(|| a_bool.load(Ordering::Relaxed)); + } + + for _ in 0..5 { + s.spawn(|| a_bool.load(Ordering::Relaxed)); + } + }); + } +} diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs index d710a5744..6229556c8 100644 --- a/library/std/src/time/tests.rs +++ b/library/std/src/time/tests.rs @@ -31,7 +31,8 @@ fn instant_monotonic_concurrent() -> crate::thread::Result<()> { .map(|_| { crate::thread::spawn(|| { let mut old = Instant::now(); - for _ in 0..5_000_000 { + let count = if cfg!(miri) { 1_000 } else { 5_000_000 }; + for _ in 0..count { let new = Instant::now(); assert!(new >= old); old = new; diff --git a/library/stdarch/CONTRIBUTING.md b/library/stdarch/CONTRIBUTING.md index ebccd73ea..4212abcd7 100644 --- a/library/stdarch/CONTRIBUTING.md +++ b/library/stdarch/CONTRIBUTING.md @@ -9,7 +9,7 @@ $ cd stdarch $ TARGET="" ci/run.sh ``` -Where `` is the target triple as used by `rustup`, e.g. `x86_x64-unknown-linux-gnu` (without any preceding `nightly-` or similar). +Where `` is the target triple as used by `rustup`, e.g. `x86_64-unknown-linux-gnu` (without any preceding `nightly-` or similar). Also remember that this repository requires the nightly channel of Rust! The above tests do in fact require nightly rust to be the default on your system, to set that use `rustup default nightly` (and `rustup default stable` to revert). diff --git a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 49464dacf..2f99999da 100644 --- a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:21.10 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ diff --git a/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 74181a4cb..b4cd0a68a 100644 --- a/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:21.10 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ diff --git a/library/stdarch/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile index 1618db22f..b9b3c682e 100644 --- a/library/stdarch/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:21.10 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y --no-install-recommends \ gcc libc6-dev qemu-user ca-certificates \ diff --git a/library/stdarch/ci/dox.sh b/library/stdarch/ci/dox.sh index e70a32b2d..3e507b456 100755 --- a/library/stdarch/ci/dox.sh +++ b/library/stdarch/ci/dox.sh @@ -22,9 +22,6 @@ dox() { rm -rf "target/doc/${arch}" mkdir "target/doc/${arch}" - export RUSTFLAGS="--cfg core_arch_docs" - export RUSTDOCFLAGS="--cfg core_arch_docs" - cargo build --verbose --target "${target}" --manifest-path crates/core_arch/Cargo.toml cargo build --verbose --target "${target}" --manifest-path crates/std_detect/Cargo.toml @@ -32,16 +29,14 @@ dox() { -o "target/doc/${arch}" crates/core_arch/src/lib.rs \ --edition=2018 \ --crate-name core_arch \ - --library-path "target/${target}/debug/deps" \ - --cfg core_arch_docs + --library-path "target/${target}/debug/deps" rustdoc --verbose --target "${target}" \ -o "target/doc/${arch}" crates/std_detect/src/lib.rs \ --edition=2018 \ --crate-name std_detect \ --library-path "target/${target}/debug/deps" \ --extern cfg_if="$(ls target/"${target}"/debug/deps/libcfg_if-*.rlib)" \ - --extern libc="$(ls target/"${target}"/debug/deps/liblibc-*.rlib)" \ - --cfg core_arch_docs + --extern libc="$(ls target/"${target}"/debug/deps/liblibc-*.rlib)" } dox i686 i686-unknown-linux-gnu diff --git a/library/stdarch/crates/core_arch/Cargo.toml b/library/stdarch/crates/core_arch/Cargo.toml index 14b5479d1..e2b332af2 100644 --- a/library/stdarch/crates/core_arch/Cargo.toml +++ b/library/stdarch/crates/core_arch/Cargo.toml @@ -13,7 +13,6 @@ readme = "README.md" keywords = ["core", "simd", "arch", "intrinsics"] categories = ["hardware-support", "no-std"] license = "MIT OR Apache-2.0" -build = "build.rs" edition = "2018" [badges] diff --git a/library/stdarch/crates/core_arch/build.rs b/library/stdarch/crates/core_arch/build.rs deleted file mode 100644 index 4d65e9ddc..000000000 --- a/library/stdarch/crates/core_arch/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("cargo:rustc-cfg=core_arch_docs"); -} diff --git a/library/stdarch/crates/core_arch/src/aarch64/crc.rs b/library/stdarch/crates/core_arch/src/aarch64/crc.rs index 6e8128534..ac3f8d815 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/crc.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/crc.rs @@ -10,6 +10,8 @@ extern "unadjusted" { use stdarch_test::assert_instr; /// CRC32 single round checksum for quad words (64 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32d) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(test, assert_instr(crc32x))] @@ -18,6 +20,8 @@ pub unsafe fn __crc32d(crc: u32, data: u64) -> u32 { } /// CRC32-C single round checksum for quad words (64 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32cd) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(test, assert_instr(crc32cx))] diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs index 74ea2963c..ac05a0c23 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs @@ -10,6 +10,8 @@ use super::*; use stdarch_test::assert_instr; /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_s8) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -23,6 +25,8 @@ pub unsafe fn veor3q_s8(a: int8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_s16) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -36,6 +40,8 @@ pub unsafe fn veor3q_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_s32) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -49,6 +55,8 @@ pub unsafe fn veor3q_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_s64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -62,6 +70,8 @@ pub unsafe fn veor3q_s64(a: int64x2_t, b: int64x2_t, c: int64x2_t) -> int64x2_t } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_u8) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -75,6 +85,8 @@ pub unsafe fn veor3q_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16 } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_u16) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -88,6 +100,8 @@ pub unsafe fn veor3q_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_u32) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -101,6 +115,8 @@ pub unsafe fn veor3q_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x } /// Three-way exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor3q_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(eor3))] @@ -114,6 +130,8 @@ pub unsafe fn veor3q_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x } /// Absolute difference between the arguments of Floating +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabd))] @@ -128,6 +146,8 @@ pub unsafe fn vabd_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Absolute difference between the arguments of Floating +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabd))] @@ -142,6 +162,8 @@ pub unsafe fn vabdq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point absolute difference +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabds_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabd))] @@ -151,6 +173,8 @@ pub unsafe fn vabds_f32(a: f32, b: f32) -> f32 { } /// Floating-point absolute difference +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabd))] @@ -160,6 +184,8 @@ pub unsafe fn vabdd_f64(a: f64, b: f64) -> f64 { } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabdl))] @@ -171,6 +197,8 @@ pub unsafe fn vabdl_high_u8(a: uint8x16_t, b: uint8x16_t) -> uint16x8_t { } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabdl))] @@ -182,6 +210,8 @@ pub unsafe fn vabdl_high_u16(a: uint16x8_t, b: uint16x8_t) -> uint32x4_t { } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabdl))] @@ -193,6 +223,8 @@ pub unsafe fn vabdl_high_u32(a: uint32x4_t, b: uint32x4_t) -> uint64x2_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabdl))] @@ -205,6 +237,8 @@ pub unsafe fn vabdl_high_s8(a: int8x16_t, b: int8x16_t) -> int16x8_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabdl))] @@ -217,6 +251,8 @@ pub unsafe fn vabdl_high_s16(a: int16x8_t, b: int16x8_t) -> int32x4_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabdl))] @@ -229,6 +265,8 @@ pub unsafe fn vabdl_high_s32(a: int32x4_t, b: int32x4_t) -> int64x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -238,6 +276,8 @@ pub unsafe fn vceq_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -247,6 +287,8 @@ pub unsafe fn vceqq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -256,6 +298,8 @@ pub unsafe fn vceq_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -265,6 +309,8 @@ pub unsafe fn vceqq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -274,6 +320,8 @@ pub unsafe fn vceq_p64(a: poly64x1_t, b: poly64x1_t) -> uint64x1_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -283,6 +331,8 @@ pub unsafe fn vceqq_p64(a: poly64x2_t, b: poly64x2_t) -> uint64x2_t { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -292,6 +342,8 @@ pub unsafe fn vceq_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -301,6 +353,8 @@ pub unsafe fn vceqq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Compare bitwise equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -310,6 +364,8 @@ pub unsafe fn vceqd_s64(a: i64, b: i64) -> u64 { } /// Compare bitwise equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -319,6 +375,8 @@ pub unsafe fn vceqd_u64(a: u64, b: u64) -> u64 { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -328,6 +386,8 @@ pub unsafe fn vceqs_f32(a: f32, b: f32) -> u32 { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -337,6 +397,8 @@ pub unsafe fn vceqd_f64(a: f64, b: f64) -> u64 { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -347,6 +409,8 @@ pub unsafe fn vceqz_s8(a: int8x8_t) -> uint8x8_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -357,6 +421,8 @@ pub unsafe fn vceqzq_s8(a: int8x16_t) -> uint8x16_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -367,6 +433,8 @@ pub unsafe fn vceqz_s16(a: int16x4_t) -> uint16x4_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -377,6 +445,8 @@ pub unsafe fn vceqzq_s16(a: int16x8_t) -> uint16x8_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -387,6 +457,8 @@ pub unsafe fn vceqz_s32(a: int32x2_t) -> uint32x2_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -397,6 +469,8 @@ pub unsafe fn vceqzq_s32(a: int32x4_t) -> uint32x4_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -407,6 +481,8 @@ pub unsafe fn vceqz_s64(a: int64x1_t) -> uint64x1_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -417,6 +493,8 @@ pub unsafe fn vceqzq_s64(a: int64x2_t) -> uint64x2_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -427,6 +505,8 @@ pub unsafe fn vceqz_p8(a: poly8x8_t) -> uint8x8_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -437,6 +517,8 @@ pub unsafe fn vceqzq_p8(a: poly8x16_t) -> uint8x16_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -447,6 +529,8 @@ pub unsafe fn vceqz_p64(a: poly64x1_t) -> uint64x1_t { } /// Signed compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -457,6 +541,8 @@ pub unsafe fn vceqzq_p64(a: poly64x2_t) -> uint64x2_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -467,6 +553,8 @@ pub unsafe fn vceqz_u8(a: uint8x8_t) -> uint8x8_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -477,6 +565,8 @@ pub unsafe fn vceqzq_u8(a: uint8x16_t) -> uint8x16_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -487,6 +577,8 @@ pub unsafe fn vceqz_u16(a: uint16x4_t) -> uint16x4_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -497,6 +589,8 @@ pub unsafe fn vceqzq_u16(a: uint16x8_t) -> uint16x8_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -507,6 +601,8 @@ pub unsafe fn vceqz_u32(a: uint32x2_t) -> uint32x2_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -517,6 +613,8 @@ pub unsafe fn vceqzq_u32(a: uint32x4_t) -> uint32x4_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -527,6 +625,8 @@ pub unsafe fn vceqz_u64(a: uint64x1_t) -> uint64x1_t { } /// Unsigned compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmeq))] @@ -537,6 +637,8 @@ pub unsafe fn vceqzq_u64(a: uint64x2_t) -> uint64x2_t { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -547,6 +649,8 @@ pub unsafe fn vceqz_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -557,6 +661,8 @@ pub unsafe fn vceqzq_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqz_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -567,6 +673,8 @@ pub unsafe fn vceqz_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmeq))] @@ -577,6 +685,8 @@ pub unsafe fn vceqzq_f64(a: float64x2_t) -> uint64x2_t { } /// Compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -586,6 +696,8 @@ pub unsafe fn vceqzd_s64(a: i64) -> u64 { } /// Compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -595,6 +707,8 @@ pub unsafe fn vceqzd_u64(a: u64) -> u64 { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -604,6 +718,8 @@ pub unsafe fn vceqzs_f32(a: f32) -> u32 { } /// Floating-point compare bitwise equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqzd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -613,6 +729,8 @@ pub unsafe fn vceqzd_f64(a: f64) -> u64 { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -624,6 +742,8 @@ pub unsafe fn vtst_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -635,6 +755,8 @@ pub unsafe fn vtstq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -646,6 +768,8 @@ pub unsafe fn vtst_p64(a: poly64x1_t, b: poly64x1_t) -> uint64x1_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -657,6 +781,8 @@ pub unsafe fn vtstq_p64(a: poly64x2_t, b: poly64x2_t) -> uint64x2_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -668,6 +794,8 @@ pub unsafe fn vtst_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmtst))] @@ -679,6 +807,8 @@ pub unsafe fn vtstq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Compare bitwise test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tst))] @@ -688,6 +818,8 @@ pub unsafe fn vtstd_s64(a: i64, b: i64) -> u64 { } /// Compare bitwise test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tst))] @@ -697,6 +829,8 @@ pub unsafe fn vtstd_u64(a: u64, b: u64) -> u64 { } /// Signed saturating accumulate of unsigned value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuqadds_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(suqadd))] @@ -711,6 +845,8 @@ pub unsafe fn vuqadds_s32(a: i32, b: u32) -> i32 { } /// Signed saturating accumulate of unsigned value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuqaddd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(suqadd))] @@ -725,6 +861,8 @@ pub unsafe fn vuqaddd_s64(a: i64, b: u64) -> i64 { } /// Signed saturating accumulate of unsigned value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuqaddb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(suqadd))] @@ -734,6 +872,8 @@ pub unsafe fn vuqaddb_s8(a: i8, b: u8) -> i8 { } /// Signed saturating accumulate of unsigned value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuqaddh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(suqadd))] @@ -743,6 +883,8 @@ pub unsafe fn vuqaddh_s16(a: i16, b: u16) -> i16 { } /// Floating-point absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabs_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabs))] @@ -752,6 +894,8 @@ pub unsafe fn vabs_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabsq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fabs))] @@ -761,6 +905,8 @@ pub unsafe fn vabsq_f64(a: float64x2_t) -> float64x2_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -770,6 +916,8 @@ pub unsafe fn vcgt_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -779,6 +927,8 @@ pub unsafe fn vcgtq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhi))] @@ -788,6 +938,8 @@ pub unsafe fn vcgt_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhi))] @@ -797,6 +949,8 @@ pub unsafe fn vcgtq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -806,6 +960,8 @@ pub unsafe fn vcgt_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -815,6 +971,8 @@ pub unsafe fn vcgtq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -824,6 +982,8 @@ pub unsafe fn vcgtd_s64(a: i64, b: i64) -> u64 { } /// Compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -833,6 +993,8 @@ pub unsafe fn vcgtd_u64(a: u64, b: u64) -> u64 { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgts_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -842,6 +1004,8 @@ pub unsafe fn vcgts_f32(a: f32, b: f32) -> u32 { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -851,6 +1015,8 @@ pub unsafe fn vcgtd_f64(a: f64, b: f64) -> u64 { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -860,6 +1026,8 @@ pub unsafe fn vclt_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -869,6 +1037,8 @@ pub unsafe fn vcltq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhi))] @@ -878,6 +1048,8 @@ pub unsafe fn vclt_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhi))] @@ -887,6 +1059,8 @@ pub unsafe fn vcltq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -896,6 +1070,8 @@ pub unsafe fn vclt_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -905,6 +1081,8 @@ pub unsafe fn vcltq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -914,6 +1092,8 @@ pub unsafe fn vcltd_s64(a: i64, b: i64) -> u64 { } /// Compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -923,6 +1103,8 @@ pub unsafe fn vcltd_u64(a: u64, b: u64) -> u64 { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclts_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -932,6 +1114,8 @@ pub unsafe fn vclts_f32(a: f32, b: f32) -> u32 { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -941,6 +1125,8 @@ pub unsafe fn vcltd_f64(a: f64, b: f64) -> u64 { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -950,6 +1136,8 @@ pub unsafe fn vcle_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -959,6 +1147,8 @@ pub unsafe fn vcleq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcged_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -968,6 +1158,8 @@ pub unsafe fn vcged_s64(a: i64, b: i64) -> u64 { } /// Compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcged_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -977,6 +1169,8 @@ pub unsafe fn vcged_u64(a: u64, b: u64) -> u64 { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcges_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -986,6 +1180,8 @@ pub unsafe fn vcges_f32(a: f32, b: f32) -> u32 { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcged_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -995,6 +1191,8 @@ pub unsafe fn vcged_f64(a: f64, b: f64) -> u64 { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhs))] @@ -1004,6 +1202,8 @@ pub unsafe fn vcle_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhs))] @@ -1013,6 +1213,8 @@ pub unsafe fn vcleq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1022,6 +1224,8 @@ pub unsafe fn vcle_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1031,6 +1235,8 @@ pub unsafe fn vcleq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcled_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -1040,6 +1246,8 @@ pub unsafe fn vcled_s64(a: i64, b: i64) -> u64 { } /// Compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcled_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -1049,6 +1257,8 @@ pub unsafe fn vcled_u64(a: u64, b: u64) -> u64 { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcles_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1058,6 +1268,8 @@ pub unsafe fn vcles_f32(a: f32, b: f32) -> u32 { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcled_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1067,6 +1279,8 @@ pub unsafe fn vcled_f64(a: f64, b: f64) -> u64 { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1076,6 +1290,8 @@ pub unsafe fn vcge_s64(a: int64x1_t, b: int64x1_t) -> uint64x1_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1085,6 +1301,8 @@ pub unsafe fn vcgeq_s64(a: int64x2_t, b: int64x2_t) -> uint64x2_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhs))] @@ -1094,6 +1312,8 @@ pub unsafe fn vcge_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmhs))] @@ -1103,6 +1323,8 @@ pub unsafe fn vcgeq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1112,6 +1334,8 @@ pub unsafe fn vcge_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1121,6 +1345,8 @@ pub unsafe fn vcgeq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1131,6 +1357,8 @@ pub unsafe fn vcgez_s8(a: int8x8_t) -> uint8x8_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1141,6 +1369,8 @@ pub unsafe fn vcgezq_s8(a: int8x16_t) -> uint8x16_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1151,6 +1381,8 @@ pub unsafe fn vcgez_s16(a: int16x4_t) -> uint16x4_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1161,6 +1393,8 @@ pub unsafe fn vcgezq_s16(a: int16x8_t) -> uint16x8_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1171,6 +1405,8 @@ pub unsafe fn vcgez_s32(a: int32x2_t) -> uint32x2_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1181,6 +1417,8 @@ pub unsafe fn vcgezq_s32(a: int32x4_t) -> uint32x4_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1191,6 +1429,8 @@ pub unsafe fn vcgez_s64(a: int64x1_t) -> uint64x1_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmge))] @@ -1201,6 +1441,8 @@ pub unsafe fn vcgezq_s64(a: int64x2_t) -> uint64x2_t { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1211,6 +1453,8 @@ pub unsafe fn vcgez_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1221,6 +1465,8 @@ pub unsafe fn vcgezq_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgez_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1231,6 +1477,8 @@ pub unsafe fn vcgez_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmge))] @@ -1241,6 +1489,8 @@ pub unsafe fn vcgezq_f64(a: float64x2_t) -> uint64x2_t { } /// Compare signed greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(eor))] @@ -1250,6 +1500,8 @@ pub unsafe fn vcgezd_s64(a: i64) -> u64 { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1259,6 +1511,8 @@ pub unsafe fn vcgezs_f32(a: f32) -> u32 { } /// Floating-point compare greater than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgezd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1268,6 +1522,8 @@ pub unsafe fn vcgezd_f64(a: f64) -> u64 { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1278,6 +1534,8 @@ pub unsafe fn vcgtz_s8(a: int8x8_t) -> uint8x8_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1288,6 +1546,8 @@ pub unsafe fn vcgtzq_s8(a: int8x16_t) -> uint8x16_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1298,6 +1558,8 @@ pub unsafe fn vcgtz_s16(a: int16x4_t) -> uint16x4_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1308,6 +1570,8 @@ pub unsafe fn vcgtzq_s16(a: int16x8_t) -> uint16x8_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1318,6 +1582,8 @@ pub unsafe fn vcgtz_s32(a: int32x2_t) -> uint32x2_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1328,6 +1594,8 @@ pub unsafe fn vcgtzq_s32(a: int32x4_t) -> uint32x4_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1338,6 +1606,8 @@ pub unsafe fn vcgtz_s64(a: int64x1_t) -> uint64x1_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1348,6 +1618,8 @@ pub unsafe fn vcgtzq_s64(a: int64x2_t) -> uint64x2_t { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -1358,6 +1630,8 @@ pub unsafe fn vcgtz_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -1368,6 +1642,8 @@ pub unsafe fn vcgtzq_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtz_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -1378,6 +1654,8 @@ pub unsafe fn vcgtz_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmgt))] @@ -1388,6 +1666,8 @@ pub unsafe fn vcgtzq_f64(a: float64x2_t) -> uint64x2_t { } /// Compare signed greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -1397,6 +1677,8 @@ pub unsafe fn vcgtzd_s64(a: i64) -> u64 { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1406,6 +1688,8 @@ pub unsafe fn vcgtzs_f32(a: f32) -> u32 { } /// Floating-point compare greater than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtzd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1415,6 +1699,8 @@ pub unsafe fn vcgtzd_f64(a: f64) -> u64 { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1425,6 +1711,8 @@ pub unsafe fn vclez_s8(a: int8x8_t) -> uint8x8_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1435,6 +1723,8 @@ pub unsafe fn vclezq_s8(a: int8x16_t) -> uint8x16_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1445,6 +1735,8 @@ pub unsafe fn vclez_s16(a: int16x4_t) -> uint16x4_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1455,6 +1747,8 @@ pub unsafe fn vclezq_s16(a: int16x8_t) -> uint16x8_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1465,6 +1759,8 @@ pub unsafe fn vclez_s32(a: int32x2_t) -> uint32x2_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1475,6 +1771,8 @@ pub unsafe fn vclezq_s32(a: int32x4_t) -> uint32x4_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1485,6 +1783,8 @@ pub unsafe fn vclez_s64(a: int64x1_t) -> uint64x1_t { } /// Compare signed less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmgt))] @@ -1495,6 +1795,8 @@ pub unsafe fn vclezq_s64(a: int64x2_t) -> uint64x2_t { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmle))] @@ -1505,6 +1807,8 @@ pub unsafe fn vclez_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmle))] @@ -1515,6 +1819,8 @@ pub unsafe fn vclezq_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclez_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmle))] @@ -1525,6 +1831,8 @@ pub unsafe fn vclez_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmle))] @@ -1535,6 +1843,8 @@ pub unsafe fn vclezq_f64(a: float64x2_t) -> uint64x2_t { } /// Compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmp))] @@ -1544,6 +1854,8 @@ pub unsafe fn vclezd_s64(a: i64) -> u64 { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1553,6 +1865,8 @@ pub unsafe fn vclezs_f32(a: f32) -> u32 { } /// Floating-point compare less than or equal to zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclezd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1562,6 +1876,8 @@ pub unsafe fn vclezd_f64(a: f64) -> u64 { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1572,6 +1888,8 @@ pub unsafe fn vcltz_s8(a: int8x8_t) -> uint8x8_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1582,6 +1900,8 @@ pub unsafe fn vcltzq_s8(a: int8x16_t) -> uint8x16_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1592,6 +1912,8 @@ pub unsafe fn vcltz_s16(a: int16x4_t) -> uint16x4_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1602,6 +1924,8 @@ pub unsafe fn vcltzq_s16(a: int16x8_t) -> uint16x8_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1612,6 +1936,8 @@ pub unsafe fn vcltz_s32(a: int32x2_t) -> uint32x2_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1622,6 +1948,8 @@ pub unsafe fn vcltzq_s32(a: int32x4_t) -> uint32x4_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1632,6 +1960,8 @@ pub unsafe fn vcltz_s64(a: int64x1_t) -> uint64x1_t { } /// Compare signed less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(cmlt))] @@ -1642,6 +1972,8 @@ pub unsafe fn vcltzq_s64(a: int64x2_t) -> uint64x2_t { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmlt))] @@ -1652,6 +1984,8 @@ pub unsafe fn vcltz_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmlt))] @@ -1662,6 +1996,8 @@ pub unsafe fn vcltzq_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltz_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmlt))] @@ -1672,6 +2008,8 @@ pub unsafe fn vcltz_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmlt))] @@ -1682,6 +2020,8 @@ pub unsafe fn vcltzq_f64(a: float64x2_t) -> uint64x2_t { } /// Compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(asr))] @@ -1691,6 +2031,8 @@ pub unsafe fn vcltzd_s64(a: i64) -> u64 { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1700,6 +2042,8 @@ pub unsafe fn vcltzs_f32(a: f32) -> u32 { } /// Floating-point compare less than zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltzd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcmp))] @@ -1709,6 +2053,8 @@ pub unsafe fn vcltzd_f64(a: f64) -> u64 { } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagt_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1723,6 +2069,8 @@ pub unsafe fn vcagt_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagtq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1737,6 +2085,8 @@ pub unsafe fn vcagtq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagts_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1751,6 +2101,8 @@ pub unsafe fn vcagts_f32(a: f32, b: f32) -> u32 { } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagtd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1765,6 +2117,8 @@ pub unsafe fn vcagtd_f64(a: f64, b: f64) -> u64 { } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcage_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1779,6 +2133,8 @@ pub unsafe fn vcage_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcageq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1793,6 +2149,8 @@ pub unsafe fn vcageq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcages_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1807,6 +2165,8 @@ pub unsafe fn vcages_f32(a: f32, b: f32) -> u32 { } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaged_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1821,6 +2181,8 @@ pub unsafe fn vcaged_f64(a: f64, b: f64) -> u64 { } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcalt_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1830,6 +2192,8 @@ pub unsafe fn vcalt_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaltq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1839,6 +2203,8 @@ pub unsafe fn vcaltq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcalts_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1848,6 +2214,8 @@ pub unsafe fn vcalts_f32(a: f32, b: f32) -> u32 { } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaltd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facgt))] @@ -1857,6 +2225,8 @@ pub unsafe fn vcaltd_f64(a: f64, b: f64) -> u64 { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcale_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1866,6 +2236,8 @@ pub unsafe fn vcale_f64(a: float64x1_t, b: float64x1_t) -> uint64x1_t { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaleq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1875,6 +2247,8 @@ pub unsafe fn vcaleq_f64(a: float64x2_t, b: float64x2_t) -> uint64x2_t { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcales_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1884,6 +2258,8 @@ pub unsafe fn vcales_f32(a: f32, b: f32) -> u32 { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaled_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(facge))] @@ -1893,6 +2269,8 @@ pub unsafe fn vcaled_f64(a: f64, b: f64) -> u64 { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -1915,6 +2293,8 @@ pub unsafe fn vcopy_lane_s8(a: int8x8_t, b: } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -1945,6 +2325,8 @@ pub unsafe fn vcopyq_laneq_s8(a: int8x16_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -1963,6 +2345,8 @@ pub unsafe fn vcopy_lane_s16(a: int16x4_t, b } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -1985,6 +2369,8 @@ pub unsafe fn vcopyq_laneq_s16(a: int16x8_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2001,6 +2387,8 @@ pub unsafe fn vcopy_lane_s32(a: int32x2_t, b } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2019,6 +2407,8 @@ pub unsafe fn vcopyq_laneq_s32(a: int32x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2035,6 +2425,8 @@ pub unsafe fn vcopyq_laneq_s64(a: int64x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2057,6 +2449,8 @@ pub unsafe fn vcopy_lane_u8(a: uint8x8_t, b: } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2087,6 +2481,8 @@ pub unsafe fn vcopyq_laneq_u8(a: uint8x16_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2105,6 +2501,8 @@ pub unsafe fn vcopy_lane_u16(a: uint16x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2127,6 +2525,8 @@ pub unsafe fn vcopyq_laneq_u16(a: uint16x8_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2143,6 +2543,8 @@ pub unsafe fn vcopy_lane_u32(a: uint32x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2161,6 +2563,8 @@ pub unsafe fn vcopyq_laneq_u32(a: uint32x4_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2177,6 +2581,8 @@ pub unsafe fn vcopyq_laneq_u64(a: uint64x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2199,6 +2605,8 @@ pub unsafe fn vcopy_lane_p8(a: poly8x8_t, b: } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2229,6 +2637,8 @@ pub unsafe fn vcopyq_laneq_p8(a: poly8x16_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2247,6 +2657,8 @@ pub unsafe fn vcopy_lane_p16(a: poly16x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2269,6 +2681,8 @@ pub unsafe fn vcopyq_laneq_p16(a: poly16x8_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2285,6 +2699,8 @@ pub unsafe fn vcopyq_laneq_p64(a: poly64x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2301,6 +2717,8 @@ pub unsafe fn vcopy_lane_f32(a: float32x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2319,6 +2737,8 @@ pub unsafe fn vcopyq_laneq_f32(a: float32x4_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2335,6 +2755,8 @@ pub unsafe fn vcopyq_laneq_f64(a: float64x2_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2358,6 +2780,8 @@ pub unsafe fn vcopy_laneq_s8(a: int8x8_t, b: } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2377,6 +2801,8 @@ pub unsafe fn vcopy_laneq_s16(a: int16x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2394,6 +2820,8 @@ pub unsafe fn vcopy_laneq_s32(a: int32x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2417,6 +2845,8 @@ pub unsafe fn vcopy_laneq_u8(a: uint8x8_t, b } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2436,6 +2866,8 @@ pub unsafe fn vcopy_laneq_u16(a: uint16x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2453,6 +2885,8 @@ pub unsafe fn vcopy_laneq_u32(a: uint32x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2476,6 +2910,8 @@ pub unsafe fn vcopy_laneq_p8(a: poly8x8_t, b } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2495,6 +2931,8 @@ pub unsafe fn vcopy_laneq_p16(a: poly16x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopy_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2512,6 +2950,8 @@ pub unsafe fn vcopy_laneq_f32(a: float32x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2543,6 +2983,8 @@ pub unsafe fn vcopyq_lane_s8(a: int8x16_t, b } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2566,6 +3008,8 @@ pub unsafe fn vcopyq_lane_s16(a: int16x8_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2585,6 +3029,8 @@ pub unsafe fn vcopyq_lane_s32(a: int32x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2616,6 +3062,8 @@ pub unsafe fn vcopyq_lane_u8(a: uint8x16_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2639,6 +3087,8 @@ pub unsafe fn vcopyq_lane_u16(a: uint16x8_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2658,6 +3108,8 @@ pub unsafe fn vcopyq_lane_u32(a: uint32x4_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2689,6 +3141,8 @@ pub unsafe fn vcopyq_lane_p8(a: poly8x16_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 0, LANE2 = 1))] @@ -2712,6 +3166,8 @@ pub unsafe fn vcopyq_lane_p16(a: poly16x8_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 1, LANE2 = 0))] @@ -2729,6 +3185,8 @@ pub unsafe fn vcopyq_lane_s64(a: int64x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 1, LANE2 = 0))] @@ -2746,6 +3204,8 @@ pub unsafe fn vcopyq_lane_u64(a: uint64x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 1, LANE2 = 0))] @@ -2763,6 +3223,8 @@ pub unsafe fn vcopyq_lane_p64(a: poly64x2_t, } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 1, LANE2 = 0))] @@ -2782,6 +3244,8 @@ pub unsafe fn vcopyq_lane_f32(a: float32x4_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcopyq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(mov, LANE1 = 1, LANE2 = 0))] @@ -2799,6 +3263,8 @@ pub unsafe fn vcopyq_lane_f64(a: float64x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -2808,6 +3274,8 @@ pub unsafe fn vcreate_f64(a: u64) -> float64x1_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf))] @@ -2817,6 +3285,8 @@ pub unsafe fn vcvt_f64_s64(a: int64x1_t) -> float64x1_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf))] @@ -2826,6 +3296,8 @@ pub unsafe fn vcvtq_f64_s64(a: int64x2_t) -> float64x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf))] @@ -2835,6 +3307,8 @@ pub unsafe fn vcvt_f64_u64(a: uint64x1_t) -> float64x1_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf))] @@ -2844,6 +3318,8 @@ pub unsafe fn vcvtq_f64_u64(a: uint64x2_t) -> float64x2_t { } /// Floating-point convert to higher precision long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtl))] @@ -2853,6 +3329,8 @@ pub unsafe fn vcvt_f64_f32(a: float32x2_t) -> float64x2_t { } /// Floating-point convert to higher precision long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_high_f64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtl))] @@ -2863,6 +3341,8 @@ pub unsafe fn vcvt_high_f64_f32(a: float32x4_t) -> float64x2_t { } /// Floating-point convert to lower precision narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtn))] @@ -2872,6 +3352,8 @@ pub unsafe fn vcvt_f32_f64(a: float64x2_t) -> float32x2_t { } /// Floating-point convert to lower precision narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_high_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtn))] @@ -2881,6 +3363,8 @@ pub unsafe fn vcvt_high_f32_f64(a: float32x2_t, b: float64x2_t) -> float32x4_t { } /// Floating-point convert to lower precision narrow, rounding to odd +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtx_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtxn))] @@ -2895,6 +3379,8 @@ pub unsafe fn vcvtx_f32_f64(a: float64x2_t) -> float32x2_t { } /// Floating-point convert to lower precision narrow, rounding to odd +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtxd_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtxn))] @@ -2904,6 +3390,8 @@ pub unsafe fn vcvtxd_f32_f64(a: f64) -> f32 { } /// Floating-point convert to lower precision narrow, rounding to odd +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtx_high_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtxn))] @@ -2913,6 +3401,8 @@ pub unsafe fn vcvtx_high_f32_f64(a: float32x2_t, b: float64x2_t) -> float32x4_t } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf, N = 2))] @@ -2929,6 +3419,8 @@ pub unsafe fn vcvt_n_f64_s64(a: int64x1_t) -> float64x1_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf, N = 2))] @@ -2945,6 +3437,8 @@ pub unsafe fn vcvtq_n_f64_s64(a: int64x2_t) -> float64x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_n_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf, N = 2))] @@ -2961,6 +3455,8 @@ pub unsafe fn vcvts_n_f32_s32(a: i32) -> f32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_n_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf, N = 2))] @@ -2977,6 +3473,8 @@ pub unsafe fn vcvtd_n_f64_s64(a: i64) -> f64 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf, N = 2))] @@ -2993,6 +3491,8 @@ pub unsafe fn vcvt_n_f64_u64(a: uint64x1_t) -> float64x1_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf, N = 2))] @@ -3009,6 +3509,8 @@ pub unsafe fn vcvtq_n_f64_u64(a: uint64x2_t) -> float64x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_n_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf, N = 2))] @@ -3025,6 +3527,8 @@ pub unsafe fn vcvts_n_f32_u32(a: u32) -> f32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_n_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf, N = 2))] @@ -3041,6 +3545,8 @@ pub unsafe fn vcvtd_n_f64_u64(a: u64) -> f64 { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs, N = 2))] @@ -3057,6 +3563,8 @@ pub unsafe fn vcvt_n_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs, N = 2))] @@ -3073,6 +3581,8 @@ pub unsafe fn vcvtq_n_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_n_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs, N = 2))] @@ -3089,6 +3599,8 @@ pub unsafe fn vcvts_n_s32_f32(a: f32) -> i32 { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_n_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs, N = 2))] @@ -3105,6 +3617,8 @@ pub unsafe fn vcvtd_n_s64_f64(a: f64) -> i64 { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu, N = 2))] @@ -3121,6 +3635,8 @@ pub unsafe fn vcvt_n_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu, N = 2))] @@ -3137,6 +3653,8 @@ pub unsafe fn vcvtq_n_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_n_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu, N = 2))] @@ -3153,6 +3671,8 @@ pub unsafe fn vcvts_n_u32_f32(a: f32) -> u32 { } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_n_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu, N = 2))] @@ -3169,6 +3689,8 @@ pub unsafe fn vcvtd_n_u64_f64(a: f64) -> u64 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf))] @@ -3178,6 +3700,8 @@ pub unsafe fn vcvts_f32_s32(a: i32) -> f32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(scvtf))] @@ -3187,6 +3711,8 @@ pub unsafe fn vcvtd_f64_s64(a: i64) -> f64 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf))] @@ -3196,6 +3722,8 @@ pub unsafe fn vcvts_f32_u32(a: u32) -> f32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ucvtf))] @@ -3205,6 +3733,8 @@ pub unsafe fn vcvtd_f64_u64(a: u64) -> f64 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs))] @@ -3214,6 +3744,8 @@ pub unsafe fn vcvts_s32_f32(a: f32) -> i32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs))] @@ -3223,6 +3755,8 @@ pub unsafe fn vcvtd_s64_f64(a: f64) -> i64 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvts_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu))] @@ -3232,6 +3766,8 @@ pub unsafe fn vcvts_u32_f32(a: f32) -> u32 { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtd_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu))] @@ -3241,6 +3777,8 @@ pub unsafe fn vcvtd_u64_f64(a: f64) -> u64 { } /// Floating-point convert to signed fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs))] @@ -3255,6 +3793,8 @@ pub unsafe fn vcvt_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to signed fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzs))] @@ -3269,6 +3809,8 @@ pub unsafe fn vcvtq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to unsigned fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu))] @@ -3283,6 +3825,8 @@ pub unsafe fn vcvt_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to unsigned fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtzu))] @@ -3297,6 +3841,8 @@ pub unsafe fn vcvtq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvta_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3311,6 +3857,8 @@ pub unsafe fn vcvta_s32_f32(a: float32x2_t) -> int32x2_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtaq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3325,6 +3873,8 @@ pub unsafe fn vcvtaq_s32_f32(a: float32x4_t) -> int32x4_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvta_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3339,6 +3889,8 @@ pub unsafe fn vcvta_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtaq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3353,6 +3905,8 @@ pub unsafe fn vcvtaq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtas_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3367,6 +3921,8 @@ pub unsafe fn vcvtas_s32_f32(a: f32) -> i32 { } /// Floating-point convert to integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtad_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtas))] @@ -3381,6 +3937,8 @@ pub unsafe fn vcvtad_s64_f64(a: f64) -> i64 { } /// Floating-point convert to integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtas_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3395,6 +3953,8 @@ pub unsafe fn vcvtas_u32_f32(a: f32) -> u32 { } /// Floating-point convert to integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtad_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3409,6 +3969,8 @@ pub unsafe fn vcvtad_u64_f64(a: f64) -> u64 { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtn_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3423,6 +3985,8 @@ pub unsafe fn vcvtn_s32_f32(a: float32x2_t) -> int32x2_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3437,6 +4001,8 @@ pub unsafe fn vcvtnq_s32_f32(a: float32x4_t) -> int32x4_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtn_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3451,6 +4017,8 @@ pub unsafe fn vcvtn_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3465,6 +4033,8 @@ pub unsafe fn vcvtnq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtns_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3479,6 +4049,8 @@ pub unsafe fn vcvtns_s32_f32(a: f32) -> i32 { } /// Floating-point convert to signed integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnd_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtns))] @@ -3493,6 +4065,8 @@ pub unsafe fn vcvtnd_s64_f64(a: f64) -> i64 { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtm_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3507,6 +4081,8 @@ pub unsafe fn vcvtm_s32_f32(a: float32x2_t) -> int32x2_t { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3521,6 +4097,8 @@ pub unsafe fn vcvtmq_s32_f32(a: float32x4_t) -> int32x4_t { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtm_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3535,6 +4113,8 @@ pub unsafe fn vcvtm_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3549,6 +4129,8 @@ pub unsafe fn vcvtmq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtms_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3563,6 +4145,8 @@ pub unsafe fn vcvtms_s32_f32(a: f32) -> i32 { } /// Floating-point convert to signed integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmd_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtms))] @@ -3577,6 +4161,8 @@ pub unsafe fn vcvtmd_s64_f64(a: f64) -> i64 { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtp_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3591,6 +4177,8 @@ pub unsafe fn vcvtp_s32_f32(a: float32x2_t) -> int32x2_t { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3605,6 +4193,8 @@ pub unsafe fn vcvtpq_s32_f32(a: float32x4_t) -> int32x4_t { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtp_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3619,6 +4209,8 @@ pub unsafe fn vcvtp_s64_f64(a: float64x1_t) -> int64x1_t { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3633,6 +4225,8 @@ pub unsafe fn vcvtpq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtps_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3647,6 +4241,8 @@ pub unsafe fn vcvtps_s32_f32(a: f32) -> i32 { } /// Floating-point convert to signed integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpd_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtps))] @@ -3661,6 +4257,8 @@ pub unsafe fn vcvtpd_s64_f64(a: f64) -> i64 { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvta_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3675,6 +4273,8 @@ pub unsafe fn vcvta_u32_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtaq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3689,6 +4289,8 @@ pub unsafe fn vcvtaq_u32_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvta_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3703,6 +4305,8 @@ pub unsafe fn vcvta_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtaq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtau))] @@ -3717,6 +4321,8 @@ pub unsafe fn vcvtaq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtn_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3731,6 +4337,8 @@ pub unsafe fn vcvtn_u32_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3745,6 +4353,8 @@ pub unsafe fn vcvtnq_u32_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtn_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3759,6 +4369,8 @@ pub unsafe fn vcvtn_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3773,6 +4385,8 @@ pub unsafe fn vcvtnq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtns_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3787,6 +4401,8 @@ pub unsafe fn vcvtns_u32_f32(a: f32) -> u32 { } /// Floating-point convert to unsigned integer, rounding to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtnd_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtnu))] @@ -3801,6 +4417,8 @@ pub unsafe fn vcvtnd_u64_f64(a: f64) -> u64 { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtm_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3815,6 +4433,8 @@ pub unsafe fn vcvtm_u32_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3829,6 +4449,8 @@ pub unsafe fn vcvtmq_u32_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtm_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3843,6 +4465,8 @@ pub unsafe fn vcvtm_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3857,6 +4481,8 @@ pub unsafe fn vcvtmq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtms_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3871,6 +4497,8 @@ pub unsafe fn vcvtms_u32_f32(a: f32) -> u32 { } /// Floating-point convert to unsigned integer, rounding toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtmd_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtmu))] @@ -3885,6 +4513,8 @@ pub unsafe fn vcvtmd_u64_f64(a: f64) -> u64 { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtp_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3899,6 +4529,8 @@ pub unsafe fn vcvtp_u32_f32(a: float32x2_t) -> uint32x2_t { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3913,6 +4545,8 @@ pub unsafe fn vcvtpq_u32_f32(a: float32x4_t) -> uint32x4_t { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtp_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3927,6 +4561,8 @@ pub unsafe fn vcvtp_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3941,6 +4577,8 @@ pub unsafe fn vcvtpq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtps_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3955,6 +4593,8 @@ pub unsafe fn vcvtps_u32_f32(a: f32) -> u32 { } /// Floating-point convert to unsigned integer, rounding toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtpd_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fcvtpu))] @@ -3969,6 +4609,8 @@ pub unsafe fn vcvtpd_u64_f64(a: f64) -> u64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(dup, N = 1))] @@ -3980,6 +4622,8 @@ pub unsafe fn vdupq_laneq_p64(a: poly64x2_t) -> poly64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(dup, N = 0))] @@ -3991,6 +4635,8 @@ pub unsafe fn vdupq_lane_p64(a: poly64x1_t) -> poly64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(dup, N = 1))] @@ -4002,6 +4648,8 @@ pub unsafe fn vdupq_laneq_f64(a: float64x2_t) -> float64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(dup, N = 0))] @@ -4013,6 +4661,8 @@ pub unsafe fn vdupq_lane_f64(a: float64x1_t) -> float64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 0))] @@ -4024,6 +4674,8 @@ pub unsafe fn vdup_lane_p64(a: poly64x1_t) -> poly64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 0))] @@ -4035,6 +4687,8 @@ pub unsafe fn vdup_lane_f64(a: float64x1_t) -> float64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4046,6 +4700,8 @@ pub unsafe fn vdup_laneq_p64(a: poly64x2_t) -> poly64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4057,6 +4713,8 @@ pub unsafe fn vdup_laneq_f64(a: float64x2_t) -> float64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4068,6 +4726,8 @@ pub unsafe fn vdupb_lane_s8(a: int8x8_t) -> i8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_laneq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 8))] @@ -4079,6 +4739,8 @@ pub unsafe fn vdupb_laneq_s8(a: int8x16_t) -> i8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4090,6 +4752,8 @@ pub unsafe fn vduph_lane_s16(a: int16x4_t) -> i16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4101,6 +4765,8 @@ pub unsafe fn vduph_laneq_s16(a: int16x8_t) -> i16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4112,6 +4778,8 @@ pub unsafe fn vdups_lane_s32(a: int32x2_t) -> i32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4123,6 +4791,8 @@ pub unsafe fn vdups_laneq_s32(a: int32x4_t) -> i32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 0))] @@ -4134,6 +4804,8 @@ pub unsafe fn vdupd_lane_s64(a: int64x1_t) -> i64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_laneq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4145,6 +4817,8 @@ pub unsafe fn vdupd_laneq_s64(a: int64x2_t) -> i64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4156,6 +4830,8 @@ pub unsafe fn vdupb_lane_u8(a: uint8x8_t) -> u8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_laneq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 8))] @@ -4167,6 +4843,8 @@ pub unsafe fn vdupb_laneq_u8(a: uint8x16_t) -> u8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4178,6 +4856,8 @@ pub unsafe fn vduph_lane_u16(a: uint16x4_t) -> u16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4189,6 +4869,8 @@ pub unsafe fn vduph_laneq_u16(a: uint16x8_t) -> u16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4200,6 +4882,8 @@ pub unsafe fn vdups_lane_u32(a: uint32x2_t) -> u32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4211,6 +4895,8 @@ pub unsafe fn vdups_laneq_u32(a: uint32x4_t) -> u32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 0))] @@ -4222,6 +4908,8 @@ pub unsafe fn vdupd_lane_u64(a: uint64x1_t) -> u64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_laneq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4233,6 +4921,8 @@ pub unsafe fn vdupd_laneq_u64(a: uint64x2_t) -> u64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4244,6 +4934,8 @@ pub unsafe fn vdupb_lane_p8(a: poly8x8_t) -> p8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupb_laneq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 8))] @@ -4255,6 +4947,8 @@ pub unsafe fn vdupb_laneq_p8(a: poly8x16_t) -> p8 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4266,6 +4960,8 @@ pub unsafe fn vduph_lane_p16(a: poly16x4_t) -> p16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vduph_laneq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 4))] @@ -4277,6 +4973,8 @@ pub unsafe fn vduph_laneq_p16(a: poly16x8_t) -> p16 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4288,6 +4986,8 @@ pub unsafe fn vdups_lane_f32(a: float32x2_t) -> f32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdups_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 2))] @@ -4299,6 +4999,8 @@ pub unsafe fn vdups_laneq_f32(a: float32x4_t) -> f32 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 0))] @@ -4310,6 +5012,8 @@ pub unsafe fn vdupd_lane_f64(a: float64x1_t) -> f64 { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupd_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, N = 1))] @@ -4321,6 +5025,8 @@ pub unsafe fn vdupd_laneq_f64(a: float64x2_t) -> f64 { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ext, N = 1))] @@ -4336,6 +5042,8 @@ pub unsafe fn vextq_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_ } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ext, N = 1))] @@ -4351,6 +5059,8 @@ pub unsafe fn vextq_f64(a: float64x2_t, b: float64x2_t) -> float64 } /// Floating-point multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -4360,6 +5070,8 @@ pub unsafe fn vmla_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float6 } /// Floating-point multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -4369,6 +5081,8 @@ pub unsafe fn vmlaq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2))] @@ -4380,6 +5094,8 @@ pub unsafe fn vmlal_high_s8(a: int16x8_t, b: int8x16_t, c: int8x16_t) -> int16x8 } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2))] @@ -4391,6 +5107,8 @@ pub unsafe fn vmlal_high_s16(a: int32x4_t, b: int16x8_t, c: int16x8_t) -> int32x } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2))] @@ -4402,6 +5120,8 @@ pub unsafe fn vmlal_high_s32(a: int64x2_t, b: int32x4_t, c: int32x4_t) -> int64x } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2))] @@ -4413,6 +5133,8 @@ pub unsafe fn vmlal_high_u8(a: uint16x8_t, b: uint8x16_t, c: uint8x16_t) -> uint } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2))] @@ -4424,6 +5146,8 @@ pub unsafe fn vmlal_high_u16(a: uint32x4_t, b: uint16x8_t, c: uint16x8_t) -> uin } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2))] @@ -4435,6 +5159,8 @@ pub unsafe fn vmlal_high_u32(a: uint64x2_t, b: uint32x4_t, c: uint32x4_t) -> uin } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2))] @@ -4444,6 +5170,8 @@ pub unsafe fn vmlal_high_n_s16(a: int32x4_t, b: int16x8_t, c: i16) -> int32x4_t } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2))] @@ -4453,6 +5181,8 @@ pub unsafe fn vmlal_high_n_s32(a: int64x2_t, b: int32x4_t, c: i32) -> int64x2_t } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2))] @@ -4462,6 +5192,8 @@ pub unsafe fn vmlal_high_n_u16(a: uint32x4_t, b: uint16x8_t, c: u16) -> uint32x4 } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2))] @@ -4471,6 +5203,8 @@ pub unsafe fn vmlal_high_n_u32(a: uint64x2_t, b: uint32x4_t, c: u32) -> uint64x2 } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2, LANE = 1))] @@ -4482,6 +5216,8 @@ pub unsafe fn vmlal_high_lane_s16(a: int32x4_t, b: int16x8_t, c } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2, LANE = 1))] @@ -4493,6 +5229,8 @@ pub unsafe fn vmlal_high_laneq_s16(a: int32x4_t, b: int16x8_t, } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2, LANE = 1))] @@ -4504,6 +5242,8 @@ pub unsafe fn vmlal_high_lane_s32(a: int64x2_t, b: int32x4_t, c } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlal2, LANE = 1))] @@ -4515,6 +5255,8 @@ pub unsafe fn vmlal_high_laneq_s32(a: int64x2_t, b: int32x4_t, } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2, LANE = 1))] @@ -4526,6 +5268,8 @@ pub unsafe fn vmlal_high_lane_u16(a: uint32x4_t, b: uint16x8_t, } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2, LANE = 1))] @@ -4537,6 +5281,8 @@ pub unsafe fn vmlal_high_laneq_u16(a: uint32x4_t, b: uint16x8_t } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2, LANE = 1))] @@ -4548,6 +5294,8 @@ pub unsafe fn vmlal_high_lane_u32(a: uint64x2_t, b: uint32x4_t, } /// Multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_high_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlal2, LANE = 1))] @@ -4559,6 +5307,8 @@ pub unsafe fn vmlal_high_laneq_u32(a: uint64x2_t, b: uint32x4_t } /// Floating-point multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -4568,6 +5318,8 @@ pub unsafe fn vmls_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float6 } /// Floating-point multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -4577,6 +5329,8 @@ pub unsafe fn vmlsq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2))] @@ -4588,6 +5342,8 @@ pub unsafe fn vmlsl_high_s8(a: int16x8_t, b: int8x16_t, c: int8x16_t) -> int16x8 } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2))] @@ -4599,6 +5355,8 @@ pub unsafe fn vmlsl_high_s16(a: int32x4_t, b: int16x8_t, c: int16x8_t) -> int32x } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2))] @@ -4610,6 +5368,8 @@ pub unsafe fn vmlsl_high_s32(a: int64x2_t, b: int32x4_t, c: int32x4_t) -> int64x } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2))] @@ -4621,6 +5381,8 @@ pub unsafe fn vmlsl_high_u8(a: uint16x8_t, b: uint8x16_t, c: uint8x16_t) -> uint } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2))] @@ -4632,6 +5394,8 @@ pub unsafe fn vmlsl_high_u16(a: uint32x4_t, b: uint16x8_t, c: uint16x8_t) -> uin } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2))] @@ -4643,6 +5407,8 @@ pub unsafe fn vmlsl_high_u32(a: uint64x2_t, b: uint32x4_t, c: uint32x4_t) -> uin } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2))] @@ -4652,6 +5418,8 @@ pub unsafe fn vmlsl_high_n_s16(a: int32x4_t, b: int16x8_t, c: i16) -> int32x4_t } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2))] @@ -4661,6 +5429,8 @@ pub unsafe fn vmlsl_high_n_s32(a: int64x2_t, b: int32x4_t, c: i32) -> int64x2_t } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2))] @@ -4670,6 +5440,8 @@ pub unsafe fn vmlsl_high_n_u16(a: uint32x4_t, b: uint16x8_t, c: u16) -> uint32x4 } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2))] @@ -4679,6 +5451,8 @@ pub unsafe fn vmlsl_high_n_u32(a: uint64x2_t, b: uint32x4_t, c: u32) -> uint64x2 } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2, LANE = 1))] @@ -4690,6 +5464,8 @@ pub unsafe fn vmlsl_high_lane_s16(a: int32x4_t, b: int16x8_t, c } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2, LANE = 1))] @@ -4701,6 +5477,8 @@ pub unsafe fn vmlsl_high_laneq_s16(a: int32x4_t, b: int16x8_t, } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2, LANE = 1))] @@ -4712,6 +5490,8 @@ pub unsafe fn vmlsl_high_lane_s32(a: int64x2_t, b: int32x4_t, c } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smlsl2, LANE = 1))] @@ -4723,6 +5503,8 @@ pub unsafe fn vmlsl_high_laneq_s32(a: int64x2_t, b: int32x4_t, } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2, LANE = 1))] @@ -4734,6 +5516,8 @@ pub unsafe fn vmlsl_high_lane_u16(a: uint32x4_t, b: uint16x8_t, } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2, LANE = 1))] @@ -4745,6 +5529,8 @@ pub unsafe fn vmlsl_high_laneq_u16(a: uint32x4_t, b: uint16x8_t } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2, LANE = 1))] @@ -4756,6 +5542,8 @@ pub unsafe fn vmlsl_high_lane_u32(a: uint64x2_t, b: uint32x4_t, } /// Multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_high_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umlsl2, LANE = 1))] @@ -4767,6 +5555,8 @@ pub unsafe fn vmlsl_high_laneq_u32(a: uint64x2_t, b: uint32x4_t } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4777,6 +5567,8 @@ pub unsafe fn vmovn_high_s16(a: int8x8_t, b: int16x8_t) -> int8x16_t { } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4787,6 +5579,8 @@ pub unsafe fn vmovn_high_s32(a: int16x4_t, b: int32x4_t) -> int16x8_t { } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4797,6 +5591,8 @@ pub unsafe fn vmovn_high_s64(a: int32x2_t, b: int64x2_t) -> int32x4_t { } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4807,6 +5603,8 @@ pub unsafe fn vmovn_high_u16(a: uint8x8_t, b: uint16x8_t) -> uint8x16_t { } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4817,6 +5615,8 @@ pub unsafe fn vmovn_high_u32(a: uint16x4_t, b: uint32x4_t) -> uint16x8_t { } /// Extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovn_high_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(xtn2))] @@ -4827,6 +5627,8 @@ pub unsafe fn vmovn_high_u64(a: uint32x2_t, b: uint64x2_t) -> uint32x4_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(neg))] @@ -4836,6 +5638,8 @@ pub unsafe fn vneg_s64(a: int64x1_t) -> int64x1_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(neg))] @@ -4845,6 +5649,8 @@ pub unsafe fn vnegq_s64(a: int64x2_t) -> int64x2_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(neg))] @@ -4854,6 +5660,8 @@ pub unsafe fn vnegd_s64(a: i64) -> i64 { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fneg))] @@ -4863,6 +5671,8 @@ pub unsafe fn vneg_f64(a: float64x1_t) -> float64x1_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fneg))] @@ -4872,6 +5682,8 @@ pub unsafe fn vnegq_f64(a: float64x2_t) -> float64x2_t { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4886,6 +5698,8 @@ pub unsafe fn vqneg_s64(a: int64x1_t) -> int64x1_t { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4900,6 +5714,8 @@ pub unsafe fn vqnegq_s64(a: int64x2_t) -> int64x2_t { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4909,6 +5725,8 @@ pub unsafe fn vqnegb_s8(a: i8) -> i8 { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4918,6 +5736,8 @@ pub unsafe fn vqnegh_s16(a: i16) -> i16 { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegs_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4927,6 +5747,8 @@ pub unsafe fn vqnegs_s32(a: i32) -> i32 { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqneg))] @@ -4936,6 +5758,8 @@ pub unsafe fn vqnegd_s64(a: i64) -> i64 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqsub))] @@ -4947,6 +5771,8 @@ pub unsafe fn vqsubb_s8(a: i8, b: i8) -> i8 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqsub))] @@ -4958,6 +5784,8 @@ pub unsafe fn vqsubh_s16(a: i16, b: i16) -> i16 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubb_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqsub))] @@ -4969,6 +5797,8 @@ pub unsafe fn vqsubb_u8(a: u8, b: u8) -> u8 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqsub))] @@ -4980,6 +5810,8 @@ pub unsafe fn vqsubh_u16(a: u16, b: u16) -> u16 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubs_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqsub))] @@ -4994,6 +5826,8 @@ pub unsafe fn vqsubs_u32(a: u32, b: u32) -> u32 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqsub))] @@ -5008,6 +5842,8 @@ pub unsafe fn vqsubd_u64(a: u64, b: u64) -> u64 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubs_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqsub))] @@ -5022,6 +5858,8 @@ pub unsafe fn vqsubs_s32(a: i32, b: i32) -> i32 { } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqsub))] @@ -5036,6 +5874,8 @@ pub unsafe fn vqsubd_s64(a: i64, b: i64) -> i64 { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbit_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5050,6 +5890,8 @@ pub unsafe fn vrbit_s8(a: int8x8_t) -> int8x8_t { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbitq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5064,6 +5906,8 @@ pub unsafe fn vrbitq_s8(a: int8x16_t) -> int8x16_t { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbit_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5073,6 +5917,8 @@ pub unsafe fn vrbit_u8(a: uint8x8_t) -> uint8x8_t { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbitq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5082,6 +5928,8 @@ pub unsafe fn vrbitq_u8(a: uint8x16_t) -> uint8x16_t { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbit_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5091,6 +5939,8 @@ pub unsafe fn vrbit_p8(a: poly8x8_t) -> poly8x8_t { } /// Reverse bit order +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrbitq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rbit))] @@ -5100,6 +5950,8 @@ pub unsafe fn vrbitq_p8(a: poly8x16_t) -> poly8x16_t { } /// Floating-point round to integral exact, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndx_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintx))] @@ -5114,6 +5966,8 @@ pub unsafe fn vrndx_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral exact, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndxq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintx))] @@ -5128,6 +5982,8 @@ pub unsafe fn vrndxq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral exact, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndx_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintx))] @@ -5142,6 +5998,8 @@ pub unsafe fn vrndx_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral exact, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndxq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintx))] @@ -5156,6 +6014,8 @@ pub unsafe fn vrndxq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnda_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinta))] @@ -5170,6 +6030,8 @@ pub unsafe fn vrnda_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral, to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndaq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinta))] @@ -5184,6 +6046,8 @@ pub unsafe fn vrndaq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral, to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnda_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinta))] @@ -5198,6 +6062,8 @@ pub unsafe fn vrnda_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, to nearest with ties to away +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndaq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinta))] @@ -5212,6 +6078,8 @@ pub unsafe fn vrndaq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndn_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintn))] @@ -5226,6 +6094,8 @@ pub unsafe fn vrndn_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndnq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintn))] @@ -5240,6 +6110,8 @@ pub unsafe fn vrndnq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndns_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintn))] @@ -5254,6 +6126,8 @@ pub unsafe fn vrndns_f32(a: f32) -> f32 { } /// Floating-point round to integral, toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndm_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintm))] @@ -5268,6 +6142,8 @@ pub unsafe fn vrndm_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral, toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndmq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintm))] @@ -5282,6 +6158,8 @@ pub unsafe fn vrndmq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral, toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndm_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintm))] @@ -5296,6 +6174,8 @@ pub unsafe fn vrndm_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, toward minus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndmq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintm))] @@ -5310,6 +6190,8 @@ pub unsafe fn vrndmq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndp_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintp))] @@ -5324,6 +6206,8 @@ pub unsafe fn vrndp_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral, toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndpq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintp))] @@ -5338,6 +6222,8 @@ pub unsafe fn vrndpq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral, toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndp_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintp))] @@ -5352,6 +6238,8 @@ pub unsafe fn vrndp_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, toward plus infinity +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndpq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintp))] @@ -5366,6 +6254,8 @@ pub unsafe fn vrndpq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintz))] @@ -5380,6 +6270,8 @@ pub unsafe fn vrnd_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral, toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintz))] @@ -5394,6 +6286,8 @@ pub unsafe fn vrndq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral, toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintz))] @@ -5408,6 +6302,8 @@ pub unsafe fn vrnd_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frintz))] @@ -5422,6 +6318,8 @@ pub unsafe fn vrndq_f64(a: float64x2_t) -> float64x2_t { } /// Floating-point round to integral, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndi_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinti))] @@ -5436,6 +6334,8 @@ pub unsafe fn vrndi_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to integral, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndiq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinti))] @@ -5450,6 +6350,8 @@ pub unsafe fn vrndiq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to integral, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndi_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinti))] @@ -5464,6 +6366,8 @@ pub unsafe fn vrndi_f64(a: float64x1_t) -> float64x1_t { } /// Floating-point round to integral, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndiq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frinti))] @@ -5478,6 +6382,8 @@ pub unsafe fn vrndiq_f64(a: float64x2_t) -> float64x2_t { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqadd))] @@ -5489,6 +6395,8 @@ pub unsafe fn vqaddb_s8(a: i8, b: i8) -> i8 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqadd))] @@ -5500,6 +6408,8 @@ pub unsafe fn vqaddh_s16(a: i16, b: i16) -> i16 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddb_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqadd))] @@ -5511,6 +6421,8 @@ pub unsafe fn vqaddb_u8(a: u8, b: u8) -> u8 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqadd))] @@ -5522,6 +6434,8 @@ pub unsafe fn vqaddh_u16(a: u16, b: u16) -> u16 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadds_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqadd))] @@ -5536,6 +6450,8 @@ pub unsafe fn vqadds_u32(a: u32, b: u32) -> u32 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqadd))] @@ -5550,6 +6466,8 @@ pub unsafe fn vqaddd_u64(a: u64, b: u64) -> u64 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadds_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqadd))] @@ -5564,6 +6482,8 @@ pub unsafe fn vqadds_s32(a: i32, b: i32) -> i32 { } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqadd))] @@ -5578,6 +6498,8 @@ pub unsafe fn vqaddd_s64(a: i64, b: i64) -> i64 { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5592,6 +6514,8 @@ pub unsafe fn vld1_f64_x2(a: *const f64) -> float64x1x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5606,6 +6530,8 @@ pub unsafe fn vld1q_f64_x2(a: *const f64) -> float64x2x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5620,6 +6546,8 @@ pub unsafe fn vld1_f64_x3(a: *const f64) -> float64x1x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5634,6 +6562,8 @@ pub unsafe fn vld1q_f64_x3(a: *const f64) -> float64x2x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5648,6 +6578,8 @@ pub unsafe fn vld1_f64_x4(a: *const f64) -> float64x1x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld1))] @@ -5662,6 +6594,8 @@ pub unsafe fn vld1q_f64_x4(a: *const f64) -> float64x2x4_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2))] @@ -5676,6 +6610,8 @@ pub unsafe fn vld2q_s64(a: *const i64) -> int64x2x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2))] @@ -5685,6 +6621,8 @@ pub unsafe fn vld2q_u64(a: *const u64) -> uint64x2x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld2))] @@ -5694,6 +6632,8 @@ pub unsafe fn vld2q_p64(a: *const p64) -> poly64x2x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -5708,6 +6648,8 @@ pub unsafe fn vld2_f64(a: *const f64) -> float64x1x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2))] @@ -5722,6 +6664,8 @@ pub unsafe fn vld2q_f64(a: *const f64) -> float64x2x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2r))] @@ -5736,6 +6680,8 @@ pub unsafe fn vld2q_dup_s64(a: *const i64) -> int64x2x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2r))] @@ -5745,6 +6691,8 @@ pub unsafe fn vld2q_dup_u64(a: *const u64) -> uint64x2x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld2r))] @@ -5754,6 +6702,8 @@ pub unsafe fn vld2q_dup_p64(a: *const p64) -> poly64x2x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2r))] @@ -5768,6 +6718,8 @@ pub unsafe fn vld2_dup_f64(a: *const f64) -> float64x1x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2r))] @@ -5782,6 +6734,8 @@ pub unsafe fn vld2q_dup_f64(a: *const f64) -> float64x2x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5798,6 +6752,8 @@ pub unsafe fn vld2q_lane_s8(a: *const i8, b: int8x16x2_t) -> in } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5814,6 +6770,8 @@ pub unsafe fn vld2_lane_s64(a: *const i64, b: int64x1x2_t) -> i } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5830,6 +6788,8 @@ pub unsafe fn vld2q_lane_s64(a: *const i64, b: int64x2x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5841,6 +6801,8 @@ pub unsafe fn vld2_lane_p64(a: *const p64, b: poly64x1x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5852,6 +6814,8 @@ pub unsafe fn vld2q_lane_p64(a: *const p64, b: poly64x2x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5863,6 +6827,8 @@ pub unsafe fn vld2q_lane_u8(a: *const u8, b: uint8x16x2_t) -> u } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5874,6 +6840,8 @@ pub unsafe fn vld2_lane_u64(a: *const u64, b: uint64x1x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5885,6 +6853,8 @@ pub unsafe fn vld2q_lane_u64(a: *const u64, b: uint64x2x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5896,6 +6866,8 @@ pub unsafe fn vld2q_lane_p8(a: *const p8, b: poly8x16x2_t) -> p } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5912,6 +6884,8 @@ pub unsafe fn vld2_lane_f64(a: *const f64, b: float64x1x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld2, LANE = 0))] @@ -5928,6 +6902,8 @@ pub unsafe fn vld2q_lane_f64(a: *const f64, b: float64x2x2_t) - } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3))] @@ -5942,6 +6918,8 @@ pub unsafe fn vld3q_s64(a: *const i64) -> int64x2x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3))] @@ -5951,6 +6929,8 @@ pub unsafe fn vld3q_u64(a: *const u64) -> uint64x2x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld3))] @@ -5960,6 +6940,8 @@ pub unsafe fn vld3q_p64(a: *const p64) -> poly64x2x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -5974,6 +6956,8 @@ pub unsafe fn vld3_f64(a: *const f64) -> float64x1x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3))] @@ -5988,6 +6972,8 @@ pub unsafe fn vld3q_f64(a: *const f64) -> float64x2x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3r))] @@ -6002,6 +6988,8 @@ pub unsafe fn vld3q_dup_s64(a: *const i64) -> int64x2x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3r))] @@ -6011,6 +6999,8 @@ pub unsafe fn vld3q_dup_u64(a: *const u64) -> uint64x2x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld3r))] @@ -6020,6 +7010,8 @@ pub unsafe fn vld3q_dup_p64(a: *const p64) -> poly64x2x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3r))] @@ -6034,6 +7026,8 @@ pub unsafe fn vld3_dup_f64(a: *const f64) -> float64x1x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3r))] @@ -6048,6 +7042,8 @@ pub unsafe fn vld3q_dup_f64(a: *const f64) -> float64x2x3_t { } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6064,6 +7060,8 @@ pub unsafe fn vld3q_lane_s8(a: *const i8, b: int8x16x3_t) -> in } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6080,6 +7078,8 @@ pub unsafe fn vld3_lane_s64(a: *const i64, b: int64x1x3_t) -> i } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6096,6 +7096,8 @@ pub unsafe fn vld3q_lane_s64(a: *const i64, b: int64x2x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6107,6 +7109,8 @@ pub unsafe fn vld3_lane_p64(a: *const p64, b: poly64x1x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6118,6 +7122,8 @@ pub unsafe fn vld3q_lane_p64(a: *const p64, b: poly64x2x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6129,6 +7135,8 @@ pub unsafe fn vld3q_lane_p8(a: *const p8, b: poly8x16x3_t) -> p } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6140,6 +7148,8 @@ pub unsafe fn vld3q_lane_u8(a: *const u8, b: uint8x16x3_t) -> u } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6151,6 +7161,8 @@ pub unsafe fn vld3_lane_u64(a: *const u64, b: uint64x1x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6162,6 +7174,8 @@ pub unsafe fn vld3q_lane_u64(a: *const u64, b: uint64x2x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6178,6 +7192,8 @@ pub unsafe fn vld3_lane_f64(a: *const f64, b: float64x1x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld3, LANE = 0))] @@ -6194,6 +7210,8 @@ pub unsafe fn vld3q_lane_f64(a: *const f64, b: float64x2x3_t) - } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4))] @@ -6208,6 +7226,8 @@ pub unsafe fn vld4q_s64(a: *const i64) -> int64x2x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4))] @@ -6217,6 +7237,8 @@ pub unsafe fn vld4q_u64(a: *const u64) -> uint64x2x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld4))] @@ -6226,6 +7248,8 @@ pub unsafe fn vld4q_p64(a: *const p64) -> poly64x2x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -6240,6 +7264,8 @@ pub unsafe fn vld4_f64(a: *const f64) -> float64x1x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4))] @@ -6254,6 +7280,8 @@ pub unsafe fn vld4q_f64(a: *const f64) -> float64x2x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4r))] @@ -6268,6 +7296,8 @@ pub unsafe fn vld4q_dup_s64(a: *const i64) -> int64x2x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4r))] @@ -6277,6 +7307,8 @@ pub unsafe fn vld4q_dup_u64(a: *const u64) -> uint64x2x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld4r))] @@ -6286,6 +7318,8 @@ pub unsafe fn vld4q_dup_p64(a: *const p64) -> poly64x2x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4r))] @@ -6300,6 +7334,8 @@ pub unsafe fn vld4_dup_f64(a: *const f64) -> float64x1x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4r))] @@ -6314,6 +7350,8 @@ pub unsafe fn vld4q_dup_f64(a: *const f64) -> float64x2x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6330,6 +7368,8 @@ pub unsafe fn vld4q_lane_s8(a: *const i8, b: int8x16x4_t) -> in } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6346,6 +7386,8 @@ pub unsafe fn vld4_lane_s64(a: *const i64, b: int64x1x4_t) -> i } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6362,6 +7404,8 @@ pub unsafe fn vld4q_lane_s64(a: *const i64, b: int64x2x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6373,6 +7417,8 @@ pub unsafe fn vld4_lane_p64(a: *const p64, b: poly64x1x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6384,6 +7430,8 @@ pub unsafe fn vld4q_lane_p64(a: *const p64, b: poly64x2x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6395,6 +7443,8 @@ pub unsafe fn vld4q_lane_p8(a: *const p8, b: poly8x16x4_t) -> p } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6406,6 +7456,8 @@ pub unsafe fn vld4q_lane_u8(a: *const u8, b: uint8x16x4_t) -> u } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6417,6 +7469,8 @@ pub unsafe fn vld4_lane_u64(a: *const u64, b: uint64x1x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6428,6 +7482,8 @@ pub unsafe fn vld4q_lane_u64(a: *const u64, b: uint64x2x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6444,6 +7500,8 @@ pub unsafe fn vld4_lane_f64(a: *const f64, b: float64x1x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ld4, LANE = 0))] @@ -6460,6 +7518,8 @@ pub unsafe fn vld4q_lane_f64(a: *const f64, b: float64x2x4_t) - } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, LANE = 0))] @@ -6471,6 +7531,8 @@ pub unsafe fn vst1_lane_f64(a: *mut f64, b: float64x1_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, LANE = 0))] @@ -6482,6 +7544,8 @@ pub unsafe fn vst1q_lane_f64(a: *mut f64, b: float64x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6496,6 +7560,8 @@ pub unsafe fn vst1_f64_x2(a: *mut f64, b: float64x1x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6510,6 +7576,8 @@ pub unsafe fn vst1q_f64_x2(a: *mut f64, b: float64x2x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6524,6 +7592,8 @@ pub unsafe fn vst1_f64_x3(a: *mut f64, b: float64x1x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6538,6 +7608,8 @@ pub unsafe fn vst1q_f64_x3(a: *mut f64, b: float64x2x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6552,6 +7624,8 @@ pub unsafe fn vst1_f64_x4(a: *mut f64, b: float64x1x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6566,6 +7640,8 @@ pub unsafe fn vst1q_f64_x4(a: *mut f64, b: float64x2x4_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2))] @@ -6580,6 +7656,8 @@ pub unsafe fn vst2q_s64(a: *mut i64, b: int64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2))] @@ -6589,6 +7667,8 @@ pub unsafe fn vst2q_u64(a: *mut u64, b: uint64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st2))] @@ -6598,6 +7678,8 @@ pub unsafe fn vst2q_p64(a: *mut p64, b: poly64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st1))] @@ -6612,6 +7694,8 @@ pub unsafe fn vst2_f64(a: *mut f64, b: float64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2))] @@ -6626,6 +7710,8 @@ pub unsafe fn vst2q_f64(a: *mut f64, b: float64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6642,6 +7728,8 @@ pub unsafe fn vst2q_lane_s8(a: *mut i8, b: int8x16x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6658,6 +7746,8 @@ pub unsafe fn vst2_lane_s64(a: *mut i64, b: int64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6674,6 +7764,8 @@ pub unsafe fn vst2q_lane_s64(a: *mut i64, b: int64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6685,6 +7777,8 @@ pub unsafe fn vst2q_lane_u8(a: *mut u8, b: uint8x16x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6696,6 +7790,8 @@ pub unsafe fn vst2_lane_u64(a: *mut u64, b: uint64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6707,6 +7803,8 @@ pub unsafe fn vst2q_lane_u64(a: *mut u64, b: uint64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6718,6 +7816,8 @@ pub unsafe fn vst2q_lane_p8(a: *mut p8, b: poly8x16x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6729,6 +7829,8 @@ pub unsafe fn vst2_lane_p64(a: *mut p64, b: poly64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6740,6 +7842,8 @@ pub unsafe fn vst2q_lane_p64(a: *mut p64, b: poly64x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6756,6 +7860,8 @@ pub unsafe fn vst2_lane_f64(a: *mut f64, b: float64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st2, LANE = 0))] @@ -6772,6 +7878,8 @@ pub unsafe fn vst2q_lane_f64(a: *mut f64, b: float64x2x2_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3))] @@ -6786,6 +7894,8 @@ pub unsafe fn vst3q_s64(a: *mut i64, b: int64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3))] @@ -6795,6 +7905,8 @@ pub unsafe fn vst3q_u64(a: *mut u64, b: uint64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st3))] @@ -6804,6 +7916,8 @@ pub unsafe fn vst3q_p64(a: *mut p64, b: poly64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -6818,6 +7932,8 @@ pub unsafe fn vst3_f64(a: *mut f64, b: float64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3))] @@ -6832,6 +7948,8 @@ pub unsafe fn vst3q_f64(a: *mut f64, b: float64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6848,6 +7966,8 @@ pub unsafe fn vst3q_lane_s8(a: *mut i8, b: int8x16x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6864,6 +7984,8 @@ pub unsafe fn vst3_lane_s64(a: *mut i64, b: int64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6880,6 +8002,8 @@ pub unsafe fn vst3q_lane_s64(a: *mut i64, b: int64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6891,6 +8015,8 @@ pub unsafe fn vst3q_lane_u8(a: *mut u8, b: uint8x16x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6902,6 +8028,8 @@ pub unsafe fn vst3_lane_u64(a: *mut u64, b: uint64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6913,6 +8041,8 @@ pub unsafe fn vst3q_lane_u64(a: *mut u64, b: uint64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6924,6 +8054,8 @@ pub unsafe fn vst3q_lane_p8(a: *mut p8, b: poly8x16x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6935,6 +8067,8 @@ pub unsafe fn vst3_lane_p64(a: *mut p64, b: poly64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6946,6 +8080,8 @@ pub unsafe fn vst3q_lane_p64(a: *mut p64, b: poly64x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6962,6 +8098,8 @@ pub unsafe fn vst3_lane_f64(a: *mut f64, b: float64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st3, LANE = 0))] @@ -6978,6 +8116,8 @@ pub unsafe fn vst3q_lane_f64(a: *mut f64, b: float64x2x3_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4))] @@ -6992,6 +8132,8 @@ pub unsafe fn vst4q_s64(a: *mut i64, b: int64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4))] @@ -7001,6 +8143,8 @@ pub unsafe fn vst4q_u64(a: *mut u64, b: uint64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st4))] @@ -7010,6 +8154,8 @@ pub unsafe fn vst4q_p64(a: *mut p64, b: poly64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -7024,6 +8170,8 @@ pub unsafe fn vst4_f64(a: *mut f64, b: float64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4))] @@ -7038,6 +8186,8 @@ pub unsafe fn vst4q_f64(a: *mut f64, b: float64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7054,6 +8204,8 @@ pub unsafe fn vst4q_lane_s8(a: *mut i8, b: int8x16x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7070,6 +8222,8 @@ pub unsafe fn vst4_lane_s64(a: *mut i64, b: int64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7086,6 +8240,8 @@ pub unsafe fn vst4q_lane_s64(a: *mut i64, b: int64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7097,6 +8253,8 @@ pub unsafe fn vst4q_lane_u8(a: *mut u8, b: uint8x16x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7108,6 +8266,8 @@ pub unsafe fn vst4_lane_u64(a: *mut u64, b: uint64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7119,6 +8279,8 @@ pub unsafe fn vst4q_lane_u64(a: *mut u64, b: uint64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7130,6 +8292,8 @@ pub unsafe fn vst4q_lane_p8(a: *mut p8, b: poly8x16x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7141,6 +8305,8 @@ pub unsafe fn vst4_lane_p64(a: *mut p64, b: poly64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7152,6 +8318,8 @@ pub unsafe fn vst4q_lane_p64(a: *mut p64, b: poly64x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7168,6 +8336,8 @@ pub unsafe fn vst4_lane_f64(a: *mut f64, b: float64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(st4, LANE = 0))] @@ -7184,6 +8354,8 @@ pub unsafe fn vst4q_lane_f64(a: *mut f64, b: float64x2x4_t) { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -7193,6 +8365,8 @@ pub unsafe fn vmul_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -7202,6 +8376,8 @@ pub unsafe fn vmulq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -7211,6 +8387,8 @@ pub unsafe fn vmul_n_f64(a: float64x1_t, b: f64) -> float64x1_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul))] @@ -7220,6 +8398,8 @@ pub unsafe fn vmulq_n_f64(a: float64x2_t, b: f64) -> float64x2_t { } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7231,6 +8411,8 @@ pub unsafe fn vmul_lane_f64(a: float64x1_t, b: float64x1_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7242,6 +8424,8 @@ pub unsafe fn vmul_laneq_f64(a: float64x1_t, b: float64x2_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7253,6 +8437,8 @@ pub unsafe fn vmulq_lane_f64(a: float64x2_t, b: float64x1_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7264,6 +8450,8 @@ pub unsafe fn vmulq_laneq_f64(a: float64x2_t, b: float64x2_t) - } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmuls_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7276,6 +8464,8 @@ pub unsafe fn vmuls_lane_f32(a: f32, b: float32x2_t) -> f32 { } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmuls_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7288,6 +8478,8 @@ pub unsafe fn vmuls_laneq_f32(a: f32, b: float32x4_t) -> f32 { } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmuld_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7300,6 +8492,8 @@ pub unsafe fn vmuld_lane_f64(a: f64, b: float64x1_t) -> f64 { } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmuld_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmul, LANE = 0))] @@ -7312,6 +8506,8 @@ pub unsafe fn vmuld_laneq_f64(a: f64, b: float64x2_t) -> f64 { } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2))] @@ -7323,6 +8519,8 @@ pub unsafe fn vmull_high_s8(a: int8x16_t, b: int8x16_t) -> int16x8_t { } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2))] @@ -7334,6 +8532,8 @@ pub unsafe fn vmull_high_s16(a: int16x8_t, b: int16x8_t) -> int32x4_t { } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2))] @@ -7345,6 +8545,8 @@ pub unsafe fn vmull_high_s32(a: int32x4_t, b: int32x4_t) -> int64x2_t { } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2))] @@ -7356,6 +8558,8 @@ pub unsafe fn vmull_high_u8(a: uint8x16_t, b: uint8x16_t) -> uint16x8_t { } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2))] @@ -7367,6 +8571,8 @@ pub unsafe fn vmull_high_u16(a: uint16x8_t, b: uint16x8_t) -> uint32x4_t { } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2))] @@ -7378,6 +8584,8 @@ pub unsafe fn vmull_high_u32(a: uint32x4_t, b: uint32x4_t) -> uint64x2_t { } /// Polynomial multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(pmull))] @@ -7392,6 +8600,8 @@ pub unsafe fn vmull_p64(a: p64, b: p64) -> p128 { } /// Polynomial multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(pmull))] @@ -7403,6 +8613,8 @@ pub unsafe fn vmull_high_p8(a: poly8x16_t, b: poly8x16_t) -> poly16x8_t { } /// Polynomial multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(pmull))] @@ -7412,6 +8624,8 @@ pub unsafe fn vmull_high_p64(a: poly64x2_t, b: poly64x2_t) -> p128 { } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2))] @@ -7421,6 +8635,8 @@ pub unsafe fn vmull_high_n_s16(a: int16x8_t, b: i16) -> int32x4_t { } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2))] @@ -7430,6 +8646,8 @@ pub unsafe fn vmull_high_n_s32(a: int32x4_t, b: i32) -> int64x2_t { } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2))] @@ -7439,6 +8657,8 @@ pub unsafe fn vmull_high_n_u16(a: uint16x8_t, b: u16) -> uint32x4_t { } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2))] @@ -7448,6 +8668,8 @@ pub unsafe fn vmull_high_n_u32(a: uint32x4_t, b: u32) -> uint64x2_t { } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2, LANE = 1))] @@ -7459,6 +8681,8 @@ pub unsafe fn vmull_high_lane_s16(a: int16x8_t, b: int16x4_t) - } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2, LANE = 1))] @@ -7470,6 +8694,8 @@ pub unsafe fn vmull_high_laneq_s16(a: int16x8_t, b: int16x8_t) } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2, LANE = 1))] @@ -7481,6 +8707,8 @@ pub unsafe fn vmull_high_lane_s32(a: int32x4_t, b: int32x2_t) - } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(smull2, LANE = 1))] @@ -7492,6 +8720,8 @@ pub unsafe fn vmull_high_laneq_s32(a: int32x4_t, b: int32x4_t) } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2, LANE = 1))] @@ -7503,6 +8733,8 @@ pub unsafe fn vmull_high_lane_u16(a: uint16x8_t, b: uint16x4_t) } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2, LANE = 1))] @@ -7514,6 +8746,8 @@ pub unsafe fn vmull_high_laneq_u16(a: uint16x8_t, b: uint16x8_t } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2, LANE = 1))] @@ -7525,6 +8759,8 @@ pub unsafe fn vmull_high_lane_u32(a: uint32x4_t, b: uint32x2_t) } /// Multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_high_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(umull2, LANE = 1))] @@ -7536,6 +8772,8 @@ pub unsafe fn vmull_high_laneq_u32(a: uint32x4_t, b: uint32x4_t } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7550,6 +8788,8 @@ pub unsafe fn vmulx_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7564,6 +8804,8 @@ pub unsafe fn vmulxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7578,6 +8820,8 @@ pub unsafe fn vmulx_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7592,6 +8836,8 @@ pub unsafe fn vmulxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7603,6 +8849,8 @@ pub unsafe fn vmulx_lane_f64(a: float64x1_t, b: float64x1_t) -> } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7614,6 +8862,8 @@ pub unsafe fn vmulx_laneq_f64(a: float64x1_t, b: float64x2_t) - } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7625,6 +8875,8 @@ pub unsafe fn vmulx_lane_f32(a: float32x2_t, b: float32x2_t) -> } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulx_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7636,6 +8888,8 @@ pub unsafe fn vmulx_laneq_f32(a: float32x2_t, b: float32x4_t) - } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7647,6 +8901,8 @@ pub unsafe fn vmulxq_lane_f32(a: float32x4_t, b: float32x2_t) - } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7658,6 +8914,8 @@ pub unsafe fn vmulxq_laneq_f32(a: float32x4_t, b: float32x4_t) } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7669,6 +8927,8 @@ pub unsafe fn vmulxq_lane_f64(a: float64x2_t, b: float64x1_t) - } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7680,6 +8940,8 @@ pub unsafe fn vmulxq_laneq_f64(a: float64x2_t, b: float64x2_t) } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7694,6 +8956,8 @@ pub unsafe fn vmulxs_f32(a: f32, b: f32) -> f32 { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx))] @@ -7708,6 +8972,8 @@ pub unsafe fn vmulxd_f64(a: f64, b: f64) -> f64 { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxs_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7719,6 +8985,8 @@ pub unsafe fn vmulxs_lane_f32(a: f32, b: float32x2_t) -> f32 { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxs_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7730,6 +8998,8 @@ pub unsafe fn vmulxs_laneq_f32(a: f32, b: float32x4_t) -> f32 { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxd_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7741,6 +9011,8 @@ pub unsafe fn vmulxd_lane_f64(a: f64, b: float64x1_t) -> f64 { } /// Floating-point multiply extended +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulxd_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmulx, LANE = 0))] @@ -7752,6 +9024,8 @@ pub unsafe fn vmulxd_laneq_f64(a: f64, b: float64x2_t) -> f64 { } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmadd))] @@ -7766,6 +9040,8 @@ pub unsafe fn vfma_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float6 } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla))] @@ -7780,6 +9056,8 @@ pub unsafe fn vfmaq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmadd))] @@ -7789,6 +9067,8 @@ pub unsafe fn vfma_n_f64(a: float64x1_t, b: float64x1_t, c: f64) -> float64x1_t } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla))] @@ -7798,6 +9078,8 @@ pub unsafe fn vfmaq_n_f64(a: float64x2_t, b: float64x2_t, c: f64) -> float64x2_t } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7809,6 +9091,8 @@ pub unsafe fn vfma_lane_f32(a: float32x2_t, b: float32x2_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7820,6 +9104,8 @@ pub unsafe fn vfma_laneq_f32(a: float32x2_t, b: float32x2_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7831,6 +9117,8 @@ pub unsafe fn vfmaq_lane_f32(a: float32x4_t, b: float32x4_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7842,6 +9130,8 @@ pub unsafe fn vfmaq_laneq_f32(a: float32x4_t, b: float32x4_t, c } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmadd, LANE = 0))] @@ -7853,6 +9143,8 @@ pub unsafe fn vfma_lane_f64(a: float64x1_t, b: float64x1_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7864,6 +9156,8 @@ pub unsafe fn vfma_laneq_f64(a: float64x1_t, b: float64x1_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7875,6 +9169,8 @@ pub unsafe fn vfmaq_lane_f64(a: float64x2_t, b: float64x2_t, c: } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7886,6 +9182,8 @@ pub unsafe fn vfmaq_laneq_f64(a: float64x2_t, b: float64x2_t, c } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmas_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7903,6 +9201,8 @@ pub unsafe fn vfmas_lane_f32(a: f32, b: f32, c: float32x2_t) -> } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmas_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7920,6 +9220,8 @@ pub unsafe fn vfmas_laneq_f32(a: f32, b: f32, c: float32x4_t) - } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmad_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmadd, LANE = 0))] @@ -7937,6 +9239,8 @@ pub unsafe fn vfmad_lane_f64(a: f64, b: f64, c: float64x1_t) -> } /// Floating-point fused multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmad_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmla, LANE = 0))] @@ -7954,6 +9258,8 @@ pub unsafe fn vfmad_laneq_f64(a: f64, b: f64, c: float64x2_t) - } /// Floating-point fused multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmsub))] @@ -7964,6 +9270,8 @@ pub unsafe fn vfms_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float6 } /// Floating-point fused multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls))] @@ -7974,6 +9282,8 @@ pub unsafe fn vfmsq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float } /// Floating-point fused Multiply-subtract to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmsub))] @@ -7983,6 +9293,8 @@ pub unsafe fn vfms_n_f64(a: float64x1_t, b: float64x1_t, c: f64) -> float64x1_t } /// Floating-point fused Multiply-subtract to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_n_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls))] @@ -7992,6 +9304,8 @@ pub unsafe fn vfmsq_n_f64(a: float64x2_t, b: float64x2_t, c: f64) -> float64x2_t } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8003,6 +9317,8 @@ pub unsafe fn vfms_lane_f32(a: float32x2_t, b: float32x2_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8014,6 +9330,8 @@ pub unsafe fn vfms_laneq_f32(a: float32x2_t, b: float32x2_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8025,6 +9343,8 @@ pub unsafe fn vfmsq_lane_f32(a: float32x4_t, b: float32x4_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8036,6 +9356,8 @@ pub unsafe fn vfmsq_laneq_f32(a: float32x4_t, b: float32x4_t, c } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmsub, LANE = 0))] @@ -8047,6 +9369,8 @@ pub unsafe fn vfms_lane_f64(a: float64x1_t, b: float64x1_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8058,6 +9382,8 @@ pub unsafe fn vfms_laneq_f64(a: float64x1_t, b: float64x1_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8069,6 +9395,8 @@ pub unsafe fn vfmsq_lane_f64(a: float64x2_t, b: float64x2_t, c: } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8080,6 +9408,8 @@ pub unsafe fn vfmsq_laneq_f64(a: float64x2_t, b: float64x2_t, c } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmss_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8090,6 +9420,8 @@ pub unsafe fn vfmss_lane_f32(a: f32, b: f32, c: float32x2_t) -> } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmss_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8100,6 +9432,8 @@ pub unsafe fn vfmss_laneq_f32(a: f32, b: f32, c: float32x4_t) - } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsd_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmsub, LANE = 0))] @@ -8110,6 +9444,8 @@ pub unsafe fn vfmsd_lane_f64(a: f64, b: f64, c: float64x1_t) -> } /// Floating-point fused multiply-subtract to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsd_laneq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmls, LANE = 0))] @@ -8120,6 +9456,8 @@ pub unsafe fn vfmsd_laneq_f64(a: f64, b: f64, c: float64x2_t) - } /// Divide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdiv_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fdiv))] @@ -8129,6 +9467,8 @@ pub unsafe fn vdiv_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Divide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdivq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fdiv))] @@ -8138,6 +9478,8 @@ pub unsafe fn vdivq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Divide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdiv_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fdiv))] @@ -8147,6 +9489,8 @@ pub unsafe fn vdiv_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Divide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdivq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fdiv))] @@ -8156,6 +9500,8 @@ pub unsafe fn vdivq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsub))] @@ -8165,6 +9511,8 @@ pub unsafe fn vsub_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsub))] @@ -8174,6 +9522,8 @@ pub unsafe fn vsubq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -8183,6 +9533,8 @@ pub unsafe fn vsubd_s64(a: i64, b: i64) -> i64 { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -8192,6 +9544,8 @@ pub unsafe fn vsubd_u64(a: u64, b: u64) -> u64 { } /// Add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -8201,6 +9555,8 @@ pub unsafe fn vaddd_s64(a: i64, b: i64) -> i64 { } /// Add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -8210,6 +9566,8 @@ pub unsafe fn vaddd_u64(a: u64, b: u64) -> u64 { } /// Floating-point add across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddv_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(faddp))] @@ -8224,6 +9582,8 @@ pub unsafe fn vaddv_f32(a: float32x2_t) -> f32 { } /// Floating-point add across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddvq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(faddp))] @@ -8238,6 +9598,8 @@ pub unsafe fn vaddvq_f32(a: float32x4_t) -> f32 { } /// Floating-point add across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddvq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(faddp))] @@ -8252,6 +9614,8 @@ pub unsafe fn vaddvq_f64(a: float64x2_t) -> f64 { } /// Signed Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlv_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(saddlv))] @@ -8266,6 +9630,8 @@ pub unsafe fn vaddlv_s16(a: int16x4_t) -> i32 { } /// Signed Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlvq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(saddlv))] @@ -8280,6 +9646,8 @@ pub unsafe fn vaddlvq_s16(a: int16x8_t) -> i32 { } /// Signed Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlv_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(saddlp))] @@ -8294,6 +9662,8 @@ pub unsafe fn vaddlv_s32(a: int32x2_t) -> i64 { } /// Signed Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlvq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(saddlv))] @@ -8308,6 +9678,8 @@ pub unsafe fn vaddlvq_s32(a: int32x4_t) -> i64 { } /// Unsigned Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlv_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uaddlv))] @@ -8322,6 +9694,8 @@ pub unsafe fn vaddlv_u16(a: uint16x4_t) -> u32 { } /// Unsigned Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlvq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uaddlv))] @@ -8336,6 +9710,8 @@ pub unsafe fn vaddlvq_u16(a: uint16x8_t) -> u32 { } /// Unsigned Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlv_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uaddlp))] @@ -8350,6 +9726,8 @@ pub unsafe fn vaddlv_u32(a: uint32x2_t) -> u64 { } /// Unsigned Add Long across Vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddlvq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uaddlv))] @@ -8364,6 +9742,8 @@ pub unsafe fn vaddlvq_u32(a: uint32x4_t) -> u64 { } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubw))] @@ -8374,6 +9754,8 @@ pub unsafe fn vsubw_high_s8(a: int16x8_t, b: int8x16_t) -> int16x8_t { } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubw))] @@ -8384,6 +9766,8 @@ pub unsafe fn vsubw_high_s16(a: int32x4_t, b: int16x8_t) -> int32x4_t { } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubw))] @@ -8394,6 +9778,8 @@ pub unsafe fn vsubw_high_s32(a: int64x2_t, b: int32x4_t) -> int64x2_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubw))] @@ -8404,6 +9790,8 @@ pub unsafe fn vsubw_high_u8(a: uint16x8_t, b: uint8x16_t) -> uint16x8_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubw))] @@ -8414,6 +9802,8 @@ pub unsafe fn vsubw_high_u16(a: uint32x4_t, b: uint16x8_t) -> uint32x4_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubw))] @@ -8424,6 +9814,8 @@ pub unsafe fn vsubw_high_u32(a: uint64x2_t, b: uint32x4_t) -> uint64x2_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubl))] @@ -8437,6 +9829,8 @@ pub unsafe fn vsubl_high_s8(a: int8x16_t, b: int8x16_t) -> int16x8_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubl))] @@ -8450,6 +9844,8 @@ pub unsafe fn vsubl_high_s16(a: int16x8_t, b: int16x8_t) -> int32x4_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ssubl))] @@ -8463,6 +9859,8 @@ pub unsafe fn vsubl_high_s32(a: int32x4_t, b: int32x4_t) -> int64x2_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubl))] @@ -8476,6 +9874,8 @@ pub unsafe fn vsubl_high_u8(a: uint8x16_t, b: uint8x16_t) -> uint16x8_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubl))] @@ -8489,6 +9889,8 @@ pub unsafe fn vsubl_high_u16(a: uint16x8_t, b: uint16x8_t) -> uint32x4_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usubl))] @@ -8502,6 +9904,8 @@ pub unsafe fn vsubl_high_u32(a: uint32x4_t, b: uint32x4_t) -> uint64x2_t { } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_s8) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8515,6 +9919,8 @@ pub unsafe fn vbcaxq_s8(a: int8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_s16) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8528,6 +9934,8 @@ pub unsafe fn vbcaxq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_s32) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8541,6 +9949,8 @@ pub unsafe fn vbcaxq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_s64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8554,6 +9964,8 @@ pub unsafe fn vbcaxq_s64(a: int64x2_t, b: int64x2_t, c: int64x2_t) -> int64x2_t } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_u8) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8567,6 +9979,8 @@ pub unsafe fn vbcaxq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16 } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_u16) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8580,6 +9994,8 @@ pub unsafe fn vbcaxq_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_u32) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8593,6 +10009,8 @@ pub unsafe fn vbcaxq_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x } /// Bit clear and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbcaxq_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(bcax))] @@ -8606,6 +10024,8 @@ pub unsafe fn vbcaxq_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcadd_rot270_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8619,6 +10039,8 @@ pub unsafe fn vcadd_rot270_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaddq_rot270_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8632,6 +10054,8 @@ pub unsafe fn vcaddq_rot270_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaddq_rot270_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8645,6 +10069,8 @@ pub unsafe fn vcaddq_rot270_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcadd_rot90_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8658,6 +10084,8 @@ pub unsafe fn vcadd_rot90_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaddq_rot90_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8671,6 +10099,8 @@ pub unsafe fn vcaddq_rot90_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point complex add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaddq_rot90_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcadd))] @@ -8684,6 +10114,8 @@ pub unsafe fn vcaddq_rot90_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8697,6 +10129,8 @@ pub unsafe fn vcmla_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8710,6 +10144,8 @@ pub unsafe fn vcmlaq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> floa } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8723,6 +10159,8 @@ pub unsafe fn vcmlaq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> floa } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot90_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8736,6 +10174,8 @@ pub unsafe fn vcmla_rot90_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot90_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8749,6 +10189,8 @@ pub unsafe fn vcmlaq_rot90_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) - } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot90_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8762,6 +10204,8 @@ pub unsafe fn vcmlaq_rot90_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) - } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot180_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8775,6 +10219,8 @@ pub unsafe fn vcmla_rot180_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) - } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot180_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8788,6 +10234,8 @@ pub unsafe fn vcmlaq_rot180_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot180_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8801,6 +10249,8 @@ pub unsafe fn vcmlaq_rot180_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot270_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8814,6 +10264,8 @@ pub unsafe fn vcmla_rot270_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) - } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot270_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8827,6 +10279,8 @@ pub unsafe fn vcmlaq_rot270_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot270_f64) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla))] @@ -8840,6 +10294,8 @@ pub unsafe fn vcmlaq_rot270_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8851,6 +10307,8 @@ pub unsafe fn vcmla_lane_f32(a: float32x2_t, b: float32x2_t, c: } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8862,6 +10320,8 @@ pub unsafe fn vcmla_laneq_f32(a: float32x2_t, b: float32x2_t, c } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8873,6 +10333,8 @@ pub unsafe fn vcmlaq_lane_f32(a: float32x4_t, b: float32x4_t, c } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8884,6 +10346,8 @@ pub unsafe fn vcmlaq_laneq_f32(a: float32x4_t, b: float32x4_t, } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot90_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8895,6 +10359,8 @@ pub unsafe fn vcmla_rot90_lane_f32(a: float32x2_t, b: float32x2 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot90_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8906,6 +10372,8 @@ pub unsafe fn vcmla_rot90_laneq_f32(a: float32x2_t, b: float32x } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot90_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8917,6 +10385,8 @@ pub unsafe fn vcmlaq_rot90_lane_f32(a: float32x4_t, b: float32x } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot90_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8928,6 +10398,8 @@ pub unsafe fn vcmlaq_rot90_laneq_f32(a: float32x4_t, b: float32 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot180_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8939,6 +10411,8 @@ pub unsafe fn vcmla_rot180_lane_f32(a: float32x2_t, b: float32x } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot180_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8950,6 +10424,8 @@ pub unsafe fn vcmla_rot180_laneq_f32(a: float32x2_t, b: float32 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot180_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8961,6 +10437,8 @@ pub unsafe fn vcmlaq_rot180_lane_f32(a: float32x4_t, b: float32 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot180_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8972,6 +10450,8 @@ pub unsafe fn vcmlaq_rot180_laneq_f32(a: float32x4_t, b: float3 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot270_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8983,6 +10463,8 @@ pub unsafe fn vcmla_rot270_lane_f32(a: float32x2_t, b: float32x } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmla_rot270_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -8994,6 +10476,8 @@ pub unsafe fn vcmla_rot270_laneq_f32(a: float32x2_t, b: float32 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot270_lane_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -9005,6 +10489,8 @@ pub unsafe fn vcmlaq_rot270_lane_f32(a: float32x4_t, b: float32 } /// Floating-point complex multiply accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcmlaq_rot270_laneq_f32) #[inline] #[target_feature(enable = "neon,fcma")] #[cfg_attr(test, assert_instr(fcmla, LANE = 0))] @@ -9016,6 +10502,8 @@ pub unsafe fn vcmlaq_rot270_laneq_f32(a: float32x4_t, b: float3 } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot))] @@ -9029,6 +10517,8 @@ pub unsafe fn vdot_s32(a: int32x2_t, b: int8x8_t, c: int8x8_t) -> int32x2_t { } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot))] @@ -9042,6 +10532,8 @@ pub unsafe fn vdotq_s32(a: int32x4_t, b: int8x16_t, c: int8x16_t) -> int32x4_t { } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot))] @@ -9055,6 +10547,8 @@ pub unsafe fn vdot_u32(a: uint32x2_t, b: uint8x8_t, c: uint8x8_t) -> uint32x2_t } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot))] @@ -9068,6 +10562,8 @@ pub unsafe fn vdotq_u32(a: uint32x4_t, b: uint8x16_t, c: uint8x16_t) -> uint32x4 } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_lane_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot, LANE = 0))] @@ -9079,6 +10575,8 @@ pub unsafe fn vdot_lane_s32(a: int32x2_t, b: int8x8_t, c: int8x } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_laneq_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot, LANE = 0))] @@ -9090,6 +10588,8 @@ pub unsafe fn vdot_laneq_s32(a: int32x2_t, b: int8x8_t, c: int8 } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_lane_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot, LANE = 0))] @@ -9101,6 +10601,8 @@ pub unsafe fn vdotq_lane_s32(a: int32x4_t, b: int8x16_t, c: int } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_laneq_s32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(sdot, LANE = 0))] @@ -9112,6 +10614,8 @@ pub unsafe fn vdotq_laneq_s32(a: int32x4_t, b: int8x16_t, c: in } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_lane_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot, LANE = 0))] @@ -9123,6 +10627,8 @@ pub unsafe fn vdot_lane_u32(a: uint32x2_t, b: uint8x8_t, c: uin } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdot_laneq_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot, LANE = 0))] @@ -9134,6 +10640,8 @@ pub unsafe fn vdot_laneq_u32(a: uint32x2_t, b: uint8x8_t, c: ui } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_lane_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot, LANE = 0))] @@ -9145,6 +10653,8 @@ pub unsafe fn vdotq_lane_u32(a: uint32x4_t, b: uint8x16_t, c: u } /// Dot product arithmetic +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdotq_laneq_u32) #[inline] #[target_feature(enable = "neon,dotprod")] #[cfg_attr(test, assert_instr(udot, LANE = 0))] @@ -9156,6 +10666,8 @@ pub unsafe fn vdotq_laneq_u32(a: uint32x4_t, b: uint8x16_t, c: } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmax))] @@ -9170,6 +10682,8 @@ pub unsafe fn vmax_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmax))] @@ -9184,6 +10698,8 @@ pub unsafe fn vmaxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point Maximum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnm_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnm))] @@ -9198,6 +10714,8 @@ pub unsafe fn vmaxnm_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Floating-point Maximum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnmq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnm))] @@ -9212,6 +10730,8 @@ pub unsafe fn vmaxnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point maximum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnmv_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9226,6 +10746,8 @@ pub unsafe fn vmaxnmv_f32(a: float32x2_t) -> f32 { } /// Floating-point maximum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnmvq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9240,6 +10762,8 @@ pub unsafe fn vmaxnmvq_f64(a: float64x2_t) -> f64 { } /// Floating-point maximum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnmvq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmv))] @@ -9254,6 +10778,8 @@ pub unsafe fn vmaxnmvq_f32(a: float32x4_t) -> f32 { } /// Floating-point Maximum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxnm_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9268,6 +10794,8 @@ pub unsafe fn vpmaxnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Floating-point Maximum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxnmq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9282,6 +10810,8 @@ pub unsafe fn vpmaxnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point Maximum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxnmq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9296,6 +10826,8 @@ pub unsafe fn vpmaxnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point maximum number pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxnms_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9310,6 +10842,8 @@ pub unsafe fn vpmaxnms_f32(a: float32x2_t) -> f32 { } /// Floating-point maximum number pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxnmqd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxnmp))] @@ -9324,6 +10858,8 @@ pub unsafe fn vpmaxnmqd_f64(a: float64x2_t) -> f64 { } /// Floating-point maximum pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxp))] @@ -9338,6 +10874,8 @@ pub unsafe fn vpmaxs_f32(a: float32x2_t) -> f32 { } /// Floating-point maximum pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxqd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmaxp))] @@ -9352,6 +10890,8 @@ pub unsafe fn vpmaxqd_f64(a: float64x2_t) -> f64 { } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmin))] @@ -9366,6 +10906,8 @@ pub unsafe fn vmin_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fmin))] @@ -9380,6 +10922,8 @@ pub unsafe fn vminq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point Minimum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnm_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnm))] @@ -9394,6 +10938,8 @@ pub unsafe fn vminnm_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Floating-point Minimum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnmq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnm))] @@ -9408,6 +10954,8 @@ pub unsafe fn vminnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point minimum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnmv_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9422,6 +10970,8 @@ pub unsafe fn vminnmv_f32(a: float32x2_t) -> f32 { } /// Floating-point minimum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnmvq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9436,6 +10986,8 @@ pub unsafe fn vminnmvq_f64(a: float64x2_t) -> f64 { } /// Floating-point minimum number across vector +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnmvq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmv))] @@ -9450,6 +11002,8 @@ pub unsafe fn vminnmvq_f32(a: float32x4_t) -> f32 { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sxtl2))] @@ -9460,6 +11014,8 @@ pub unsafe fn vmovl_high_s8(a: int8x16_t) -> int16x8_t { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sxtl2))] @@ -9470,6 +11026,8 @@ pub unsafe fn vmovl_high_s16(a: int16x8_t) -> int32x4_t { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sxtl2))] @@ -9480,6 +11038,8 @@ pub unsafe fn vmovl_high_s32(a: int32x4_t) -> int64x2_t { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uxtl2))] @@ -9490,6 +11050,8 @@ pub unsafe fn vmovl_high_u8(a: uint8x16_t) -> uint16x8_t { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uxtl2))] @@ -9500,6 +11062,8 @@ pub unsafe fn vmovl_high_u16(a: uint16x8_t) -> uint32x4_t { } /// Vector move +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmovl_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uxtl2))] @@ -9510,6 +11074,8 @@ pub unsafe fn vmovl_high_u32(a: uint32x4_t) -> uint64x2_t { } /// Floating-point add pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpaddq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(faddp))] @@ -9524,6 +11090,8 @@ pub unsafe fn vpaddq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point add pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpaddq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(faddp))] @@ -9538,6 +11106,8 @@ pub unsafe fn vpaddq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point add pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpadds_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -9549,6 +11119,8 @@ pub unsafe fn vpadds_f32(a: float32x2_t) -> f32 { } /// Floating-point add pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpaddd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -9560,6 +11132,8 @@ pub unsafe fn vpaddd_f64(a: float64x2_t) -> f64 { } /// Floating-point Minimum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminnm_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9574,6 +11148,8 @@ pub unsafe fn vpminnm_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Floating-point Minimum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminnmq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9588,6 +11164,8 @@ pub unsafe fn vpminnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point Minimum Number Pairwise (vector). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminnmq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9602,6 +11180,8 @@ pub unsafe fn vpminnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Floating-point minimum number pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminnms_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9616,6 +11196,8 @@ pub unsafe fn vpminnms_f32(a: float32x2_t) -> f32 { } /// Floating-point minimum number pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminnmqd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminnmp))] @@ -9630,6 +11212,8 @@ pub unsafe fn vpminnmqd_f64(a: float64x2_t) -> f64 { } /// Floating-point minimum pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmins_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminp))] @@ -9644,6 +11228,8 @@ pub unsafe fn vpmins_f32(a: float32x2_t) -> f32 { } /// Floating-point minimum pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpminqd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fminp))] @@ -9658,6 +11244,8 @@ pub unsafe fn vpminqd_f64(a: float64x2_t) -> f64 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmullh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -9669,6 +11257,8 @@ pub unsafe fn vqdmullh_s16(a: i16, b: i16) -> i32 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -9683,6 +11273,8 @@ pub unsafe fn vqdmulls_s32(a: i32, b: i32) -> i64 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2))] @@ -9694,6 +11286,8 @@ pub unsafe fn vqdmull_high_s16(a: int16x8_t, b: int16x8_t) -> int32x4_t { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2))] @@ -9705,6 +11299,8 @@ pub unsafe fn vqdmull_high_s32(a: int32x4_t, b: int32x4_t) -> int64x2_t { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2))] @@ -9716,6 +11312,8 @@ pub unsafe fn vqdmull_high_n_s16(a: int16x8_t, b: i16) -> int32x4_t { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2))] @@ -9727,6 +11325,8 @@ pub unsafe fn vqdmull_high_n_s32(a: int32x4_t, b: i32) -> int64x2_t { } /// Vector saturating doubling long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 4))] @@ -9739,6 +11339,8 @@ pub unsafe fn vqdmull_laneq_s16(a: int16x4_t, b: int16x8_t) -> int } /// Vector saturating doubling long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 2))] @@ -9751,6 +11353,8 @@ pub unsafe fn vqdmull_laneq_s32(a: int32x2_t, b: int32x4_t) -> int } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmullh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 2))] @@ -9763,6 +11367,8 @@ pub unsafe fn vqdmullh_lane_s16(a: i16, b: int16x4_t) -> i32 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmullh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 4))] @@ -9775,6 +11381,8 @@ pub unsafe fn vqdmullh_laneq_s16(a: i16, b: int16x8_t) -> i32 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulls_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 1))] @@ -9787,6 +11395,8 @@ pub unsafe fn vqdmulls_lane_s32(a: i32, b: int32x2_t) -> i64 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulls_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, N = 2))] @@ -9799,6 +11409,8 @@ pub unsafe fn vqdmulls_laneq_s32(a: i32, b: int32x4_t) -> i64 { } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2, N = 2))] @@ -9812,6 +11424,8 @@ pub unsafe fn vqdmull_high_lane_s16(a: int16x8_t, b: int16x4_t) -> } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2, N = 1))] @@ -9825,6 +11439,8 @@ pub unsafe fn vqdmull_high_lane_s32(a: int32x4_t, b: int32x2_t) -> } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2, N = 4))] @@ -9838,6 +11454,8 @@ pub unsafe fn vqdmull_high_laneq_s16(a: int16x8_t, b: int16x8_t) - } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull2, N = 2))] @@ -9851,6 +11469,8 @@ pub unsafe fn vqdmull_high_laneq_s32(a: int32x4_t, b: int32x4_t) - } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2))] @@ -9860,6 +11480,8 @@ pub unsafe fn vqdmlal_high_s16(a: int32x4_t, b: int16x8_t, c: int16x8_t) -> int3 } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2))] @@ -9869,6 +11491,8 @@ pub unsafe fn vqdmlal_high_s32(a: int64x2_t, b: int32x4_t, c: int32x4_t) -> int6 } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2))] @@ -9878,6 +11502,8 @@ pub unsafe fn vqdmlal_high_n_s16(a: int32x4_t, b: int16x8_t, c: i16) -> int32x4_ } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2))] @@ -9887,6 +11513,8 @@ pub unsafe fn vqdmlal_high_n_s32(a: int64x2_t, b: int32x4_t, c: i32) -> int64x2_ } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal, N = 2))] @@ -9898,6 +11526,8 @@ pub unsafe fn vqdmlal_laneq_s16(a: int32x4_t, b: int16x4_t, c: int } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal, N = 1))] @@ -9909,6 +11539,8 @@ pub unsafe fn vqdmlal_laneq_s32(a: int64x2_t, b: int32x2_t, c: int } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2, N = 1))] @@ -9920,6 +11552,8 @@ pub unsafe fn vqdmlal_high_lane_s16(a: int32x4_t, b: int16x8_t, c: } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2, N = 1))] @@ -9931,6 +11565,8 @@ pub unsafe fn vqdmlal_high_laneq_s16(a: int32x4_t, b: int16x8_t, c } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2, N = 1))] @@ -9942,6 +11578,8 @@ pub unsafe fn vqdmlal_high_lane_s32(a: int64x2_t, b: int32x4_t, c: } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal2, N = 1))] @@ -9953,6 +11591,8 @@ pub unsafe fn vqdmlal_high_laneq_s32(a: int64x2_t, b: int32x4_t, c } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlalh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -9963,6 +11603,8 @@ pub unsafe fn vqdmlalh_s16(a: i32, b: i16, c: i16) -> i32 { } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlals_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -9973,6 +11615,8 @@ pub unsafe fn vqdmlals_s32(a: i64, b: i32, c: i32) -> i64 { } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlalh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal, LANE = 0))] @@ -9984,6 +11628,8 @@ pub unsafe fn vqdmlalh_lane_s16(a: i32, b: i16, c: int16x4_t) - } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlalh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlal, LANE = 0))] @@ -9995,6 +11641,8 @@ pub unsafe fn vqdmlalh_laneq_s16(a: i32, b: i16, c: int16x8_t) } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlals_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, LANE = 0))] @@ -10006,6 +11654,8 @@ pub unsafe fn vqdmlals_lane_s32(a: i64, b: i32, c: int32x2_t) - } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlals_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, LANE = 0))] @@ -10017,6 +11667,8 @@ pub unsafe fn vqdmlals_laneq_s32(a: i64, b: i32, c: int32x4_t) } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2))] @@ -10026,6 +11678,8 @@ pub unsafe fn vqdmlsl_high_s16(a: int32x4_t, b: int16x8_t, c: int16x8_t) -> int3 } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2))] @@ -10035,6 +11689,8 @@ pub unsafe fn vqdmlsl_high_s32(a: int64x2_t, b: int32x4_t, c: int32x4_t) -> int6 } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2))] @@ -10044,6 +11700,8 @@ pub unsafe fn vqdmlsl_high_n_s16(a: int32x4_t, b: int16x8_t, c: i16) -> int32x4_ } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2))] @@ -10053,6 +11711,8 @@ pub unsafe fn vqdmlsl_high_n_s32(a: int64x2_t, b: int32x4_t, c: i32) -> int64x2_ } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl, N = 2))] @@ -10064,6 +11724,8 @@ pub unsafe fn vqdmlsl_laneq_s16(a: int32x4_t, b: int16x4_t, c: int } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl, N = 1))] @@ -10075,6 +11737,8 @@ pub unsafe fn vqdmlsl_laneq_s32(a: int64x2_t, b: int32x2_t, c: int } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2, N = 1))] @@ -10086,6 +11750,8 @@ pub unsafe fn vqdmlsl_high_lane_s16(a: int32x4_t, b: int16x8_t, c: } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2, N = 1))] @@ -10097,6 +11763,8 @@ pub unsafe fn vqdmlsl_high_laneq_s16(a: int32x4_t, b: int16x8_t, c } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2, N = 1))] @@ -10108,6 +11776,8 @@ pub unsafe fn vqdmlsl_high_lane_s32(a: int64x2_t, b: int32x4_t, c: } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_high_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl2, N = 1))] @@ -10119,6 +11789,8 @@ pub unsafe fn vqdmlsl_high_laneq_s32(a: int64x2_t, b: int32x4_t, c } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlslh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -10129,6 +11801,8 @@ pub unsafe fn vqdmlslh_s16(a: i32, b: i16, c: i16) -> i32 { } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull))] @@ -10139,6 +11813,8 @@ pub unsafe fn vqdmlsls_s32(a: i64, b: i32, c: i32) -> i64 { } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlslh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl, LANE = 0))] @@ -10150,6 +11826,8 @@ pub unsafe fn vqdmlslh_lane_s16(a: i32, b: i16, c: int16x4_t) - } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlslh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmlsl, LANE = 0))] @@ -10161,6 +11839,8 @@ pub unsafe fn vqdmlslh_laneq_s16(a: i32, b: i16, c: int16x8_t) } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsls_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, LANE = 0))] @@ -10172,6 +11852,8 @@ pub unsafe fn vqdmlsls_lane_s32(a: i64, b: i32, c: int32x2_t) - } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsls_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmull, LANE = 0))] @@ -10183,6 +11865,8 @@ pub unsafe fn vqdmlsls_laneq_s32(a: i64, b: i32, c: int32x4_t) } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh))] @@ -10194,6 +11878,8 @@ pub unsafe fn vqdmulhh_s16(a: i16, b: i16) -> i16 { } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhs_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh))] @@ -10205,6 +11891,8 @@ pub unsafe fn vqdmulhs_s32(a: i32, b: i32) -> i32 { } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, N = 2))] @@ -10217,6 +11905,8 @@ pub unsafe fn vqdmulhh_lane_s16(a: i16, b: int16x4_t) -> i16 { } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, N = 2))] @@ -10229,6 +11919,8 @@ pub unsafe fn vqdmulhh_laneq_s16(a: i16, b: int16x8_t) -> i16 { } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhs_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, N = 1))] @@ -10241,6 +11933,8 @@ pub unsafe fn vqdmulhs_lane_s32(a: i32, b: int32x2_t) -> i32 { } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhs_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, N = 1))] @@ -10253,6 +11947,8 @@ pub unsafe fn vqdmulhs_laneq_s32(a: i32, b: int32x4_t) -> i32 { } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, LANE = 0))] @@ -10264,6 +11960,8 @@ pub unsafe fn vqdmulh_lane_s16(a: int16x4_t, b: int16x4_t) -> i } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, LANE = 0))] @@ -10275,6 +11973,8 @@ pub unsafe fn vqdmulhq_lane_s16(a: int16x8_t, b: int16x4_t) -> } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, LANE = 0))] @@ -10286,6 +11986,8 @@ pub unsafe fn vqdmulh_lane_s32(a: int32x2_t, b: int32x2_t) -> i } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqdmulh, LANE = 0))] @@ -10297,6 +11999,8 @@ pub unsafe fn vqdmulhq_lane_s32(a: int32x4_t, b: int32x2_t) -> } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovnh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn))] @@ -10306,6 +12010,8 @@ pub unsafe fn vqmovnh_s16(a: i16) -> i8 { } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovns_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn))] @@ -10315,6 +12021,8 @@ pub unsafe fn vqmovns_s32(a: i32) -> i16 { } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovnh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn))] @@ -10324,6 +12032,8 @@ pub unsafe fn vqmovnh_u16(a: u16) -> u8 { } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovns_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn))] @@ -10333,6 +12043,8 @@ pub unsafe fn vqmovns_u32(a: u32) -> u16 { } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovnd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn))] @@ -10347,6 +12059,8 @@ pub unsafe fn vqmovnd_s64(a: i64) -> i32 { } /// Saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovnd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn))] @@ -10361,6 +12075,8 @@ pub unsafe fn vqmovnd_u64(a: u64) -> u32 { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn2))] @@ -10370,6 +12086,8 @@ pub unsafe fn vqmovn_high_s16(a: int8x8_t, b: int16x8_t) -> int8x16_t { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn2))] @@ -10379,6 +12097,8 @@ pub unsafe fn vqmovn_high_s32(a: int16x4_t, b: int32x4_t) -> int16x8_t { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtn2))] @@ -10388,6 +12108,8 @@ pub unsafe fn vqmovn_high_s64(a: int32x2_t, b: int64x2_t) -> int32x4_t { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn2))] @@ -10397,6 +12119,8 @@ pub unsafe fn vqmovn_high_u16(a: uint8x8_t, b: uint16x8_t) -> uint8x16_t { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn2))] @@ -10406,6 +12130,8 @@ pub unsafe fn vqmovn_high_u32(a: uint16x4_t, b: uint32x4_t) -> uint16x8_t { } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_high_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqxtn2))] @@ -10415,6 +12141,8 @@ pub unsafe fn vqmovn_high_u64(a: uint32x2_t, b: uint64x2_t) -> uint32x4_t { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovunh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun))] @@ -10424,6 +12152,8 @@ pub unsafe fn vqmovunh_s16(a: i16) -> u8 { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovuns_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun))] @@ -10433,6 +12163,8 @@ pub unsafe fn vqmovuns_s32(a: i32) -> u16 { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovund_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun))] @@ -10442,6 +12174,8 @@ pub unsafe fn vqmovund_s64(a: i64) -> u32 { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun2))] @@ -10451,6 +12185,8 @@ pub unsafe fn vqmovun_high_s16(a: uint8x8_t, b: int16x8_t) -> uint8x16_t { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun2))] @@ -10460,6 +12196,8 @@ pub unsafe fn vqmovun_high_s32(a: uint16x4_t, b: int32x4_t) -> uint16x8_t { } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_high_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqxtun2))] @@ -10469,6 +12207,8 @@ pub unsafe fn vqmovun_high_s64(a: uint32x2_t, b: int64x2_t) -> uint32x4_t { } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh))] @@ -10478,6 +12218,8 @@ pub unsafe fn vqrdmulhh_s16(a: i16, b: i16) -> i16 { } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhs_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh))] @@ -10487,6 +12229,8 @@ pub unsafe fn vqrdmulhs_s32(a: i32, b: i32) -> i32 { } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh, LANE = 1))] @@ -10498,6 +12242,8 @@ pub unsafe fn vqrdmulhh_lane_s16(a: i16, b: int16x4_t) -> i16 { } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh, LANE = 1))] @@ -10509,6 +12255,8 @@ pub unsafe fn vqrdmulhh_laneq_s16(a: i16, b: int16x8_t) -> i16 } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhs_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh, LANE = 1))] @@ -10520,6 +12268,8 @@ pub unsafe fn vqrdmulhs_lane_s32(a: i32, b: int32x2_t) -> i32 { } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhs_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrdmulh, LANE = 1))] @@ -10531,6 +12281,8 @@ pub unsafe fn vqrdmulhs_laneq_s32(a: i32, b: int32x4_t) -> i32 } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10545,6 +12297,8 @@ pub unsafe fn vqrdmlah_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_ } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10559,6 +12313,8 @@ pub unsafe fn vqrdmlahq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8 } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10573,6 +12329,8 @@ pub unsafe fn vqrdmlah_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_ } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10587,6 +12345,8 @@ pub unsafe fn vqrdmlahq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4 } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahh_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10599,6 +12359,8 @@ pub unsafe fn vqrdmlahh_s16(a: i16, b: i16, c: i16) -> i16 { } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahs_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah))] @@ -10611,6 +12373,8 @@ pub unsafe fn vqrdmlahs_s32(a: i32, b: i32, c: i32) -> i32 { } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10623,6 +12387,8 @@ pub unsafe fn vqrdmlah_lane_s16(a: int16x4_t, b: int16x4_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10635,6 +12401,8 @@ pub unsafe fn vqrdmlah_laneq_s16(a: int16x4_t, b: int16x4_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10647,6 +12415,8 @@ pub unsafe fn vqrdmlahq_lane_s16(a: int16x8_t, b: int16x8_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10659,6 +12429,8 @@ pub unsafe fn vqrdmlahq_laneq_s16(a: int16x8_t, b: int16x8_t, c } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10671,6 +12443,8 @@ pub unsafe fn vqrdmlah_lane_s32(a: int32x2_t, b: int32x2_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlah_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10683,6 +12457,8 @@ pub unsafe fn vqrdmlah_laneq_s32(a: int32x2_t, b: int32x2_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10695,6 +12471,8 @@ pub unsafe fn vqrdmlahq_lane_s32(a: int32x4_t, b: int32x4_t, c: } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahq_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10707,6 +12485,8 @@ pub unsafe fn vqrdmlahq_laneq_s32(a: int32x4_t, b: int32x4_t, c } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahh_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10718,6 +12498,8 @@ pub unsafe fn vqrdmlahh_lane_s16(a: i16, b: i16, c: int16x4_t) } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahh_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10729,6 +12511,8 @@ pub unsafe fn vqrdmlahh_laneq_s16(a: i16, b: i16, c: int16x8_t) } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahs_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10740,6 +12524,8 @@ pub unsafe fn vqrdmlahs_lane_s32(a: i32, b: i32, c: int32x2_t) } /// Signed saturating rounding doubling multiply accumulate returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlahs_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlah, LANE = 1))] @@ -10751,6 +12537,8 @@ pub unsafe fn vqrdmlahs_laneq_s32(a: i32, b: i32, c: int32x4_t) } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10765,6 +12553,8 @@ pub unsafe fn vqrdmlsh_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_ } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10779,6 +12569,8 @@ pub unsafe fn vqrdmlshq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8 } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10793,6 +12585,8 @@ pub unsafe fn vqrdmlsh_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_ } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10807,6 +12601,8 @@ pub unsafe fn vqrdmlshq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4 } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshh_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10819,6 +12615,8 @@ pub unsafe fn vqrdmlshh_s16(a: i16, b: i16, c: i16) -> i16 { } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshs_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh))] @@ -10831,6 +12629,8 @@ pub unsafe fn vqrdmlshs_s32(a: i32, b: i32, c: i32) -> i32 { } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10843,6 +12643,8 @@ pub unsafe fn vqrdmlsh_lane_s16(a: int16x4_t, b: int16x4_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10855,6 +12657,8 @@ pub unsafe fn vqrdmlsh_laneq_s16(a: int16x4_t, b: int16x4_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10867,6 +12671,8 @@ pub unsafe fn vqrdmlshq_lane_s16(a: int16x8_t, b: int16x8_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10879,6 +12685,8 @@ pub unsafe fn vqrdmlshq_laneq_s16(a: int16x8_t, b: int16x8_t, c } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10891,6 +12699,8 @@ pub unsafe fn vqrdmlsh_lane_s32(a: int32x2_t, b: int32x2_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlsh_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10903,6 +12713,8 @@ pub unsafe fn vqrdmlsh_laneq_s32(a: int32x2_t, b: int32x2_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10915,6 +12727,8 @@ pub unsafe fn vqrdmlshq_lane_s32(a: int32x4_t, b: int32x4_t, c: } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshq_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10927,6 +12741,8 @@ pub unsafe fn vqrdmlshq_laneq_s32(a: int32x4_t, b: int32x4_t, c } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshh_lane_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10938,6 +12754,8 @@ pub unsafe fn vqrdmlshh_lane_s16(a: i16, b: i16, c: int16x4_t) } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshh_laneq_s16) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10949,6 +12767,8 @@ pub unsafe fn vqrdmlshh_laneq_s16(a: i16, b: i16, c: int16x8_t) } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshs_lane_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10960,6 +12780,8 @@ pub unsafe fn vqrdmlshs_lane_s32(a: i32, b: i32, c: int32x2_t) } /// Signed saturating rounding doubling multiply subtract returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmlshs_laneq_s32) #[inline] #[target_feature(enable = "rdm")] #[cfg_attr(test, assert_instr(sqrdmlsh, LANE = 1))] @@ -10971,6 +12793,8 @@ pub unsafe fn vqrdmlshs_laneq_s32(a: i32, b: i32, c: int32x4_t) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshl))] @@ -10985,6 +12809,8 @@ pub unsafe fn vqrshls_s32(a: i32, b: i32) -> i32 { } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshld_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshl))] @@ -10999,6 +12825,8 @@ pub unsafe fn vqrshld_s64(a: i64, b: i64) -> i64 { } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshl))] @@ -11010,6 +12838,8 @@ pub unsafe fn vqrshlb_s8(a: i8, b: i8) -> i8 { } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshl))] @@ -11021,6 +12851,8 @@ pub unsafe fn vqrshlh_s16(a: i16, b: i16) -> i16 { } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshls_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshl))] @@ -11035,6 +12867,8 @@ pub unsafe fn vqrshls_u32(a: u32, b: i32) -> u32 { } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshld_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshl))] @@ -11049,6 +12883,8 @@ pub unsafe fn vqrshld_u64(a: u64, b: i64) -> u64 { } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlb_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshl))] @@ -11060,6 +12896,8 @@ pub unsafe fn vqrshlb_u8(a: u8, b: i8) -> u8 { } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshl))] @@ -11071,6 +12909,8 @@ pub unsafe fn vqrshlh_u16(a: u16, b: i16) -> u16 { } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrnh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn, N = 2))] @@ -11083,6 +12923,8 @@ pub unsafe fn vqrshrnh_n_s16(a: i16) -> i8 { } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrns_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn, N = 2))] @@ -11095,6 +12937,8 @@ pub unsafe fn vqrshrns_n_s32(a: i32) -> i16 { } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrnd_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn, N = 2))] @@ -11107,6 +12951,8 @@ pub unsafe fn vqrshrnd_n_s64(a: i64) -> i32 { } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn2, N = 2))] @@ -11118,6 +12964,8 @@ pub unsafe fn vqrshrn_high_n_s16(a: int8x8_t, b: int16x8_t) -> int } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn2, N = 2))] @@ -11129,6 +12977,8 @@ pub unsafe fn vqrshrn_high_n_s32(a: int16x4_t, b: int32x4_t) -> in } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrn2, N = 2))] @@ -11140,6 +12990,8 @@ pub unsafe fn vqrshrn_high_n_s64(a: int32x2_t, b: int64x2_t) -> in } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrnh_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn, N = 2))] @@ -11152,6 +13004,8 @@ pub unsafe fn vqrshrnh_n_u16(a: u16) -> u8 { } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrns_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn, N = 2))] @@ -11164,6 +13018,8 @@ pub unsafe fn vqrshrns_n_u32(a: u32) -> u16 { } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrnd_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn, N = 2))] @@ -11176,6 +13032,8 @@ pub unsafe fn vqrshrnd_n_u64(a: u64) -> u32 { } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn2, N = 2))] @@ -11187,6 +13045,8 @@ pub unsafe fn vqrshrn_high_n_u16(a: uint8x8_t, b: uint16x8_t) -> u } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn2, N = 2))] @@ -11198,6 +13058,8 @@ pub unsafe fn vqrshrn_high_n_u32(a: uint16x4_t, b: uint32x4_t) -> } /// Unsigned saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_high_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqrshrn2, N = 2))] @@ -11209,6 +13071,8 @@ pub unsafe fn vqrshrn_high_n_u64(a: uint32x2_t, b: uint64x2_t) -> } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrunh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun, N = 2))] @@ -11221,6 +13085,8 @@ pub unsafe fn vqrshrunh_n_s16(a: i16) -> u8 { } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshruns_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun, N = 2))] @@ -11233,6 +13099,8 @@ pub unsafe fn vqrshruns_n_s32(a: i32) -> u16 { } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrund_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun, N = 2))] @@ -11245,6 +13113,8 @@ pub unsafe fn vqrshrund_n_s64(a: i64) -> u32 { } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun2, N = 2))] @@ -11256,6 +13126,8 @@ pub unsafe fn vqrshrun_high_n_s16(a: uint8x8_t, b: int16x8_t) -> u } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun2, N = 2))] @@ -11267,6 +13139,8 @@ pub unsafe fn vqrshrun_high_n_s32(a: uint16x4_t, b: int32x4_t) -> } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqrshrun2, N = 2))] @@ -11278,6 +13152,8 @@ pub unsafe fn vqrshrun_high_n_s64(a: uint32x2_t, b: int64x2_t) -> } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshld_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl))] @@ -11292,6 +13168,8 @@ pub unsafe fn vqshld_s64(a: i64, b: i64) -> i64 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl))] @@ -11302,6 +13180,8 @@ pub unsafe fn vqshlb_s8(a: i8, b: i8) -> i8 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl))] @@ -11312,6 +13192,8 @@ pub unsafe fn vqshlh_s16(a: i16, b: i16) -> i16 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl))] @@ -11322,6 +13204,8 @@ pub unsafe fn vqshls_s32(a: i32, b: i32) -> i32 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshld_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl))] @@ -11336,6 +13220,8 @@ pub unsafe fn vqshld_u64(a: u64, b: i64) -> u64 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlb_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl))] @@ -11346,6 +13232,8 @@ pub unsafe fn vqshlb_u8(a: u8, b: i8) -> u8 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl))] @@ -11356,6 +13244,8 @@ pub unsafe fn vqshlh_u16(a: u16, b: i16) -> u16 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshls_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl))] @@ -11366,6 +13256,8 @@ pub unsafe fn vqshls_u32(a: u32, b: i32) -> u32 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlb_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl, N = 2))] @@ -11377,6 +13269,8 @@ pub unsafe fn vqshlb_n_s8(a: i8) -> i8 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl, N = 2))] @@ -11388,6 +13282,8 @@ pub unsafe fn vqshlh_n_s16(a: i16) -> i16 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshls_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl, N = 2))] @@ -11399,6 +13295,8 @@ pub unsafe fn vqshls_n_s32(a: i32) -> i32 { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshld_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshl, N = 2))] @@ -11410,6 +13308,8 @@ pub unsafe fn vqshld_n_s64(a: i64) -> i64 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlb_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl, N = 2))] @@ -11421,6 +13321,8 @@ pub unsafe fn vqshlb_n_u8(a: u8) -> u8 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlh_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl, N = 2))] @@ -11432,6 +13334,8 @@ pub unsafe fn vqshlh_n_u16(a: u16) -> u16 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshls_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl, N = 2))] @@ -11443,6 +13347,8 @@ pub unsafe fn vqshls_n_u32(a: u32) -> u32 { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshld_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshl, N = 2))] @@ -11454,6 +13360,8 @@ pub unsafe fn vqshld_n_u64(a: u64) -> u64 { } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlub_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshlu, N = 2))] @@ -11465,6 +13373,8 @@ pub unsafe fn vqshlub_n_s8(a: i8) -> u8 { } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshlu, N = 2))] @@ -11476,6 +13386,8 @@ pub unsafe fn vqshluh_n_s16(a: i16) -> u16 { } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlus_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshlu, N = 2))] @@ -11487,6 +13399,8 @@ pub unsafe fn vqshlus_n_s32(a: i32) -> u32 { } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlud_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshlu, N = 2))] @@ -11498,6 +13412,8 @@ pub unsafe fn vqshlud_n_s64(a: i64) -> u64 { } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrnd_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn, N = 2))] @@ -11514,6 +13430,8 @@ pub unsafe fn vqshrnd_n_s64(a: i64) -> i32 { } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrnh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn, N = 2))] @@ -11525,6 +13443,8 @@ pub unsafe fn vqshrnh_n_s16(a: i16) -> i8 { } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrns_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn, N = 2))] @@ -11536,6 +13456,8 @@ pub unsafe fn vqshrns_n_s32(a: i32) -> i16 { } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn2, N = 2))] @@ -11547,6 +13469,8 @@ pub unsafe fn vqshrn_high_n_s16(a: int8x8_t, b: int16x8_t) -> int8 } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn2, N = 2))] @@ -11558,6 +13482,8 @@ pub unsafe fn vqshrn_high_n_s32(a: int16x4_t, b: int32x4_t) -> int } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrn2, N = 2))] @@ -11569,6 +13495,8 @@ pub unsafe fn vqshrn_high_n_s64(a: int32x2_t, b: int64x2_t) -> int } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrnd_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn, N = 2))] @@ -11585,6 +13513,8 @@ pub unsafe fn vqshrnd_n_u64(a: u64) -> u32 { } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrnh_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn, N = 2))] @@ -11596,6 +13526,8 @@ pub unsafe fn vqshrnh_n_u16(a: u16) -> u8 { } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrns_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn, N = 2))] @@ -11607,6 +13539,8 @@ pub unsafe fn vqshrns_n_u32(a: u32) -> u16 { } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn2, N = 2))] @@ -11618,6 +13552,8 @@ pub unsafe fn vqshrn_high_n_u16(a: uint8x8_t, b: uint16x8_t) -> ui } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn2, N = 2))] @@ -11629,6 +13565,8 @@ pub unsafe fn vqshrn_high_n_u32(a: uint16x4_t, b: uint32x4_t) -> u } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_high_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uqshrn2, N = 2))] @@ -11640,6 +13578,8 @@ pub unsafe fn vqshrn_high_n_u64(a: uint32x2_t, b: uint64x2_t) -> u } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrunh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun, N = 2))] @@ -11651,6 +13591,8 @@ pub unsafe fn vqshrunh_n_s16(a: i16) -> u8 { } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshruns_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun, N = 2))] @@ -11662,6 +13604,8 @@ pub unsafe fn vqshruns_n_s32(a: i32) -> u16 { } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrund_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun, N = 2))] @@ -11673,6 +13617,8 @@ pub unsafe fn vqshrund_n_s64(a: i64) -> u32 { } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun2, N = 2))] @@ -11684,6 +13630,8 @@ pub unsafe fn vqshrun_high_n_s16(a: uint8x8_t, b: int16x8_t) -> ui } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun2, N = 2))] @@ -11695,6 +13643,8 @@ pub unsafe fn vqshrun_high_n_s32(a: uint16x4_t, b: int32x4_t) -> u } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqshrun2, N = 2))] @@ -11706,6 +13656,8 @@ pub unsafe fn vqshrun_high_n_s64(a: uint32x2_t, b: int64x2_t) -> u } /// Unsigned saturating accumulate of signed value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqaddb_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usqadd))] @@ -11715,6 +13667,8 @@ pub unsafe fn vsqaddb_u8(a: u8, b: i8) -> u8 { } /// Unsigned saturating accumulate of signed value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqaddh_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usqadd))] @@ -11724,6 +13678,8 @@ pub unsafe fn vsqaddh_u16(a: u16, b: i16) -> u16 { } /// Unsigned saturating accumulate of signed value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqadds_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usqadd))] @@ -11738,6 +13694,8 @@ pub unsafe fn vsqadds_u32(a: u32, b: i32) -> u32 { } /// Unsigned saturating accumulate of signed value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqaddd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(usqadd))] @@ -11752,6 +13710,8 @@ pub unsafe fn vsqaddd_u64(a: u64, b: i64) -> u64 { } /// Calculates the square root of each lane. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqrt_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsqrt))] @@ -11761,6 +13721,8 @@ pub unsafe fn vsqrt_f32(a: float32x2_t) -> float32x2_t { } /// Calculates the square root of each lane. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqrtq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsqrt))] @@ -11770,6 +13732,8 @@ pub unsafe fn vsqrtq_f32(a: float32x4_t) -> float32x4_t { } /// Calculates the square root of each lane. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqrt_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsqrt))] @@ -11779,6 +13743,8 @@ pub unsafe fn vsqrt_f64(a: float64x1_t) -> float64x1_t { } /// Calculates the square root of each lane. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsqrtq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(fsqrt))] @@ -11788,6 +13754,8 @@ pub unsafe fn vsqrtq_f64(a: float64x2_t) -> float64x2_t { } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrte_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrte))] @@ -11802,6 +13770,8 @@ pub unsafe fn vrsqrte_f64(a: float64x1_t) -> float64x1_t { } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrteq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrte))] @@ -11816,6 +13786,8 @@ pub unsafe fn vrsqrteq_f64(a: float64x2_t) -> float64x2_t { } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrtes_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrte))] @@ -11830,6 +13802,8 @@ pub unsafe fn vrsqrtes_f32(a: f32) -> f32 { } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrted_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrte))] @@ -11844,6 +13818,8 @@ pub unsafe fn vrsqrted_f64(a: f64) -> f64 { } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrts_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrts))] @@ -11858,6 +13834,8 @@ pub unsafe fn vrsqrts_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrtsq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrts))] @@ -11872,6 +13850,8 @@ pub unsafe fn vrsqrtsq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrtss_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrts))] @@ -11886,6 +13866,8 @@ pub unsafe fn vrsqrtss_f32(a: f32, b: f32) -> f32 { } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrtsd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frsqrts))] @@ -11900,6 +13882,8 @@ pub unsafe fn vrsqrtsd_f64(a: f64, b: f64) -> f64 { } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpe_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpe))] @@ -11914,6 +13898,8 @@ pub unsafe fn vrecpe_f64(a: float64x1_t) -> float64x1_t { } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpeq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpe))] @@ -11928,6 +13914,8 @@ pub unsafe fn vrecpeq_f64(a: float64x2_t) -> float64x2_t { } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpes_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpe))] @@ -11942,6 +13930,8 @@ pub unsafe fn vrecpes_f32(a: f32) -> f32 { } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecped_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpe))] @@ -11956,6 +13946,8 @@ pub unsafe fn vrecped_f64(a: f64) -> f64 { } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecps_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecps))] @@ -11970,6 +13962,8 @@ pub unsafe fn vrecps_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpsq_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecps))] @@ -11984,6 +13978,8 @@ pub unsafe fn vrecpsq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpss_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecps))] @@ -11998,6 +13994,8 @@ pub unsafe fn vrecpss_f32(a: f32, b: f32) -> f32 { } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpsd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecps))] @@ -12012,6 +14010,8 @@ pub unsafe fn vrecpsd_f64(a: f64, b: f64) -> f64 { } /// Floating-point reciprocal exponent +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpxs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpx))] @@ -12026,6 +14026,8 @@ pub unsafe fn vrecpxs_f32(a: f32) -> f32 { } /// Floating-point reciprocal exponent +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpxd_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(frecpx))] @@ -12040,6 +14042,8 @@ pub unsafe fn vrecpxd_f64(a: f64) -> f64 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12049,6 +14053,8 @@ pub unsafe fn vreinterpret_s64_p64(a: poly64x1_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12058,6 +14064,8 @@ pub unsafe fn vreinterpret_u64_p64(a: poly64x1_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12067,6 +14075,8 @@ pub unsafe fn vreinterpret_p64_s64(a: int64x1_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12076,6 +14086,8 @@ pub unsafe fn vreinterpret_p64_u64(a: uint64x1_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12085,6 +14097,8 @@ pub unsafe fn vreinterpretq_s64_p64(a: poly64x2_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12094,6 +14108,8 @@ pub unsafe fn vreinterpretq_u64_p64(a: poly64x2_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12103,6 +14119,8 @@ pub unsafe fn vreinterpretq_p64_s64(a: int64x2_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12112,6 +14130,8 @@ pub unsafe fn vreinterpretq_p64_u64(a: uint64x2_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12121,6 +14141,8 @@ pub unsafe fn vreinterpret_s8_f64(a: float64x1_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12130,6 +14152,8 @@ pub unsafe fn vreinterpret_s16_f64(a: float64x1_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12139,6 +14163,8 @@ pub unsafe fn vreinterpret_s32_f64(a: float64x1_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12148,6 +14174,8 @@ pub unsafe fn vreinterpret_s64_f64(a: float64x1_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12157,6 +14185,8 @@ pub unsafe fn vreinterpretq_s8_f64(a: float64x2_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12166,6 +14196,8 @@ pub unsafe fn vreinterpretq_s16_f64(a: float64x2_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12175,6 +14207,8 @@ pub unsafe fn vreinterpretq_s32_f64(a: float64x2_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12184,6 +14218,8 @@ pub unsafe fn vreinterpretq_s64_f64(a: float64x2_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12193,6 +14229,8 @@ pub unsafe fn vreinterpret_u8_f64(a: float64x1_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12202,6 +14240,8 @@ pub unsafe fn vreinterpret_u16_f64(a: float64x1_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12211,6 +14251,8 @@ pub unsafe fn vreinterpret_u32_f64(a: float64x1_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12220,6 +14262,8 @@ pub unsafe fn vreinterpret_u64_f64(a: float64x1_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12229,6 +14273,8 @@ pub unsafe fn vreinterpretq_u8_f64(a: float64x2_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12238,6 +14284,8 @@ pub unsafe fn vreinterpretq_u16_f64(a: float64x2_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12247,6 +14295,8 @@ pub unsafe fn vreinterpretq_u32_f64(a: float64x2_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12256,6 +14306,8 @@ pub unsafe fn vreinterpretq_u64_f64(a: float64x2_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12265,6 +14317,8 @@ pub unsafe fn vreinterpret_p8_f64(a: float64x1_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12274,6 +14328,8 @@ pub unsafe fn vreinterpret_p16_f64(a: float64x1_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12283,6 +14339,8 @@ pub unsafe fn vreinterpret_p64_f32(a: float32x2_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12292,6 +14350,8 @@ pub unsafe fn vreinterpret_p64_f64(a: float64x1_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12301,6 +14361,8 @@ pub unsafe fn vreinterpretq_p8_f64(a: float64x2_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12310,6 +14372,8 @@ pub unsafe fn vreinterpretq_p16_f64(a: float64x2_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12319,6 +14383,8 @@ pub unsafe fn vreinterpretq_p64_f32(a: float32x4_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12328,6 +14394,8 @@ pub unsafe fn vreinterpretq_p64_f64(a: float64x2_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12337,6 +14405,8 @@ pub unsafe fn vreinterpretq_p128_f64(a: float64x2_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12346,6 +14416,8 @@ pub unsafe fn vreinterpret_f64_s8(a: int8x8_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12355,6 +14427,8 @@ pub unsafe fn vreinterpret_f64_s16(a: int16x4_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12364,6 +14438,8 @@ pub unsafe fn vreinterpret_f64_s32(a: int32x2_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12373,6 +14449,8 @@ pub unsafe fn vreinterpret_f64_s64(a: int64x1_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12382,6 +14460,8 @@ pub unsafe fn vreinterpretq_f64_s8(a: int8x16_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12391,6 +14471,8 @@ pub unsafe fn vreinterpretq_f64_s16(a: int16x8_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12400,6 +14482,8 @@ pub unsafe fn vreinterpretq_f64_s32(a: int32x4_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12409,6 +14493,8 @@ pub unsafe fn vreinterpretq_f64_s64(a: int64x2_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12418,6 +14504,8 @@ pub unsafe fn vreinterpret_f64_p8(a: poly8x8_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12427,6 +14515,8 @@ pub unsafe fn vreinterpret_f64_u16(a: uint16x4_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12436,6 +14526,8 @@ pub unsafe fn vreinterpret_f64_u32(a: uint32x2_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12445,6 +14537,8 @@ pub unsafe fn vreinterpret_f64_u64(a: uint64x1_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12454,6 +14548,8 @@ pub unsafe fn vreinterpretq_f64_p8(a: poly8x16_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12463,6 +14559,8 @@ pub unsafe fn vreinterpretq_f64_u16(a: uint16x8_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12472,6 +14570,8 @@ pub unsafe fn vreinterpretq_f64_u32(a: uint32x4_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12481,6 +14581,8 @@ pub unsafe fn vreinterpretq_f64_u64(a: uint64x2_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12490,6 +14592,8 @@ pub unsafe fn vreinterpret_f64_u8(a: uint8x8_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12499,6 +14603,8 @@ pub unsafe fn vreinterpret_f64_p16(a: poly16x4_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12508,6 +14614,8 @@ pub unsafe fn vreinterpret_f64_p64(a: poly64x1_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12517,6 +14625,8 @@ pub unsafe fn vreinterpret_f32_p64(a: poly64x1_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12526,6 +14636,8 @@ pub unsafe fn vreinterpretq_f64_u8(a: uint8x16_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12535,6 +14647,8 @@ pub unsafe fn vreinterpretq_f64_p16(a: poly16x8_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12544,6 +14658,8 @@ pub unsafe fn vreinterpretq_f64_p64(a: poly64x2_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12553,6 +14669,8 @@ pub unsafe fn vreinterpretq_f32_p64(a: poly64x2_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p128) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12562,6 +14680,8 @@ pub unsafe fn vreinterpretq_f64_p128(a: p128) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12571,6 +14691,8 @@ pub unsafe fn vreinterpret_f64_f32(a: float32x2_t) -> float64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12580,6 +14702,8 @@ pub unsafe fn vreinterpret_f32_f64(a: float64x1_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12589,6 +14713,8 @@ pub unsafe fn vreinterpretq_f64_f32(a: float32x4_t) -> float64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop))] @@ -12598,6 +14724,8 @@ pub unsafe fn vreinterpretq_f32_f64(a: float64x2_t) -> float32x4_t { } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshld_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(srshl))] @@ -12612,6 +14740,8 @@ pub unsafe fn vrshld_s64(a: i64, b: i64) -> i64 { } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshld_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(urshl))] @@ -12626,6 +14756,8 @@ pub unsafe fn vrshld_u64(a: u64, b: i64) -> u64 { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrd_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(srshr, N = 2))] @@ -12637,6 +14769,8 @@ pub unsafe fn vrshrd_n_s64(a: i64) -> i64 { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrd_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(urshr, N = 2))] @@ -12648,6 +14782,8 @@ pub unsafe fn vrshrd_n_u64(a: u64) -> u64 { } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12659,6 +14795,8 @@ pub unsafe fn vrshrn_high_n_s16(a: int8x8_t, b: int16x8_t) -> int8 } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12670,6 +14808,8 @@ pub unsafe fn vrshrn_high_n_s32(a: int16x4_t, b: int32x4_t) -> int } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12681,6 +14821,8 @@ pub unsafe fn vrshrn_high_n_s64(a: int32x2_t, b: int64x2_t) -> int } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12692,6 +14834,8 @@ pub unsafe fn vrshrn_high_n_u16(a: uint8x8_t, b: uint16x8_t) -> ui } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12703,6 +14847,8 @@ pub unsafe fn vrshrn_high_n_u32(a: uint16x4_t, b: uint32x4_t) -> u } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_high_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rshrn2, N = 2))] @@ -12714,6 +14860,8 @@ pub unsafe fn vrshrn_high_n_u64(a: uint32x2_t, b: uint64x2_t) -> u } /// Signed rounding shift right and accumulate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsrad_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(srsra, N = 2))] @@ -12726,6 +14874,8 @@ pub unsafe fn vrsrad_n_s64(a: i64, b: i64) -> i64 { } /// Ungisned rounding shift right and accumulate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsrad_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ursra, N = 2))] @@ -12738,6 +14888,8 @@ pub unsafe fn vrsrad_n_u64(a: u64, b: u64) -> u64 { } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12748,6 +14900,8 @@ pub unsafe fn vrsubhn_high_s16(a: int8x8_t, b: int16x8_t, c: int16x8_t) -> int8x } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12758,6 +14912,8 @@ pub unsafe fn vrsubhn_high_s32(a: int16x4_t, b: int32x4_t, c: int32x4_t) -> int1 } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12768,6 +14924,8 @@ pub unsafe fn vrsubhn_high_s64(a: int32x2_t, b: int64x2_t, c: int64x2_t) -> int3 } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12778,6 +14936,8 @@ pub unsafe fn vrsubhn_high_u16(a: uint8x8_t, b: uint16x8_t, c: uint16x8_t) -> ui } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12788,6 +14948,8 @@ pub unsafe fn vrsubhn_high_u32(a: uint16x4_t, b: uint32x4_t, c: uint32x4_t) -> u } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_high_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(rsubhn2))] @@ -12798,6 +14960,8 @@ pub unsafe fn vrsubhn_high_u64(a: uint32x2_t, b: uint64x2_t, c: uint64x2_t) -> u } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, LANE = 0))] @@ -12809,6 +14973,8 @@ pub unsafe fn vset_lane_f64(a: f64, b: float64x1_t) -> float64x } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(nop, LANE = 0))] @@ -12820,6 +14986,8 @@ pub unsafe fn vsetq_lane_f64(a: f64, b: float64x2_t) -> float64 } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshld_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sshl))] @@ -12829,6 +14997,8 @@ pub unsafe fn vshld_s64(a: i64, b: i64) -> i64 { } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshld_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ushl))] @@ -12838,6 +15008,8 @@ pub unsafe fn vshld_u64(a: u64, b: i64) -> u64 { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sshll2, N = 2))] @@ -12850,6 +15022,8 @@ pub unsafe fn vshll_high_n_s8(a: int8x16_t) -> int16x8_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sshll2, N = 2))] @@ -12862,6 +15036,8 @@ pub unsafe fn vshll_high_n_s16(a: int16x8_t) -> int32x4_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sshll2, N = 2))] @@ -12874,6 +15050,8 @@ pub unsafe fn vshll_high_n_s32(a: int32x4_t) -> int64x2_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ushll2, N = 2))] @@ -12886,6 +15064,8 @@ pub unsafe fn vshll_high_n_u8(a: uint8x16_t) -> uint16x8_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ushll2, N = 2))] @@ -12898,6 +15078,8 @@ pub unsafe fn vshll_high_n_u16(a: uint16x8_t) -> uint32x4_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(ushll2, N = 2))] @@ -12910,6 +15092,8 @@ pub unsafe fn vshll_high_n_u32(a: uint32x4_t) -> uint64x2_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12921,6 +15105,8 @@ pub unsafe fn vshrn_high_n_s16(a: int8x8_t, b: int16x8_t) -> int8x } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12932,6 +15118,8 @@ pub unsafe fn vshrn_high_n_s32(a: int16x4_t, b: int32x4_t) -> int1 } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12943,6 +15131,8 @@ pub unsafe fn vshrn_high_n_s64(a: int32x2_t, b: int64x2_t) -> int3 } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12954,6 +15144,8 @@ pub unsafe fn vshrn_high_n_u16(a: uint8x8_t, b: uint16x8_t) -> uin } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12965,6 +15157,8 @@ pub unsafe fn vshrn_high_n_u32(a: uint16x4_t, b: uint32x4_t) -> ui } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_high_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(shrn2, N = 2))] @@ -12976,6 +15170,8 @@ pub unsafe fn vshrn_high_n_u64(a: uint32x2_t, b: uint64x2_t) -> ui } /// SM3PARTW1 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsm3partw1q_u32) #[inline] #[target_feature(enable = "neon,sm4")] #[cfg_attr(test, assert_instr(sm3partw1))] @@ -12989,6 +15185,8 @@ pub unsafe fn vsm3partw1q_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> ui } /// SM3PARTW2 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsm3partw2q_u32) #[inline] #[target_feature(enable = "neon,sm4")] #[cfg_attr(test, assert_instr(sm3partw2))] @@ -13002,6 +15200,8 @@ pub unsafe fn vsm3partw2q_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> ui } /// SM3SS1 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsm3ss1q_u32) #[inline] #[target_feature(enable = "neon,sm4")] #[cfg_attr(test, assert_instr(sm3ss1))] @@ -13015,6 +15215,8 @@ pub unsafe fn vsm3ss1q_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint3 } /// SM4 key +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsm4ekeyq_u32) #[inline] #[target_feature(enable = "neon,sm4")] #[cfg_attr(test, assert_instr(sm4ekey))] @@ -13028,6 +15230,8 @@ pub unsafe fn vsm4ekeyq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// SM4 encode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsm4eq_u32) #[inline] #[target_feature(enable = "neon,sm4")] #[cfg_attr(test, assert_instr(sm4e))] @@ -13041,6 +15245,8 @@ pub unsafe fn vsm4eq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Rotate and exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrax1q_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(rax1))] @@ -13054,6 +15260,8 @@ pub unsafe fn vrax1q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// SHA512 hash update part 1 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha512hq_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(sha512h))] @@ -13067,6 +15275,8 @@ pub unsafe fn vsha512hq_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint } /// SHA512 hash update part 2 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha512h2q_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(sha512h2))] @@ -13080,6 +15290,8 @@ pub unsafe fn vsha512h2q_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uin } /// SHA512 schedule update 0 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha512su0q_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(sha512su0))] @@ -13093,6 +15305,8 @@ pub unsafe fn vsha512su0q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// SHA512 schedule update 1 +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha512su1q_u64) #[inline] #[target_feature(enable = "neon,sha3")] #[cfg_attr(test, assert_instr(sha512su1))] @@ -13106,6 +15320,8 @@ pub unsafe fn vsha512su1q_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> ui } /// Floating-point round to 32-bit integer, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd32x_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint32x))] @@ -13119,6 +15335,8 @@ pub unsafe fn vrnd32x_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to 32-bit integer, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd32xq_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint32x))] @@ -13132,6 +15350,8 @@ pub unsafe fn vrnd32xq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to 32-bit integer toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd32z_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint32z))] @@ -13145,6 +15365,8 @@ pub unsafe fn vrnd32z_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to 32-bit integer toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd32zq_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint32z))] @@ -13158,6 +15380,8 @@ pub unsafe fn vrnd32zq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to 64-bit integer, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd64x_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint64x))] @@ -13171,6 +15395,8 @@ pub unsafe fn vrnd64x_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to 64-bit integer, using current rounding mode +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd64xq_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint64x))] @@ -13184,6 +15410,8 @@ pub unsafe fn vrnd64xq_f32(a: float32x4_t) -> float32x4_t { } /// Floating-point round to 64-bit integer toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd64z_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint64z))] @@ -13197,6 +15425,8 @@ pub unsafe fn vrnd64z_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point round to 64-bit integer toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd64zq_f32) #[inline] #[target_feature(enable = "neon,frintts")] #[cfg_attr(test, assert_instr(frint64z))] @@ -13210,6 +15440,8 @@ pub unsafe fn vrnd64zq_f32(a: float32x4_t) -> float32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13219,6 +15451,8 @@ pub unsafe fn vtrn1_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13228,6 +15462,8 @@ pub unsafe fn vtrn1q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13237,6 +15473,8 @@ pub unsafe fn vtrn1_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13246,6 +15484,8 @@ pub unsafe fn vtrn1q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13255,6 +15495,8 @@ pub unsafe fn vtrn1q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13264,6 +15506,8 @@ pub unsafe fn vtrn1_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13273,6 +15517,8 @@ pub unsafe fn vtrn1q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13282,6 +15528,8 @@ pub unsafe fn vtrn1_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13291,6 +15539,8 @@ pub unsafe fn vtrn1q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13300,6 +15550,8 @@ pub unsafe fn vtrn1q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13309,6 +15561,8 @@ pub unsafe fn vtrn1_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13318,6 +15572,8 @@ pub unsafe fn vtrn1q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13327,6 +15583,8 @@ pub unsafe fn vtrn1_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13336,6 +15594,8 @@ pub unsafe fn vtrn1q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13345,6 +15605,8 @@ pub unsafe fn vtrn1_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13354,6 +15616,8 @@ pub unsafe fn vtrn1q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13363,6 +15627,8 @@ pub unsafe fn vtrn1_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13372,6 +15638,8 @@ pub unsafe fn vtrn1q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13381,6 +15649,8 @@ pub unsafe fn vtrn1q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn1))] @@ -13390,6 +15660,8 @@ pub unsafe fn vtrn1q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13399,6 +15671,8 @@ pub unsafe fn vtrn1_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn1q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13408,6 +15682,8 @@ pub unsafe fn vtrn1q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13417,6 +15693,8 @@ pub unsafe fn vtrn2_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13426,6 +15704,8 @@ pub unsafe fn vtrn2q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13435,6 +15715,8 @@ pub unsafe fn vtrn2_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13444,6 +15726,8 @@ pub unsafe fn vtrn2q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13453,6 +15737,8 @@ pub unsafe fn vtrn2q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13462,6 +15748,8 @@ pub unsafe fn vtrn2_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13471,6 +15759,8 @@ pub unsafe fn vtrn2q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13480,6 +15770,8 @@ pub unsafe fn vtrn2_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13489,6 +15781,8 @@ pub unsafe fn vtrn2q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13498,6 +15792,8 @@ pub unsafe fn vtrn2q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13507,6 +15803,8 @@ pub unsafe fn vtrn2_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13516,6 +15814,8 @@ pub unsafe fn vtrn2q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13525,6 +15825,8 @@ pub unsafe fn vtrn2_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13534,6 +15836,8 @@ pub unsafe fn vtrn2q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13543,6 +15847,8 @@ pub unsafe fn vtrn2_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13552,6 +15858,8 @@ pub unsafe fn vtrn2q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13561,6 +15869,8 @@ pub unsafe fn vtrn2_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13570,6 +15880,8 @@ pub unsafe fn vtrn2q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13579,6 +15891,8 @@ pub unsafe fn vtrn2q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(trn2))] @@ -13588,6 +15902,8 @@ pub unsafe fn vtrn2q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13597,6 +15913,8 @@ pub unsafe fn vtrn2_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Transpose vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn2q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13606,6 +15924,8 @@ pub unsafe fn vtrn2q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13615,6 +15935,8 @@ pub unsafe fn vzip1_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13624,6 +15946,8 @@ pub unsafe fn vzip1q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13633,6 +15957,8 @@ pub unsafe fn vzip1_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13642,6 +15968,8 @@ pub unsafe fn vzip1q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13651,6 +15979,8 @@ pub unsafe fn vzip1_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13660,6 +15990,8 @@ pub unsafe fn vzip1q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13669,6 +16001,8 @@ pub unsafe fn vzip1q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13678,6 +16012,8 @@ pub unsafe fn vzip1_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13687,6 +16023,8 @@ pub unsafe fn vzip1q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13696,6 +16034,8 @@ pub unsafe fn vzip1_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13705,6 +16045,8 @@ pub unsafe fn vzip1q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13714,6 +16056,8 @@ pub unsafe fn vzip1_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13723,6 +16067,8 @@ pub unsafe fn vzip1q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13732,6 +16078,8 @@ pub unsafe fn vzip1q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13741,6 +16089,8 @@ pub unsafe fn vzip1_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13750,6 +16100,8 @@ pub unsafe fn vzip1q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13759,6 +16111,8 @@ pub unsafe fn vzip1_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13768,6 +16122,8 @@ pub unsafe fn vzip1q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13777,6 +16133,8 @@ pub unsafe fn vzip1q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13786,6 +16144,8 @@ pub unsafe fn vzip1_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13795,6 +16155,8 @@ pub unsafe fn vzip1q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip1q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -13804,6 +16166,8 @@ pub unsafe fn vzip1q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13813,6 +16177,8 @@ pub unsafe fn vzip2_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13822,6 +16188,8 @@ pub unsafe fn vzip2q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13831,6 +16199,8 @@ pub unsafe fn vzip2_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13840,6 +16210,8 @@ pub unsafe fn vzip2q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13849,6 +16221,8 @@ pub unsafe fn vzip2_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13858,6 +16232,8 @@ pub unsafe fn vzip2q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13867,6 +16243,8 @@ pub unsafe fn vzip2q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13876,6 +16254,8 @@ pub unsafe fn vzip2_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13885,6 +16265,8 @@ pub unsafe fn vzip2q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13894,6 +16276,8 @@ pub unsafe fn vzip2_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13903,6 +16287,8 @@ pub unsafe fn vzip2q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13912,6 +16298,8 @@ pub unsafe fn vzip2_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13921,6 +16309,8 @@ pub unsafe fn vzip2q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13930,6 +16320,8 @@ pub unsafe fn vzip2q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13939,6 +16331,8 @@ pub unsafe fn vzip2_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13948,6 +16342,8 @@ pub unsafe fn vzip2q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13957,6 +16353,8 @@ pub unsafe fn vzip2_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13966,6 +16364,8 @@ pub unsafe fn vzip2q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13975,6 +16375,8 @@ pub unsafe fn vzip2q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13984,6 +16386,8 @@ pub unsafe fn vzip2_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -13993,6 +16397,8 @@ pub unsafe fn vzip2q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip2q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14002,6 +16408,8 @@ pub unsafe fn vzip2q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14011,6 +16419,8 @@ pub unsafe fn vuzp1_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14020,6 +16430,8 @@ pub unsafe fn vuzp1q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14029,6 +16441,8 @@ pub unsafe fn vuzp1_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14038,6 +16452,8 @@ pub unsafe fn vuzp1q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14047,6 +16463,8 @@ pub unsafe fn vuzp1q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14056,6 +16474,8 @@ pub unsafe fn vuzp1_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14065,6 +16485,8 @@ pub unsafe fn vuzp1q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14074,6 +16496,8 @@ pub unsafe fn vuzp1_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14083,6 +16507,8 @@ pub unsafe fn vuzp1q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14092,6 +16518,8 @@ pub unsafe fn vuzp1q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14101,6 +16529,8 @@ pub unsafe fn vuzp1_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14110,6 +16540,8 @@ pub unsafe fn vuzp1q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14119,6 +16551,8 @@ pub unsafe fn vuzp1_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14128,6 +16562,8 @@ pub unsafe fn vuzp1q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14137,6 +16573,8 @@ pub unsafe fn vuzp1_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14146,6 +16584,8 @@ pub unsafe fn vuzp1q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14155,6 +16595,8 @@ pub unsafe fn vuzp1_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14164,6 +16606,8 @@ pub unsafe fn vuzp1q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14173,6 +16617,8 @@ pub unsafe fn vuzp1q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp1))] @@ -14182,6 +16628,8 @@ pub unsafe fn vuzp1q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14191,6 +16639,8 @@ pub unsafe fn vuzp1_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp1q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip1))] @@ -14200,6 +16650,8 @@ pub unsafe fn vuzp1q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14209,6 +16661,8 @@ pub unsafe fn vuzp2_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14218,6 +16672,8 @@ pub unsafe fn vuzp2q_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14227,6 +16683,8 @@ pub unsafe fn vuzp2_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14236,6 +16694,8 @@ pub unsafe fn vuzp2q_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14245,6 +16705,8 @@ pub unsafe fn vuzp2q_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14254,6 +16716,8 @@ pub unsafe fn vuzp2_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14263,6 +16727,8 @@ pub unsafe fn vuzp2q_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14272,6 +16738,8 @@ pub unsafe fn vuzp2_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14281,6 +16749,8 @@ pub unsafe fn vuzp2q_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14290,6 +16760,8 @@ pub unsafe fn vuzp2q_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14299,6 +16771,8 @@ pub unsafe fn vuzp2_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14308,6 +16782,8 @@ pub unsafe fn vuzp2q_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14317,6 +16793,8 @@ pub unsafe fn vuzp2_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14326,6 +16804,8 @@ pub unsafe fn vuzp2q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14335,6 +16815,8 @@ pub unsafe fn vuzp2_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14344,6 +16826,8 @@ pub unsafe fn vuzp2q_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14353,6 +16837,8 @@ pub unsafe fn vuzp2_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14362,6 +16848,8 @@ pub unsafe fn vuzp2q_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14371,6 +16859,8 @@ pub unsafe fn vuzp2q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uzp2))] @@ -14380,6 +16870,8 @@ pub unsafe fn vuzp2q_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14389,6 +16881,8 @@ pub unsafe fn vuzp2_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp2q_f64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(zip2))] @@ -14398,6 +16892,8 @@ pub unsafe fn vuzp2q_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabal))] @@ -14410,6 +16906,8 @@ pub unsafe fn vabal_high_u8(a: uint16x8_t, b: uint8x16_t, c: uint8x16_t) -> uint } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabal))] @@ -14422,6 +16920,8 @@ pub unsafe fn vabal_high_u16(a: uint32x4_t, b: uint16x8_t, c: uint16x8_t) -> uin } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(uabal))] @@ -14434,6 +16934,8 @@ pub unsafe fn vabal_high_u32(a: uint64x2_t, b: uint32x4_t, c: uint32x4_t) -> uin } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabal))] @@ -14447,6 +16949,8 @@ pub unsafe fn vabal_high_s8(a: int16x8_t, b: int8x16_t, c: int8x16_t) -> int16x8 } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabal))] @@ -14460,6 +16964,8 @@ pub unsafe fn vabal_high_s16(a: int32x4_t, b: int16x8_t, c: int16x8_t) -> int32x } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sabal))] @@ -14473,6 +16979,8 @@ pub unsafe fn vabal_high_s32(a: int64x2_t, b: int32x4_t, c: int32x4_t) -> int64x } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabs_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14487,6 +16995,8 @@ pub unsafe fn vqabs_s64(a: int64x1_t) -> int64x1_t { } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14501,6 +17011,8 @@ pub unsafe fn vqabsq_s64(a: int64x2_t) -> int64x2_t { } /// Signed saturating absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsb_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14510,6 +17022,8 @@ pub unsafe fn vqabsb_s8(a: i8) -> i8 { } /// Signed saturating absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14519,6 +17033,8 @@ pub unsafe fn vqabsh_s16(a: i16) -> i16 { } /// Signed saturating absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabss_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14533,6 +17049,8 @@ pub unsafe fn vqabss_s32(a: i32) -> i32 { } /// Signed saturating absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sqabs))] @@ -14547,6 +17065,8 @@ pub unsafe fn vqabsd_s64(a: i64) -> i64 { } /// Shift left and insert +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vslid_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sli, N = 2))] @@ -14558,6 +17078,8 @@ pub unsafe fn vslid_n_s64(a: i64, b: i64) -> i64 { } /// Shift left and insert +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vslid_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sli, N = 2))] @@ -14569,6 +17091,8 @@ pub unsafe fn vslid_n_u64(a: u64, b: u64) -> u64 { } /// Shift right and insert +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsrid_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sri, N = 2))] @@ -14580,6 +17104,8 @@ pub unsafe fn vsrid_n_s64(a: i64, b: i64) -> i64 { } /// Shift right and insert +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsrid_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(sri, N = 2))] @@ -17603,18 +20129,18 @@ mod test { #[simd_test(enable = "neon")] unsafe fn test_vextq_p64() { - let a: i64x2 = i64x2::new(0, 8); - let b: i64x2 = i64x2::new(9, 11); - let e: i64x2 = i64x2::new(8, 9); + let a: i64x2 = i64x2::new(1, 1); + let b: i64x2 = i64x2::new(2, 2); + let e: i64x2 = i64x2::new(1, 2); let r: i64x2 = transmute(vextq_p64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_f64() { - let a: f64x2 = f64x2::new(0., 2.); - let b: f64x2 = f64x2::new(3., 4.); - let e: f64x2 = f64x2::new(2., 3.); + let a: f64x2 = f64x2::new(1., 1.); + let b: f64x2 = f64x2::new(2., 2.); + let e: f64x2 = f64x2::new(1., 2.); let r: f64x2 = transmute(vextq_f64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs index 65ba527ee..9d9946b4f 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs @@ -28,14 +28,17 @@ types! { } /// ARM-specific type containing two `float64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x1x2_t(pub float64x1_t, pub float64x1_t); /// ARM-specific type containing three `float64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x1x3_t(pub float64x1_t, pub float64x1_t, pub float64x1_t); /// ARM-specific type containing four `float64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x1x4_t( @@ -46,14 +49,17 @@ pub struct float64x1x4_t( ); /// ARM-specific type containing two `float64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x2x2_t(pub float64x2_t, pub float64x2_t); /// ARM-specific type containing three `float64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x2x3_t(pub float64x2_t, pub float64x2_t, pub float64x2_t); /// ARM-specific type containing four `float64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub struct float64x2x4_t( @@ -658,6 +664,8 @@ pub unsafe fn vld1q_p16(ptr: *const p16) -> poly16x8_t { } /// Load multiple single-element structures to one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ldr))] @@ -667,6 +675,8 @@ pub unsafe fn vld1_p64(ptr: *const p64) -> poly64x1_t { } /// Load multiple single-element structures to one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(ldr))] @@ -953,6 +963,8 @@ pub unsafe fn vst1q_p16(ptr: *mut p16, a: poly16x8_t) { } // Store multiple single-element structures from one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(str))] @@ -963,6 +975,8 @@ pub unsafe fn vst1_p64(ptr: *mut p64, a: poly64x1_t) { } // Store multiple single-element structures from one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(str))] @@ -1045,7 +1059,11 @@ pub unsafe fn vabsq_s64(a: int64x2_t) -> int64x2_t { #[cfg_attr(test, assert_instr(bsl))] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub unsafe fn vbsl_f64(a: uint64x1_t, b: float64x1_t, c: float64x1_t) -> float64x1_t { - simd_select(transmute::<_, int64x1_t>(a), b, c) + let not = int64x1_t(-1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. #[inline] @@ -1053,7 +1071,11 @@ pub unsafe fn vbsl_f64(a: uint64x1_t, b: float64x1_t, c: float64x1_t) -> float64 #[cfg_attr(test, assert_instr(bsl))] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub unsafe fn vbsl_p64(a: poly64x1_t, b: poly64x1_t, c: poly64x1_t) -> poly64x1_t { - simd_select(transmute::<_, int64x1_t>(a), b, c) + let not = int64x1_t(-1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) #[inline] @@ -1061,7 +1083,11 @@ pub unsafe fn vbsl_p64(a: poly64x1_t, b: poly64x1_t, c: poly64x1_t) -> poly64x1_ #[cfg_attr(test, assert_instr(bsl))] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub unsafe fn vbslq_f64(a: uint64x2_t, b: float64x2_t, c: float64x2_t) -> float64x2_t { - simd_select(transmute::<_, int64x2_t>(a), b, c) + let not = int64x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) #[inline] @@ -1069,7 +1095,11 @@ pub unsafe fn vbslq_f64(a: uint64x2_t, b: float64x2_t, c: float64x2_t) -> float6 #[cfg_attr(test, assert_instr(bsl))] #[stable(feature = "neon_intrinsics", since = "1.59.0")] pub unsafe fn vbslq_p64(a: poly64x2_t, b: poly64x2_t, c: poly64x2_t) -> poly64x2_t { - simd_select(transmute::<_, int64x2_t>(a), b, c) + let not = int64x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Signed saturating Accumulate of Unsigned value. @@ -3365,7 +3395,10 @@ pub unsafe fn vsliq_n_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x static_assert_imm4!(N); transmute(vsliq_n_s16_(transmute(a), transmute(b), N)) } + /// Shift Left and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsli_n_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(sli, N = 1))] @@ -3375,7 +3408,10 @@ pub unsafe fn vsli_n_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x1 static_assert!(N: i32 where N >= 0 && N <= 63); transmute(vsli_n_s64_(transmute(a), transmute(b), N)) } + /// Shift Left and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsliq_n_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(sli, N = 1))] @@ -3585,7 +3621,10 @@ pub unsafe fn vsriq_n_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x static_assert!(N: i32 where N >= 1 && N <= 16); transmute(vsriq_n_s16_(transmute(a), transmute(b), N)) } + /// Shift Right and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsri_n_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(sri, N = 1))] @@ -3595,7 +3634,10 @@ pub unsafe fn vsri_n_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x1 static_assert!(N: i32 where N >= 1 && N <= 64); transmute(vsri_n_s64_(transmute(a), transmute(b), N)) } + /// Shift Right and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsriq_n_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(sri, N = 1))] @@ -5136,37 +5178,37 @@ mod tests { #[simd_test(enable = "neon")] unsafe fn test_vbsl_f64() { - let a = u64x1::new(u64::MAX); - let b = f64x1::new(f64::MAX); - let c = f64x1::new(f64::MIN); - let e = f64x1::new(f64::MAX); + let a = u64x1::new(0x8000000000000000); + let b = f64x1::new(-1.23f64); + let c = f64x1::new(2.34f64); + let e = f64x1::new(-2.34f64); let r: f64x1 = transmute(vbsl_f64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_p64() { - let a = u64x1::new(u64::MAX); + let a = u64x1::new(1); let b = u64x1::new(u64::MAX); let c = u64x1::new(u64::MIN); - let e = u64x1::new(u64::MAX); + let e = u64x1::new(1); let r: u64x1 = transmute(vbsl_p64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbslq_f64() { - let a = u64x2::new(u64::MAX, 0); - let b = f64x2::new(f64::MAX, f64::MAX); - let c = f64x2::new(f64::MIN, f64::MIN); - let e = f64x2::new(f64::MAX, f64::MIN); + let a = u64x2::new(1, 0x8000000000000000); + let b = f64x2::new(f64::MAX, -1.23f64); + let c = f64x2::new(f64::MIN, 2.34f64); + let e = f64x2::new(f64::MIN, -2.34f64); let r: f64x2 = transmute(vbslq_f64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbslq_p64() { - let a = u64x2::new(u64::MAX, 0); + let a = u64x2::new(u64::MAX, 1); let b = u64x2::new(u64::MAX, u64::MAX); let c = u64x2::new(u64::MIN, u64::MIN); - let e = u64x2::new(u64::MAX, u64::MIN); + let e = u64x2::new(u64::MAX, 1); let r: u64x2 = transmute(vbslq_p64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } diff --git a/library/stdarch/crates/core_arch/src/arm/neon.rs b/library/stdarch/crates/core_arch/src/arm/neon.rs index a0ad92c33..a6291c95c 100644 --- a/library/stdarch/crates/core_arch/src/arm/neon.rs +++ b/library/stdarch/crates/core_arch/src/arm/neon.rs @@ -289,6 +289,8 @@ pub unsafe fn vld1q_p16(ptr: *const p16) -> poly16x8_t { } /// Load multiple single-element structures to one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr(vldr))] @@ -297,6 +299,8 @@ pub unsafe fn vld1_p64(ptr: *const p64) -> poly64x1_t { } /// Load multiple single-element structures to one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(test, assert_instr("vld1.64"))] @@ -481,6 +485,8 @@ pub unsafe fn vst1q_p16(ptr: *mut p16, a: poly16x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p64) #[inline] #[target_feature(enable = "neon,aes,v8")] #[cfg_attr(test, assert_instr("vst1.64"))] @@ -489,6 +495,8 @@ pub unsafe fn vst1_p64(ptr: *mut p64, a: poly64x1_t) { } /// Store multiple single-element structures from one, two, three, or four registers. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p64) #[inline] #[target_feature(enable = "neon,aes,v8")] #[cfg_attr(test, assert_instr("vst1.64"))] @@ -1033,6 +1041,7 @@ pub unsafe fn vsli_n_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4 int16x4_t(n, n, n, n), )) } + /// Shift Left and Insert (immediate) #[inline] #[target_feature(enable = "neon,v7")] @@ -1047,7 +1056,10 @@ pub unsafe fn vsliq_n_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x int16x8_t(n, n, n, n, n, n, n, n), )) } + /// Shift Left and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsli_n_p64) #[inline] #[target_feature(enable = "neon,v7,aes")] #[cfg_attr(test, assert_instr("vsli.64", N = 1))] @@ -1060,7 +1072,10 @@ pub unsafe fn vsli_n_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x1 int64x1_t(N as i64), )) } + /// Shift Left and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsliq_n_p64) #[inline] #[target_feature(enable = "neon,v7,aes")] #[cfg_attr(test, assert_instr("vsli.64", N = 1))] @@ -1317,7 +1332,10 @@ pub unsafe fn vsriq_n_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x int16x8_t(n, n, n, n, n, n, n, n), )) } + /// Shift Right and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsri_n_p64) #[inline] #[target_feature(enable = "neon,v7,aes")] #[cfg_attr(test, assert_instr("vsri.64", N = 1))] @@ -1330,7 +1348,10 @@ pub unsafe fn vsri_n_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x1 int64x1_t(-N as i64), )) } + /// Shift Right and Insert (immediate) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsriq_n_p64) #[inline] #[target_feature(enable = "neon,v7,aes")] #[cfg_attr(test, assert_instr("vsri.64", N = 1))] diff --git a/library/stdarch/crates/core_arch/src/arm/v7.rs b/library/stdarch/crates/core_arch/src/arm/v7.rs index e7507f9b9..59beaf722 100644 --- a/library/stdarch/crates/core_arch/src/arm/v7.rs +++ b/library/stdarch/crates/core_arch/src/arm/v7.rs @@ -76,7 +76,6 @@ mod tests { } #[test] - #[cfg(dont_compile_me)] // FIXME need to add `v7` upstream in rustc fn _rbit_u32() { unsafe { assert_eq!( diff --git a/library/stdarch/crates/core_arch/src/arm_shared/crc.rs b/library/stdarch/crates/core_arch/src/arm_shared/crc.rs index e0d0fbe35..779d1ed42 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/crc.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/crc.rs @@ -24,6 +24,8 @@ extern "unadjusted" { use stdarch_test::assert_instr; /// CRC32 single round checksum for bytes (8 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32b) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] @@ -33,6 +35,8 @@ pub unsafe fn __crc32b(crc: u32, data: u8) -> u32 { } /// CRC32 single round checksum for half words (16 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32h) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] @@ -42,6 +46,8 @@ pub unsafe fn __crc32h(crc: u32, data: u16) -> u32 { } /// CRC32 single round checksum for words (32 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32w) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] @@ -51,6 +57,8 @@ pub unsafe fn __crc32w(crc: u32, data: u32) -> u32 { } /// CRC32-C single round checksum for bytes (8 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32cb) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] @@ -60,6 +68,8 @@ pub unsafe fn __crc32cb(crc: u32, data: u8) -> u32 { } /// CRC32-C single round checksum for half words (16 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32ch) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] @@ -69,6 +79,8 @@ pub unsafe fn __crc32ch(crc: u32, data: u16) -> u32 { } /// CRC32-C single round checksum for words (32 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32cw) #[inline] #[target_feature(enable = "crc")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] diff --git a/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs b/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs index 3e9515e59..060091136 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/crypto.rs @@ -52,6 +52,8 @@ extern "unadjusted" { use stdarch_test::assert_instr; /// AES single round encryption. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaeseq_u8) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "aes"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -61,6 +63,8 @@ pub unsafe fn vaeseq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { } /// AES single round decryption. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaesdq_u8) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "aes"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -70,6 +74,8 @@ pub unsafe fn vaesdq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { } /// AES mix columns. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaesmcq_u8) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "aes"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -79,6 +85,8 @@ pub unsafe fn vaesmcq_u8(data: uint8x16_t) -> uint8x16_t { } /// AES inverse mix columns. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaesimcq_u8) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "aes"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -88,6 +96,8 @@ pub unsafe fn vaesimcq_u8(data: uint8x16_t) -> uint8x16_t { } /// SHA1 fixed rotate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1h_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -97,6 +107,8 @@ pub unsafe fn vsha1h_u32(hash_e: u32) -> u32 { } /// SHA1 hash update accelerator, choose. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1cq_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -106,6 +118,8 @@ pub unsafe fn vsha1cq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> } /// SHA1 hash update accelerator, majority. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1mq_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -115,6 +129,8 @@ pub unsafe fn vsha1mq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> } /// SHA1 hash update accelerator, parity. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1pq_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -124,6 +140,8 @@ pub unsafe fn vsha1pq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> } /// SHA1 schedule update accelerator, first part. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1su0q_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -133,6 +151,8 @@ pub unsafe fn vsha1su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t, w8_11: uint32x4_ } /// SHA1 schedule update accelerator, second part. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha1su1q_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -142,6 +162,8 @@ pub unsafe fn vsha1su1q_u32(tw0_3: uint32x4_t, w12_15: uint32x4_t) -> uint32x4_t } /// SHA256 hash update accelerator. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256hq_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -155,6 +177,8 @@ pub unsafe fn vsha256hq_u32( } /// SHA256 hash update accelerator, upper part. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256h2q_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -168,6 +192,8 @@ pub unsafe fn vsha256h2q_u32( } /// SHA256 schedule update accelerator, first part. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256su0q_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] @@ -177,6 +203,8 @@ pub unsafe fn vsha256su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t) -> uint32x4_t } /// SHA256 schedule update accelerator, second part. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256su1q_u32) #[inline] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "sha2"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "crypto,v8"))] diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index d69fbd8e8..ac2709744 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -10,6 +10,8 @@ use super::*; use stdarch_test::assert_instr; /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21,6 +23,8 @@ pub unsafe fn vand_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -32,6 +36,8 @@ pub unsafe fn vandq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -43,6 +49,8 @@ pub unsafe fn vand_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -54,6 +62,8 @@ pub unsafe fn vandq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -65,6 +75,8 @@ pub unsafe fn vand_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -76,6 +88,8 @@ pub unsafe fn vandq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -87,6 +101,8 @@ pub unsafe fn vand_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -98,6 +114,8 @@ pub unsafe fn vandq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -109,6 +127,8 @@ pub unsafe fn vand_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -120,6 +140,8 @@ pub unsafe fn vandq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -131,6 +153,8 @@ pub unsafe fn vand_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -142,6 +166,8 @@ pub unsafe fn vandq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -153,6 +179,8 @@ pub unsafe fn vand_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -164,6 +192,8 @@ pub unsafe fn vandq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -175,6 +205,8 @@ pub unsafe fn vand_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Vector bitwise and +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -186,6 +218,8 @@ pub unsafe fn vandq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -197,6 +231,8 @@ pub unsafe fn vorr_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -208,6 +244,8 @@ pub unsafe fn vorrq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -219,6 +257,8 @@ pub unsafe fn vorr_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -230,6 +270,8 @@ pub unsafe fn vorrq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -241,6 +283,8 @@ pub unsafe fn vorr_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -252,6 +296,8 @@ pub unsafe fn vorrq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -263,6 +309,8 @@ pub unsafe fn vorr_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -274,6 +322,8 @@ pub unsafe fn vorrq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -285,6 +335,8 @@ pub unsafe fn vorr_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -296,6 +348,8 @@ pub unsafe fn vorrq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -307,6 +361,8 @@ pub unsafe fn vorr_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -318,6 +374,8 @@ pub unsafe fn vorrq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -329,6 +387,8 @@ pub unsafe fn vorr_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -340,6 +400,8 @@ pub unsafe fn vorrq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -351,6 +413,8 @@ pub unsafe fn vorr_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Vector bitwise or (immediate, inclusive) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -362,6 +426,8 @@ pub unsafe fn vorrq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -373,6 +439,8 @@ pub unsafe fn veor_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -384,6 +452,8 @@ pub unsafe fn veorq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -395,6 +465,8 @@ pub unsafe fn veor_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -406,6 +478,8 @@ pub unsafe fn veorq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -417,6 +491,8 @@ pub unsafe fn veor_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -428,6 +504,8 @@ pub unsafe fn veorq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -439,6 +517,8 @@ pub unsafe fn veor_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -450,6 +530,8 @@ pub unsafe fn veorq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -461,6 +543,8 @@ pub unsafe fn veor_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -472,6 +556,8 @@ pub unsafe fn veorq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -483,6 +569,8 @@ pub unsafe fn veor_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -494,6 +582,8 @@ pub unsafe fn veorq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -505,6 +595,8 @@ pub unsafe fn veor_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -516,6 +608,8 @@ pub unsafe fn veorq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -527,6 +621,8 @@ pub unsafe fn veor_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Vector bitwise exclusive or (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -538,6 +634,8 @@ pub unsafe fn veorq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -555,6 +653,8 @@ vabd_s8_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -572,6 +672,8 @@ vabdq_s8_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -589,6 +691,8 @@ vabd_s16_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -606,6 +710,8 @@ vabdq_s16_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -623,6 +729,8 @@ vabd_s32_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -640,6 +748,8 @@ vabdq_s32_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -657,6 +767,8 @@ vabd_u8_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -674,6 +786,8 @@ vabdq_u8_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -691,6 +805,8 @@ vabd_u16_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -708,6 +824,8 @@ vabdq_u16_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -725,6 +843,8 @@ vabd_u32_(a, b) } /// Absolute difference between the arguments +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -742,6 +862,8 @@ vabdq_u32_(a, b) } /// Absolute difference between the arguments of Floating +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabd_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -759,6 +881,8 @@ vabd_f32_(a, b) } /// Absolute difference between the arguments of Floating +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -776,6 +900,8 @@ vabdq_f32_(a, b) } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -787,6 +913,8 @@ pub unsafe fn vabdl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -798,6 +926,8 @@ pub unsafe fn vabdl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { } /// Unsigned Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -809,6 +939,8 @@ pub unsafe fn vabdl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -821,6 +953,8 @@ pub unsafe fn vabdl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -833,6 +967,8 @@ pub unsafe fn vabdl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { } /// Signed Absolute difference Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabdl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -845,6 +981,8 @@ pub unsafe fn vabdl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -856,6 +994,8 @@ pub unsafe fn vceq_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -867,6 +1007,8 @@ pub unsafe fn vceqq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -878,6 +1020,8 @@ pub unsafe fn vceq_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -889,6 +1033,8 @@ pub unsafe fn vceqq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -900,6 +1046,8 @@ pub unsafe fn vceq_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -911,6 +1059,8 @@ pub unsafe fn vceqq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -922,6 +1072,8 @@ pub unsafe fn vceq_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -933,6 +1085,8 @@ pub unsafe fn vceqq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -944,6 +1098,8 @@ pub unsafe fn vceq_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -955,6 +1111,8 @@ pub unsafe fn vceqq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -966,6 +1124,8 @@ pub unsafe fn vceq_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -977,6 +1137,8 @@ pub unsafe fn vceqq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -988,6 +1150,8 @@ pub unsafe fn vceq_p8(a: poly8x8_t, b: poly8x8_t) -> uint8x8_t { } /// Compare bitwise Equal (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -999,6 +1163,8 @@ pub unsafe fn vceqq_p8(a: poly8x16_t, b: poly8x16_t) -> uint8x16_t { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1010,6 +1176,8 @@ pub unsafe fn vceq_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point compare equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vceqq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1021,6 +1189,8 @@ pub unsafe fn vceqq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1034,6 +1204,8 @@ pub unsafe fn vtst_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1047,6 +1219,8 @@ pub unsafe fn vtstq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1060,6 +1234,8 @@ pub unsafe fn vtst_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1073,6 +1249,8 @@ pub unsafe fn vtstq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1086,6 +1264,8 @@ pub unsafe fn vtst_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1099,6 +1279,8 @@ pub unsafe fn vtstq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1112,6 +1294,8 @@ pub unsafe fn vtst_p8(a: poly8x8_t, b: poly8x8_t) -> uint8x8_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1125,6 +1309,8 @@ pub unsafe fn vtstq_p8(a: poly8x16_t, b: poly8x16_t) -> uint8x16_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1138,6 +1324,8 @@ pub unsafe fn vtst_p16(a: poly16x4_t, b: poly16x4_t) -> uint16x4_t { } /// Signed compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1151,6 +1339,8 @@ pub unsafe fn vtstq_p16(a: poly16x8_t, b: poly16x8_t) -> uint16x8_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1164,6 +1354,8 @@ pub unsafe fn vtst_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1177,6 +1369,8 @@ pub unsafe fn vtstq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1190,6 +1384,8 @@ pub unsafe fn vtst_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1203,6 +1399,8 @@ pub unsafe fn vtstq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtst_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1216,6 +1414,8 @@ pub unsafe fn vtst_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Unsigned compare bitwise Test bits nonzero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtstq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1229,6 +1429,8 @@ pub unsafe fn vtstq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Floating-point absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabs_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1240,6 +1442,8 @@ pub unsafe fn vabs_f32(a: float32x2_t) -> float32x2_t { } /// Floating-point absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabsq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1251,6 +1455,8 @@ pub unsafe fn vabsq_f32(a: float32x4_t) -> float32x4_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1262,6 +1468,8 @@ pub unsafe fn vcgt_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1273,6 +1481,8 @@ pub unsafe fn vcgtq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1284,6 +1494,8 @@ pub unsafe fn vcgt_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1295,6 +1507,8 @@ pub unsafe fn vcgtq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1306,6 +1520,8 @@ pub unsafe fn vcgt_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Compare signed greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1317,6 +1533,8 @@ pub unsafe fn vcgtq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1328,6 +1546,8 @@ pub unsafe fn vcgt_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1339,6 +1559,8 @@ pub unsafe fn vcgtq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1350,6 +1572,8 @@ pub unsafe fn vcgt_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1361,6 +1585,8 @@ pub unsafe fn vcgtq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1372,6 +1598,8 @@ pub unsafe fn vcgt_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Compare unsigned highe +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1383,6 +1611,8 @@ pub unsafe fn vcgtq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgt_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1394,6 +1624,8 @@ pub unsafe fn vcgt_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgtq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1405,6 +1637,8 @@ pub unsafe fn vcgtq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1416,6 +1650,8 @@ pub unsafe fn vclt_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1427,6 +1663,8 @@ pub unsafe fn vcltq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1438,6 +1676,8 @@ pub unsafe fn vclt_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1449,6 +1689,8 @@ pub unsafe fn vcltq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1460,6 +1702,8 @@ pub unsafe fn vclt_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Compare signed less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1471,6 +1715,8 @@ pub unsafe fn vcltq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1482,6 +1728,8 @@ pub unsafe fn vclt_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1493,6 +1741,8 @@ pub unsafe fn vcltq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1504,6 +1754,8 @@ pub unsafe fn vclt_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1515,6 +1767,8 @@ pub unsafe fn vcltq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1526,6 +1780,8 @@ pub unsafe fn vclt_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Compare unsigned less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1537,6 +1793,8 @@ pub unsafe fn vcltq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclt_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1548,6 +1806,8 @@ pub unsafe fn vclt_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcltq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1559,6 +1819,8 @@ pub unsafe fn vcltq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1570,6 +1832,8 @@ pub unsafe fn vcle_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1581,6 +1845,8 @@ pub unsafe fn vcleq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1592,6 +1858,8 @@ pub unsafe fn vcle_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1603,6 +1871,8 @@ pub unsafe fn vcleq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1614,6 +1884,8 @@ pub unsafe fn vcle_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Compare signed less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1625,6 +1897,8 @@ pub unsafe fn vcleq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1636,6 +1910,8 @@ pub unsafe fn vcle_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1647,6 +1923,8 @@ pub unsafe fn vcleq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1658,6 +1936,8 @@ pub unsafe fn vcle_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1669,6 +1949,8 @@ pub unsafe fn vcleq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1680,6 +1962,8 @@ pub unsafe fn vcle_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Compare unsigned less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1691,6 +1975,8 @@ pub unsafe fn vcleq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcle_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1702,6 +1988,8 @@ pub unsafe fn vcle_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcleq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1713,6 +2001,8 @@ pub unsafe fn vcleq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1724,6 +2014,8 @@ pub unsafe fn vcge_s8(a: int8x8_t, b: int8x8_t) -> uint8x8_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1735,6 +2027,8 @@ pub unsafe fn vcgeq_s8(a: int8x16_t, b: int8x16_t) -> uint8x16_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1746,6 +2040,8 @@ pub unsafe fn vcge_s16(a: int16x4_t, b: int16x4_t) -> uint16x4_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1757,6 +2053,8 @@ pub unsafe fn vcgeq_s16(a: int16x8_t, b: int16x8_t) -> uint16x8_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1768,6 +2066,8 @@ pub unsafe fn vcge_s32(a: int32x2_t, b: int32x2_t) -> uint32x2_t { } /// Compare signed greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1779,6 +2079,8 @@ pub unsafe fn vcgeq_s32(a: int32x4_t, b: int32x4_t) -> uint32x4_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1790,6 +2092,8 @@ pub unsafe fn vcge_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1801,6 +2105,8 @@ pub unsafe fn vcgeq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1812,6 +2118,8 @@ pub unsafe fn vcge_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1823,6 +2131,8 @@ pub unsafe fn vcgeq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1834,6 +2144,8 @@ pub unsafe fn vcge_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Compare unsigned greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1845,6 +2157,8 @@ pub unsafe fn vcgeq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcge_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1856,6 +2170,8 @@ pub unsafe fn vcge_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcgeq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1867,6 +2183,8 @@ pub unsafe fn vcgeq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1884,6 +2202,8 @@ vcls_s8_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1901,6 +2221,8 @@ vclsq_s8_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1918,6 +2240,8 @@ vcls_s16_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1935,6 +2259,8 @@ vclsq_s16_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1952,6 +2278,8 @@ vcls_s32_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1969,6 +2297,8 @@ vclsq_s32_(a) } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1980,6 +2310,8 @@ pub unsafe fn vcls_u8(a: uint8x8_t) -> int8x8_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1991,6 +2323,8 @@ pub unsafe fn vclsq_u8(a: uint8x16_t) -> int8x16_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2002,6 +2336,8 @@ pub unsafe fn vcls_u16(a: uint16x4_t) -> int16x4_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2013,6 +2349,8 @@ pub unsafe fn vclsq_u16(a: uint16x8_t) -> int16x8_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2024,6 +2362,8 @@ pub unsafe fn vcls_u32(a: uint32x2_t) -> int32x2_t { } /// Count leading sign bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2035,6 +2375,8 @@ pub unsafe fn vclsq_u32(a: uint32x4_t) -> int32x4_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2046,6 +2388,8 @@ pub unsafe fn vclz_s8(a: int8x8_t) -> int8x8_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2057,6 +2401,8 @@ pub unsafe fn vclzq_s8(a: int8x16_t) -> int8x16_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2068,6 +2414,8 @@ pub unsafe fn vclz_s16(a: int16x4_t) -> int16x4_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2079,6 +2427,8 @@ pub unsafe fn vclzq_s16(a: int16x8_t) -> int16x8_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2090,6 +2440,8 @@ pub unsafe fn vclz_s32(a: int32x2_t) -> int32x2_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2101,6 +2453,8 @@ pub unsafe fn vclzq_s32(a: int32x4_t) -> int32x4_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2112,6 +2466,8 @@ pub unsafe fn vclz_u8(a: uint8x8_t) -> uint8x8_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2123,6 +2479,8 @@ pub unsafe fn vclzq_u8(a: uint8x16_t) -> uint8x16_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2134,6 +2492,8 @@ pub unsafe fn vclz_u16(a: uint16x4_t) -> uint16x4_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2145,6 +2505,8 @@ pub unsafe fn vclzq_u16(a: uint16x8_t) -> uint16x8_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2156,6 +2518,8 @@ pub unsafe fn vclz_u32(a: uint32x2_t) -> uint32x2_t { } /// Count leading zero bits +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2167,6 +2531,8 @@ pub unsafe fn vclzq_u32(a: uint32x4_t) -> uint32x4_t { } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagt_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2184,6 +2550,8 @@ vcagt_f32_(a, b) } /// Floating-point absolute compare greater than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcagtq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2201,6 +2569,8 @@ vcagtq_f32_(a, b) } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcage_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2218,6 +2588,8 @@ vcage_f32_(a, b) } /// Floating-point absolute compare greater than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcageq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2235,6 +2607,8 @@ vcageq_f32_(a, b) } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcalt_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2246,6 +2620,8 @@ pub unsafe fn vcalt_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point absolute compare less than +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaltq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2257,6 +2633,8 @@ pub unsafe fn vcaltq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcale_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2268,6 +2646,8 @@ pub unsafe fn vcale_f32(a: float32x2_t, b: float32x2_t) -> uint32x2_t { } /// Floating-point absolute compare less than or equal +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcaleq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2279,6 +2659,8 @@ pub unsafe fn vcaleq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2290,6 +2672,8 @@ pub unsafe fn vcreate_s8(a: u64) -> int8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2301,6 +2685,8 @@ pub unsafe fn vcreate_s16(a: u64) -> int16x4_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2312,6 +2698,8 @@ pub unsafe fn vcreate_s32(a: u64) -> int32x2_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2323,6 +2711,8 @@ pub unsafe fn vcreate_s64(a: u64) -> int64x1_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2334,6 +2724,8 @@ pub unsafe fn vcreate_u8(a: u64) -> uint8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2345,6 +2737,8 @@ pub unsafe fn vcreate_u16(a: u64) -> uint16x4_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2356,6 +2750,8 @@ pub unsafe fn vcreate_u32(a: u64) -> uint32x2_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2367,6 +2763,8 @@ pub unsafe fn vcreate_u64(a: u64) -> uint64x1_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2378,6 +2776,8 @@ pub unsafe fn vcreate_p8(a: u64) -> poly8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2389,6 +2789,8 @@ pub unsafe fn vcreate_p16(a: u64) -> poly16x4_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -2400,6 +2802,8 @@ pub unsafe fn vcreate_p64(a: u64) -> poly64x1_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcreate_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2411,6 +2815,8 @@ pub unsafe fn vcreate_f32(a: u64) -> float32x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2422,6 +2828,8 @@ pub unsafe fn vcvt_f32_s32(a: int32x2_t) -> float32x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2433,6 +2841,8 @@ pub unsafe fn vcvtq_f32_s32(a: int32x4_t) -> float32x4_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2444,6 +2854,8 @@ pub unsafe fn vcvt_f32_u32(a: uint32x2_t) -> float32x2_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2455,6 +2867,8 @@ pub unsafe fn vcvtq_f32_u32(a: uint32x4_t) -> float32x4_t { } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f32_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2471,6 +2885,8 @@ vcvt_n_f32_s32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f32_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2488,6 +2904,8 @@ vcvt_n_f32_s32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f32_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2504,6 +2922,8 @@ vcvtq_n_f32_s32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f32_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2521,6 +2941,8 @@ vcvtq_n_f32_s32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f32_u32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2537,6 +2959,8 @@ vcvt_n_f32_u32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_f32_u32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2554,6 +2978,8 @@ vcvt_n_f32_u32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f32_u32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2570,6 +2996,8 @@ vcvtq_n_f32_u32_(a, N) } /// Fixed-point convert to floating-point +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_f32_u32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2587,6 +3015,8 @@ vcvtq_n_f32_u32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_s32_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2603,6 +3033,8 @@ vcvt_n_s32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_s32_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2620,6 +3052,8 @@ vcvt_n_s32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_s32_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2636,6 +3070,8 @@ vcvtq_n_s32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_s32_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2653,6 +3089,8 @@ vcvtq_n_s32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_u32_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2669,6 +3107,8 @@ vcvt_n_u32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_n_u32_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2686,6 +3126,8 @@ vcvt_n_u32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_u32_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -2702,6 +3144,8 @@ vcvtq_n_u32_f32_(a, N) } /// Floating-point convert to fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_n_u32_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -2719,6 +3163,8 @@ vcvtq_n_u32_f32_(a, N) } /// Floating-point convert to signed fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2736,6 +3182,8 @@ vcvt_s32_f32_(a) } /// Floating-point convert to signed fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2753,6 +3201,8 @@ vcvtq_s32_f32_(a) } /// Floating-point convert to unsigned fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvt_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2770,6 +3220,8 @@ vcvt_u32_f32_(a) } /// Floating-point convert to unsigned fixed-point, rounding toward zero +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcvtq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2787,6 +3239,8 @@ vcvtq_u32_f32_(a) } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2800,6 +3254,8 @@ pub unsafe fn vdup_lane_s8(a: int8x8_t) -> int8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2813,6 +3269,8 @@ pub unsafe fn vdupq_laneq_s8(a: int8x16_t) -> int8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2826,6 +3284,8 @@ pub unsafe fn vdup_lane_s16(a: int16x4_t) -> int16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2839,6 +3299,8 @@ pub unsafe fn vdupq_laneq_s16(a: int16x8_t) -> int16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2852,6 +3314,8 @@ pub unsafe fn vdup_lane_s32(a: int32x2_t) -> int32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2865,6 +3329,8 @@ pub unsafe fn vdupq_laneq_s32(a: int32x4_t) -> int32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2878,6 +3344,8 @@ pub unsafe fn vdup_laneq_s8(a: int8x16_t) -> int8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2891,6 +3359,8 @@ pub unsafe fn vdup_laneq_s16(a: int16x8_t) -> int16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2904,6 +3374,8 @@ pub unsafe fn vdup_laneq_s32(a: int32x4_t) -> int32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2917,6 +3389,8 @@ pub unsafe fn vdupq_lane_s8(a: int8x8_t) -> int8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2930,6 +3404,8 @@ pub unsafe fn vdupq_lane_s16(a: int16x4_t) -> int16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2943,6 +3419,8 @@ pub unsafe fn vdupq_lane_s32(a: int32x2_t) -> int32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2956,6 +3434,8 @@ pub unsafe fn vdup_lane_u8(a: uint8x8_t) -> uint8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2969,6 +3449,8 @@ pub unsafe fn vdupq_laneq_u8(a: uint8x16_t) -> uint8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2982,6 +3464,8 @@ pub unsafe fn vdup_lane_u16(a: uint16x4_t) -> uint16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -2995,6 +3479,8 @@ pub unsafe fn vdupq_laneq_u16(a: uint16x8_t) -> uint16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3008,6 +3494,8 @@ pub unsafe fn vdup_lane_u32(a: uint32x2_t) -> uint32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3021,6 +3509,8 @@ pub unsafe fn vdupq_laneq_u32(a: uint32x4_t) -> uint32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3034,6 +3524,8 @@ pub unsafe fn vdup_laneq_u8(a: uint8x16_t) -> uint8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3047,6 +3539,8 @@ pub unsafe fn vdup_laneq_u16(a: uint16x8_t) -> uint16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3060,6 +3554,8 @@ pub unsafe fn vdup_laneq_u32(a: uint32x4_t) -> uint32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3073,6 +3569,8 @@ pub unsafe fn vdupq_lane_u8(a: uint8x8_t) -> uint8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3086,6 +3584,8 @@ pub unsafe fn vdupq_lane_u16(a: uint16x4_t) -> uint16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3099,6 +3599,8 @@ pub unsafe fn vdupq_lane_u32(a: uint32x2_t) -> uint32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3112,6 +3614,8 @@ pub unsafe fn vdup_lane_p8(a: poly8x8_t) -> poly8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3125,6 +3629,8 @@ pub unsafe fn vdupq_laneq_p8(a: poly8x16_t) -> poly8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3138,6 +3644,8 @@ pub unsafe fn vdup_lane_p16(a: poly16x4_t) -> poly16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3151,6 +3659,8 @@ pub unsafe fn vdupq_laneq_p16(a: poly16x8_t) -> poly16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3164,6 +3674,8 @@ pub unsafe fn vdup_laneq_p8(a: poly8x16_t) -> poly8x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3177,6 +3689,8 @@ pub unsafe fn vdup_laneq_p16(a: poly16x8_t) -> poly16x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3190,6 +3704,8 @@ pub unsafe fn vdupq_lane_p8(a: poly8x8_t) -> poly8x16_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3203,6 +3719,8 @@ pub unsafe fn vdupq_lane_p16(a: poly16x4_t) -> poly16x8_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3216,6 +3734,8 @@ pub unsafe fn vdupq_laneq_s64(a: int64x2_t) -> int64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3229,6 +3749,8 @@ pub unsafe fn vdupq_lane_s64(a: int64x1_t) -> int64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3242,6 +3764,8 @@ pub unsafe fn vdupq_laneq_u64(a: uint64x2_t) -> uint64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3255,6 +3779,8 @@ pub unsafe fn vdupq_lane_u64(a: uint64x1_t) -> uint64x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3268,6 +3794,8 @@ pub unsafe fn vdup_lane_f32(a: float32x2_t) -> float32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3281,6 +3809,8 @@ pub unsafe fn vdupq_laneq_f32(a: float32x4_t) -> float32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3294,6 +3824,8 @@ pub unsafe fn vdup_laneq_f32(a: float32x4_t) -> float32x2_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdupq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3307,6 +3839,8 @@ pub unsafe fn vdupq_lane_f32(a: float32x2_t) -> float32x4_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3320,6 +3854,8 @@ pub unsafe fn vdup_lane_s64(a: int64x1_t) -> int64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3333,6 +3869,8 @@ pub unsafe fn vdup_lane_u64(a: uint64x1_t) -> uint64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3346,6 +3884,8 @@ pub unsafe fn vdup_laneq_s64(a: int64x2_t) -> int64x1_t { } /// Set all vector lanes to the same value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_laneq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3359,11 +3899,13 @@ pub unsafe fn vdup_laneq_u64(a: uint64x2_t) -> uint64x1_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { @@ -3382,11 +3924,13 @@ pub unsafe fn vext_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 8))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 8))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 15))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { @@ -3413,11 +3957,13 @@ pub unsafe fn vextq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { @@ -3432,11 +3978,13 @@ pub unsafe fn vext_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { @@ -3455,6 +4003,8 @@ pub unsafe fn vextq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3472,11 +4022,13 @@ pub unsafe fn vext_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { @@ -3491,11 +4043,13 @@ pub unsafe fn vextq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { @@ -3514,11 +4068,13 @@ pub unsafe fn vext_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 8))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 8))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 15))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { @@ -3545,11 +4101,13 @@ pub unsafe fn vextq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { @@ -3564,11 +4122,13 @@ pub unsafe fn vext_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { @@ -3587,6 +4147,8 @@ pub unsafe fn vextq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_ } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3604,11 +4166,13 @@ pub unsafe fn vext_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { @@ -3623,11 +4187,13 @@ pub unsafe fn vextq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_ } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { @@ -3646,11 +4212,13 @@ pub unsafe fn vext_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 8))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 8))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 15))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { @@ -3677,11 +4245,13 @@ pub unsafe fn vextq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vext_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { @@ -3696,11 +4266,13 @@ pub unsafe fn vext_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 4))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 4))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 7))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { @@ -3719,6 +4291,8 @@ pub unsafe fn vextq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_ } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3736,6 +4310,8 @@ pub unsafe fn vextq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3753,6 +4329,8 @@ pub unsafe fn vextq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_ } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vext_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3770,11 +4348,13 @@ pub unsafe fn vext_f32(a: float32x2_t, b: float32x2_t) -> float32x } /// Extract vector from pair of vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vextq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 2))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", N = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, N = 3))] #[rustc_legacy_const_generics(2)] #[cfg_attr(target_arch = "aarch64", stable(feature = "neon_intrinsics", since = "1.59.0"))] pub unsafe fn vextq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { @@ -3789,6 +4369,8 @@ pub unsafe fn vextq_f32(a: float32x4_t, b: float32x4_t) -> float32 } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3800,6 +4382,8 @@ pub unsafe fn vmla_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3811,6 +4395,8 @@ pub unsafe fn vmlaq_s8(a: int8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3822,6 +4408,8 @@ pub unsafe fn vmla_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3833,6 +4421,8 @@ pub unsafe fn vmlaq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3844,6 +4434,8 @@ pub unsafe fn vmla_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3855,6 +4447,8 @@ pub unsafe fn vmlaq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3866,6 +4460,8 @@ pub unsafe fn vmla_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3877,6 +4473,8 @@ pub unsafe fn vmlaq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_ } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3888,6 +4486,8 @@ pub unsafe fn vmla_u16(a: uint16x4_t, b: uint16x4_t, c: uint16x4_t) -> uint16x4_ } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3899,6 +4499,8 @@ pub unsafe fn vmlaq_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x8 } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3910,6 +4512,8 @@ pub unsafe fn vmla_u32(a: uint32x2_t, b: uint32x2_t, c: uint32x2_t) -> uint32x2_ } /// Multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3921,6 +4525,8 @@ pub unsafe fn vmlaq_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x4 } /// Floating-point multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3932,6 +4538,8 @@ pub unsafe fn vmla_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float3 } /// Floating-point multiply-add to accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3943,6 +4551,8 @@ pub unsafe fn vmlaq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3954,6 +4564,8 @@ pub unsafe fn vmla_n_s16(a: int16x4_t, b: int16x4_t, c: i16) -> int16x4_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3965,6 +4577,8 @@ pub unsafe fn vmlaq_n_s16(a: int16x8_t, b: int16x8_t, c: i16) -> int16x8_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3976,6 +4590,8 @@ pub unsafe fn vmla_n_s32(a: int32x2_t, b: int32x2_t, c: i32) -> int32x2_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3987,6 +4603,8 @@ pub unsafe fn vmlaq_n_s32(a: int32x4_t, b: int32x4_t, c: i32) -> int32x4_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3998,6 +4616,8 @@ pub unsafe fn vmla_n_u16(a: uint16x4_t, b: uint16x4_t, c: u16) -> uint16x4_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4009,6 +4629,8 @@ pub unsafe fn vmlaq_n_u16(a: uint16x8_t, b: uint16x8_t, c: u16) -> uint16x8_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4020,6 +4642,8 @@ pub unsafe fn vmla_n_u32(a: uint32x2_t, b: uint32x2_t, c: u32) -> uint32x2_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4031,6 +4655,8 @@ pub unsafe fn vmlaq_n_u32(a: uint32x4_t, b: uint32x4_t, c: u32) -> uint32x4_t { } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4042,6 +4668,8 @@ pub unsafe fn vmla_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4053,6 +4681,8 @@ pub unsafe fn vmlaq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4066,6 +4696,8 @@ pub unsafe fn vmla_lane_s16(a: int16x4_t, b: int16x4_t, c: int1 } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4079,6 +4711,8 @@ pub unsafe fn vmla_laneq_s16(a: int16x4_t, b: int16x4_t, c: int } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4092,6 +4726,8 @@ pub unsafe fn vmlaq_lane_s16(a: int16x8_t, b: int16x8_t, c: int } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4105,6 +4741,8 @@ pub unsafe fn vmlaq_laneq_s16(a: int16x8_t, b: int16x8_t, c: in } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4118,6 +4756,8 @@ pub unsafe fn vmla_lane_s32(a: int32x2_t, b: int32x2_t, c: int3 } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4131,6 +4771,8 @@ pub unsafe fn vmla_laneq_s32(a: int32x2_t, b: int32x2_t, c: int } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4144,6 +4786,8 @@ pub unsafe fn vmlaq_lane_s32(a: int32x4_t, b: int32x4_t, c: int } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4157,6 +4801,8 @@ pub unsafe fn vmlaq_laneq_s32(a: int32x4_t, b: int32x4_t, c: in } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4170,6 +4816,8 @@ pub unsafe fn vmla_lane_u16(a: uint16x4_t, b: uint16x4_t, c: ui } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4183,6 +4831,8 @@ pub unsafe fn vmla_laneq_u16(a: uint16x4_t, b: uint16x4_t, c: u } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4196,6 +4846,8 @@ pub unsafe fn vmlaq_lane_u16(a: uint16x8_t, b: uint16x8_t, c: u } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4209,6 +4861,8 @@ pub unsafe fn vmlaq_laneq_u16(a: uint16x8_t, b: uint16x8_t, c: } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4222,6 +4876,8 @@ pub unsafe fn vmla_lane_u32(a: uint32x2_t, b: uint32x2_t, c: ui } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4235,6 +4891,8 @@ pub unsafe fn vmla_laneq_u32(a: uint32x2_t, b: uint32x2_t, c: u } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4248,6 +4906,8 @@ pub unsafe fn vmlaq_lane_u32(a: uint32x4_t, b: uint32x4_t, c: u } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4261,6 +4921,8 @@ pub unsafe fn vmlaq_laneq_u32(a: uint32x4_t, b: uint32x4_t, c: } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4274,6 +4936,8 @@ pub unsafe fn vmla_lane_f32(a: float32x2_t, b: float32x2_t, c: } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmla_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4287,6 +4951,8 @@ pub unsafe fn vmla_laneq_f32(a: float32x2_t, b: float32x2_t, c: } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4300,6 +4966,8 @@ pub unsafe fn vmlaq_lane_f32(a: float32x4_t, b: float32x4_t, c: } /// Vector multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlaq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4313,6 +4981,8 @@ pub unsafe fn vmlaq_laneq_f32(a: float32x4_t, b: float32x4_t, c } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4324,6 +4994,8 @@ pub unsafe fn vmlal_s8(a: int16x8_t, b: int8x8_t, c: int8x8_t) -> int16x8_t { } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4335,6 +5007,8 @@ pub unsafe fn vmlal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { } /// Signed multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4346,6 +5020,8 @@ pub unsafe fn vmlal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4357,6 +5033,8 @@ pub unsafe fn vmlal_u8(a: uint16x8_t, b: uint8x8_t, c: uint8x8_t) -> uint16x8_t } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4368,6 +5046,8 @@ pub unsafe fn vmlal_u16(a: uint32x4_t, b: uint16x4_t, c: uint16x4_t) -> uint32x4 } /// Unsigned multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4379,6 +5059,8 @@ pub unsafe fn vmlal_u32(a: uint64x2_t, b: uint32x2_t, c: uint32x2_t) -> uint64x2 } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4390,6 +5072,8 @@ pub unsafe fn vmlal_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4401,6 +5085,8 @@ pub unsafe fn vmlal_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4412,6 +5098,8 @@ pub unsafe fn vmlal_n_u16(a: uint32x4_t, b: uint16x4_t, c: u16) -> uint32x4_t { } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4423,6 +5111,8 @@ pub unsafe fn vmlal_n_u32(a: uint64x2_t, b: uint32x2_t, c: u32) -> uint64x2_t { } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4436,6 +5126,8 @@ pub unsafe fn vmlal_lane_s16(a: int32x4_t, b: int16x4_t, c: int } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4449,6 +5141,8 @@ pub unsafe fn vmlal_laneq_s16(a: int32x4_t, b: int16x4_t, c: in } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4462,6 +5156,8 @@ pub unsafe fn vmlal_lane_s32(a: int64x2_t, b: int32x2_t, c: int } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4475,6 +5171,8 @@ pub unsafe fn vmlal_laneq_s32(a: int64x2_t, b: int32x2_t, c: in } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4488,6 +5186,8 @@ pub unsafe fn vmlal_lane_u16(a: uint32x4_t, b: uint16x4_t, c: u } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4501,6 +5201,8 @@ pub unsafe fn vmlal_laneq_u16(a: uint32x4_t, b: uint16x4_t, c: } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4514,6 +5216,8 @@ pub unsafe fn vmlal_lane_u32(a: uint64x2_t, b: uint32x2_t, c: u } /// Vector widening multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlal_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4527,6 +5231,8 @@ pub unsafe fn vmlal_laneq_u32(a: uint64x2_t, b: uint32x2_t, c: } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4538,6 +5244,8 @@ pub unsafe fn vmls_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4549,6 +5257,8 @@ pub unsafe fn vmlsq_s8(a: int8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4560,6 +5270,8 @@ pub unsafe fn vmls_s16(a: int16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4571,6 +5283,8 @@ pub unsafe fn vmlsq_s16(a: int16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4582,6 +5296,8 @@ pub unsafe fn vmls_s32(a: int32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4593,6 +5309,8 @@ pub unsafe fn vmlsq_s32(a: int32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4604,6 +5322,8 @@ pub unsafe fn vmls_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4615,6 +5335,8 @@ pub unsafe fn vmlsq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_ } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4626,6 +5348,8 @@ pub unsafe fn vmls_u16(a: uint16x4_t, b: uint16x4_t, c: uint16x4_t) -> uint16x4_ } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4637,6 +5361,8 @@ pub unsafe fn vmlsq_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x8 } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4648,6 +5374,8 @@ pub unsafe fn vmls_u32(a: uint32x2_t, b: uint32x2_t, c: uint32x2_t) -> uint32x2_ } /// Multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4659,6 +5387,8 @@ pub unsafe fn vmlsq_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x4 } /// Floating-point multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4670,6 +5400,8 @@ pub unsafe fn vmls_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float3 } /// Floating-point multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4681,6 +5413,8 @@ pub unsafe fn vmlsq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4692,6 +5426,8 @@ pub unsafe fn vmls_n_s16(a: int16x4_t, b: int16x4_t, c: i16) -> int16x4_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4703,6 +5439,8 @@ pub unsafe fn vmlsq_n_s16(a: int16x8_t, b: int16x8_t, c: i16) -> int16x8_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4714,6 +5452,8 @@ pub unsafe fn vmls_n_s32(a: int32x2_t, b: int32x2_t, c: i32) -> int32x2_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4725,6 +5465,8 @@ pub unsafe fn vmlsq_n_s32(a: int32x4_t, b: int32x4_t, c: i32) -> int32x4_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4736,6 +5478,8 @@ pub unsafe fn vmls_n_u16(a: uint16x4_t, b: uint16x4_t, c: u16) -> uint16x4_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4747,6 +5491,8 @@ pub unsafe fn vmlsq_n_u16(a: uint16x8_t, b: uint16x8_t, c: u16) -> uint16x8_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4758,6 +5504,8 @@ pub unsafe fn vmls_n_u32(a: uint32x2_t, b: uint32x2_t, c: u32) -> uint32x2_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4769,6 +5517,8 @@ pub unsafe fn vmlsq_n_u32(a: uint32x4_t, b: uint32x4_t, c: u32) -> uint32x4_t { } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4780,6 +5530,8 @@ pub unsafe fn vmls_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4791,6 +5543,8 @@ pub unsafe fn vmlsq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4804,6 +5558,8 @@ pub unsafe fn vmls_lane_s16(a: int16x4_t, b: int16x4_t, c: int1 } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4817,6 +5573,8 @@ pub unsafe fn vmls_laneq_s16(a: int16x4_t, b: int16x4_t, c: int } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4830,6 +5588,8 @@ pub unsafe fn vmlsq_lane_s16(a: int16x8_t, b: int16x8_t, c: int } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4843,6 +5603,8 @@ pub unsafe fn vmlsq_laneq_s16(a: int16x8_t, b: int16x8_t, c: in } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4856,6 +5618,8 @@ pub unsafe fn vmls_lane_s32(a: int32x2_t, b: int32x2_t, c: int3 } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4869,6 +5633,8 @@ pub unsafe fn vmls_laneq_s32(a: int32x2_t, b: int32x2_t, c: int } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4882,6 +5648,8 @@ pub unsafe fn vmlsq_lane_s32(a: int32x4_t, b: int32x4_t, c: int } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4895,6 +5663,8 @@ pub unsafe fn vmlsq_laneq_s32(a: int32x4_t, b: int32x4_t, c: in } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4908,6 +5678,8 @@ pub unsafe fn vmls_lane_u16(a: uint16x4_t, b: uint16x4_t, c: ui } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4921,6 +5693,8 @@ pub unsafe fn vmls_laneq_u16(a: uint16x4_t, b: uint16x4_t, c: u } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4934,6 +5708,8 @@ pub unsafe fn vmlsq_lane_u16(a: uint16x8_t, b: uint16x8_t, c: u } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4947,6 +5723,8 @@ pub unsafe fn vmlsq_laneq_u16(a: uint16x8_t, b: uint16x8_t, c: } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4960,6 +5738,8 @@ pub unsafe fn vmls_lane_u32(a: uint32x2_t, b: uint32x2_t, c: ui } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4973,6 +5753,8 @@ pub unsafe fn vmls_laneq_u32(a: uint32x2_t, b: uint32x2_t, c: u } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4986,6 +5768,8 @@ pub unsafe fn vmlsq_lane_u32(a: uint32x4_t, b: uint32x4_t, c: u } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -4999,6 +5783,8 @@ pub unsafe fn vmlsq_laneq_u32(a: uint32x4_t, b: uint32x4_t, c: } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5012,6 +5798,8 @@ pub unsafe fn vmls_lane_f32(a: float32x2_t, b: float32x2_t, c: } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmls_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5025,6 +5813,8 @@ pub unsafe fn vmls_laneq_f32(a: float32x2_t, b: float32x2_t, c: } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5038,6 +5828,8 @@ pub unsafe fn vmlsq_lane_f32(a: float32x4_t, b: float32x4_t, c: } /// Vector multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5051,6 +5843,8 @@ pub unsafe fn vmlsq_laneq_f32(a: float32x4_t, b: float32x4_t, c } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5062,6 +5856,8 @@ pub unsafe fn vmlsl_s8(a: int16x8_t, b: int8x8_t, c: int8x8_t) -> int16x8_t { } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5073,6 +5869,8 @@ pub unsafe fn vmlsl_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { } /// Signed multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5084,6 +5882,8 @@ pub unsafe fn vmlsl_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5095,6 +5895,8 @@ pub unsafe fn vmlsl_u8(a: uint16x8_t, b: uint8x8_t, c: uint8x8_t) -> uint16x8_t } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5106,6 +5908,8 @@ pub unsafe fn vmlsl_u16(a: uint32x4_t, b: uint16x4_t, c: uint16x4_t) -> uint32x4 } /// Unsigned multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5117,6 +5921,8 @@ pub unsafe fn vmlsl_u32(a: uint64x2_t, b: uint32x2_t, c: uint32x2_t) -> uint64x2 } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5128,6 +5934,8 @@ pub unsafe fn vmlsl_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5139,6 +5947,8 @@ pub unsafe fn vmlsl_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5150,6 +5960,8 @@ pub unsafe fn vmlsl_n_u16(a: uint32x4_t, b: uint16x4_t, c: u16) -> uint32x4_t { } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5161,6 +5973,8 @@ pub unsafe fn vmlsl_n_u32(a: uint64x2_t, b: uint32x2_t, c: u32) -> uint64x2_t { } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5174,6 +5988,8 @@ pub unsafe fn vmlsl_lane_s16(a: int32x4_t, b: int16x4_t, c: int } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5187,6 +6003,8 @@ pub unsafe fn vmlsl_laneq_s16(a: int32x4_t, b: int16x4_t, c: in } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5200,6 +6018,8 @@ pub unsafe fn vmlsl_lane_s32(a: int64x2_t, b: int32x2_t, c: int } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5213,6 +6033,8 @@ pub unsafe fn vmlsl_laneq_s32(a: int64x2_t, b: int32x2_t, c: in } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5226,6 +6048,8 @@ pub unsafe fn vmlsl_lane_u16(a: uint32x4_t, b: uint16x4_t, c: u } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5239,6 +6063,8 @@ pub unsafe fn vmlsl_laneq_u16(a: uint32x4_t, b: uint16x4_t, c: } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5252,6 +6078,8 @@ pub unsafe fn vmlsl_lane_u32(a: uint64x2_t, b: uint32x2_t, c: u } /// Vector widening multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmlsl_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5265,6 +6093,8 @@ pub unsafe fn vmlsl_laneq_u32(a: uint64x2_t, b: uint32x2_t, c: } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5276,6 +6106,8 @@ pub unsafe fn vneg_s8(a: int8x8_t) -> int8x8_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5287,6 +6119,8 @@ pub unsafe fn vnegq_s8(a: int8x16_t) -> int8x16_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5298,6 +6132,8 @@ pub unsafe fn vneg_s16(a: int16x4_t) -> int16x4_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5309,6 +6145,8 @@ pub unsafe fn vnegq_s16(a: int16x8_t) -> int16x8_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5320,6 +6158,8 @@ pub unsafe fn vneg_s32(a: int32x2_t) -> int32x2_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5331,6 +6171,8 @@ pub unsafe fn vnegq_s32(a: int32x4_t) -> int32x4_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5342,6 +6184,8 @@ pub unsafe fn vneg_f32(a: float32x2_t) -> float32x2_t { } /// Negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5353,6 +6197,8 @@ pub unsafe fn vnegq_f32(a: float32x4_t) -> float32x4_t { } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5370,6 +6216,8 @@ vqneg_s8_(a) } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5387,6 +6235,8 @@ vqnegq_s8_(a) } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5404,6 +6254,8 @@ vqneg_s16_(a) } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5421,6 +6273,8 @@ vqnegq_s16_(a) } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5438,6 +6292,8 @@ vqneg_s32_(a) } /// Signed saturating negate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5455,6 +6311,8 @@ vqnegq_s32_(a) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5472,6 +6330,8 @@ vqsub_u8_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5489,6 +6349,8 @@ vqsubq_u8_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5506,6 +6368,8 @@ vqsub_u16_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5523,6 +6387,8 @@ vqsubq_u16_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5540,6 +6406,8 @@ vqsub_u32_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5557,6 +6425,8 @@ vqsubq_u32_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5574,6 +6444,8 @@ vqsub_u64_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5591,6 +6463,8 @@ vqsubq_u64_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5608,6 +6482,8 @@ vqsub_s8_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5625,6 +6501,8 @@ vqsubq_s8_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5642,6 +6520,8 @@ vqsub_s16_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5659,6 +6539,8 @@ vqsubq_s16_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5676,6 +6558,8 @@ vqsub_s32_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5693,6 +6577,8 @@ vqsubq_s32_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5710,6 +6596,8 @@ vqsub_s64_(a, b) } /// Saturating subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5727,6 +6615,8 @@ vqsubq_s64_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5744,6 +6634,8 @@ vhadd_u8_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5761,6 +6653,8 @@ vhaddq_u8_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5778,6 +6672,8 @@ vhadd_u16_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5795,6 +6691,8 @@ vhaddq_u16_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5812,6 +6710,8 @@ vhadd_u32_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5829,6 +6729,8 @@ vhaddq_u32_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5846,6 +6748,8 @@ vhadd_s8_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5863,6 +6767,8 @@ vhaddq_s8_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5880,6 +6786,8 @@ vhadd_s16_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5897,6 +6805,8 @@ vhaddq_s16_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhadd_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5914,6 +6824,8 @@ vhadd_s32_(a, b) } /// Halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhaddq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5931,6 +6843,8 @@ vhaddq_s32_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5948,6 +6862,8 @@ vrhadd_u8_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5965,6 +6881,8 @@ vrhaddq_u8_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5982,6 +6900,8 @@ vrhadd_u16_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -5999,6 +6919,8 @@ vrhaddq_u16_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6016,6 +6938,8 @@ vrhadd_u32_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6033,6 +6957,8 @@ vrhaddq_u32_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6050,6 +6976,8 @@ vrhadd_s8_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6067,6 +6995,8 @@ vrhaddq_s8_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6084,6 +7014,8 @@ vrhadd_s16_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6101,6 +7033,8 @@ vrhaddq_s16_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhadd_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6118,6 +7052,8 @@ vrhadd_s32_(a, b) } /// Rounding halving add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrhaddq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6135,6 +7071,8 @@ vrhaddq_s32_(a, b) } /// Floating-point round to integral, to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndn_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -6152,6 +7090,8 @@ vrndn_f32_(a) } /// Floating-point round to integral, to nearest with ties to even +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndnq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -6169,6 +7109,8 @@ vrndnq_f32_(a) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6186,6 +7128,8 @@ vqadd_u8_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6203,6 +7147,8 @@ vqaddq_u8_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6220,6 +7166,8 @@ vqadd_u16_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6237,6 +7185,8 @@ vqaddq_u16_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6254,6 +7204,8 @@ vqadd_u32_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6271,6 +7223,8 @@ vqaddq_u32_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6288,6 +7242,8 @@ vqadd_u64_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6305,6 +7261,8 @@ vqaddq_u64_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6322,6 +7280,8 @@ vqadd_s8_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6339,6 +7299,8 @@ vqaddq_s8_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6356,6 +7318,8 @@ vqadd_s16_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6373,6 +7337,8 @@ vqaddq_s16_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6390,6 +7356,8 @@ vqadd_s32_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6407,6 +7375,8 @@ vqaddq_s32_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6424,6 +7394,8 @@ vqadd_s64_(a, b) } /// Saturating add +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6441,6 +7413,8 @@ vqaddq_s64_(a, b) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6458,6 +7432,8 @@ vld1_s8_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6475,6 +7451,8 @@ vld1_s16_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6492,6 +7470,8 @@ vld1_s32_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6509,6 +7489,8 @@ vld1_s64_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6526,6 +7508,8 @@ vld1q_s8_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6543,6 +7527,8 @@ vld1q_s16_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6560,6 +7546,8 @@ vld1q_s32_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6577,6 +7565,8 @@ vld1q_s64_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6594,6 +7584,8 @@ vld1_s8_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6611,6 +7603,8 @@ vld1_s16_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6628,6 +7622,8 @@ vld1_s32_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6645,6 +7641,8 @@ vld1_s64_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6662,6 +7660,8 @@ vld1q_s8_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6679,6 +7679,8 @@ vld1q_s16_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6696,6 +7698,8 @@ vld1q_s32_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6713,6 +7717,8 @@ vld1q_s64_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6730,6 +7736,8 @@ vld1_s8_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6747,6 +7755,8 @@ vld1_s16_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6764,6 +7774,8 @@ vld1_s32_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_s64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6781,6 +7793,8 @@ vld1_s64_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6798,6 +7812,8 @@ vld1q_s8_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6815,6 +7831,8 @@ vld1q_s16_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6832,6 +7850,8 @@ vld1q_s32_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_s64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6849,6 +7869,8 @@ vld1q_s64_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6860,6 +7882,8 @@ pub unsafe fn vld1_u8_x2(a: *const u8) -> uint8x8x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6871,6 +7895,8 @@ pub unsafe fn vld1_u16_x2(a: *const u16) -> uint16x4x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6882,6 +7908,8 @@ pub unsafe fn vld1_u32_x2(a: *const u32) -> uint32x2x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6893,6 +7921,8 @@ pub unsafe fn vld1_u64_x2(a: *const u64) -> uint64x1x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6904,6 +7934,8 @@ pub unsafe fn vld1q_u8_x2(a: *const u8) -> uint8x16x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6915,6 +7947,8 @@ pub unsafe fn vld1q_u16_x2(a: *const u16) -> uint16x8x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6926,6 +7960,8 @@ pub unsafe fn vld1q_u32_x2(a: *const u32) -> uint32x4x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6937,6 +7973,8 @@ pub unsafe fn vld1q_u64_x2(a: *const u64) -> uint64x2x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6948,6 +7986,8 @@ pub unsafe fn vld1_u8_x3(a: *const u8) -> uint8x8x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6959,6 +7999,8 @@ pub unsafe fn vld1_u16_x3(a: *const u16) -> uint16x4x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6970,6 +8012,8 @@ pub unsafe fn vld1_u32_x3(a: *const u32) -> uint32x2x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6981,6 +8025,8 @@ pub unsafe fn vld1_u64_x3(a: *const u64) -> uint64x1x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -6992,6 +8038,8 @@ pub unsafe fn vld1q_u8_x3(a: *const u8) -> uint8x16x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7003,6 +8051,8 @@ pub unsafe fn vld1q_u16_x3(a: *const u16) -> uint16x8x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7014,6 +8064,8 @@ pub unsafe fn vld1q_u32_x3(a: *const u32) -> uint32x4x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7025,6 +8077,8 @@ pub unsafe fn vld1q_u64_x3(a: *const u64) -> uint64x2x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7036,6 +8090,8 @@ pub unsafe fn vld1_u8_x4(a: *const u8) -> uint8x8x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7047,6 +8103,8 @@ pub unsafe fn vld1_u16_x4(a: *const u16) -> uint16x4x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7058,6 +8116,8 @@ pub unsafe fn vld1_u32_x4(a: *const u32) -> uint32x2x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_u64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7069,6 +8129,8 @@ pub unsafe fn vld1_u64_x4(a: *const u64) -> uint64x1x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7080,6 +8142,8 @@ pub unsafe fn vld1q_u8_x4(a: *const u8) -> uint8x16x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7091,6 +8155,8 @@ pub unsafe fn vld1q_u16_x4(a: *const u16) -> uint16x8x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7102,6 +8168,8 @@ pub unsafe fn vld1q_u32_x4(a: *const u32) -> uint32x4x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_u64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7113,6 +8181,8 @@ pub unsafe fn vld1q_u64_x4(a: *const u64) -> uint64x2x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7124,6 +8194,8 @@ pub unsafe fn vld1_p8_x2(a: *const p8) -> poly8x8x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7135,6 +8207,8 @@ pub unsafe fn vld1_p8_x3(a: *const p8) -> poly8x8x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7146,6 +8220,8 @@ pub unsafe fn vld1_p8_x4(a: *const p8) -> poly8x8x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7157,6 +8233,8 @@ pub unsafe fn vld1q_p8_x2(a: *const p8) -> poly8x16x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7168,6 +8246,8 @@ pub unsafe fn vld1q_p8_x3(a: *const p8) -> poly8x16x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7179,6 +8259,8 @@ pub unsafe fn vld1q_p8_x4(a: *const p8) -> poly8x16x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7190,6 +8272,8 @@ pub unsafe fn vld1_p16_x2(a: *const p16) -> poly16x4x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7201,6 +8285,8 @@ pub unsafe fn vld1_p16_x3(a: *const p16) -> poly16x4x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7212,6 +8298,8 @@ pub unsafe fn vld1_p16_x4(a: *const p16) -> poly16x4x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7223,6 +8311,8 @@ pub unsafe fn vld1q_p16_x2(a: *const p16) -> poly16x8x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7234,6 +8324,8 @@ pub unsafe fn vld1q_p16_x3(a: *const p16) -> poly16x8x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7245,6 +8337,8 @@ pub unsafe fn vld1q_p16_x4(a: *const p16) -> poly16x8x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p64_x2) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7256,6 +8350,8 @@ pub unsafe fn vld1_p64_x2(a: *const p64) -> poly64x1x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p64_x3) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7267,6 +8363,8 @@ pub unsafe fn vld1_p64_x3(a: *const p64) -> poly64x1x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_p64_x4) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7278,6 +8376,8 @@ pub unsafe fn vld1_p64_x4(a: *const p64) -> poly64x1x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p64_x2) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7289,6 +8389,8 @@ pub unsafe fn vld1q_p64_x2(a: *const p64) -> poly64x2x2_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p64_x3) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7300,6 +8402,8 @@ pub unsafe fn vld1q_p64_x3(a: *const p64) -> poly64x2x3_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_p64_x4) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7311,6 +8415,8 @@ pub unsafe fn vld1q_p64_x4(a: *const p64) -> poly64x2x4_t { } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7328,6 +8434,8 @@ vld1_f32_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7345,6 +8453,8 @@ vld1q_f32_x2_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7362,6 +8472,8 @@ vld1_f32_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7379,6 +8491,8 @@ vld1q_f32_x3_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_f32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7396,6 +8510,8 @@ vld1_f32_x4_(a) } /// Load multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_f32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7413,6 +8529,8 @@ vld1q_f32_x4_(a) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7427,6 +8545,8 @@ vld2_s8_(a as *const i8, 1) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7442,6 +8562,8 @@ vld2_s8_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7456,6 +8578,8 @@ vld2_s16_(a as *const i8, 2) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7471,6 +8595,8 @@ vld2_s16_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7485,6 +8611,8 @@ vld2_s32_(a as *const i8, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7500,6 +8628,8 @@ vld2_s32_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7514,6 +8644,8 @@ vld2q_s8_(a as *const i8, 1) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7529,6 +8661,8 @@ vld2q_s8_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7543,6 +8677,8 @@ vld2q_s16_(a as *const i8, 2) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7558,6 +8694,8 @@ vld2q_s16_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7572,6 +8710,8 @@ vld2q_s32_(a as *const i8, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7587,6 +8727,8 @@ vld2q_s32_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7601,6 +8743,8 @@ vld2_s64_(a as *const i8, 8) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7616,6 +8760,8 @@ vld2_s64_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7627,6 +8773,8 @@ pub unsafe fn vld2_u8(a: *const u8) -> uint8x8x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7638,6 +8786,8 @@ pub unsafe fn vld2_u16(a: *const u16) -> uint16x4x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7649,6 +8799,8 @@ pub unsafe fn vld2_u32(a: *const u32) -> uint32x2x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7660,6 +8812,8 @@ pub unsafe fn vld2q_u8(a: *const u8) -> uint8x16x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7671,6 +8825,8 @@ pub unsafe fn vld2q_u16(a: *const u16) -> uint16x8x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7682,6 +8838,8 @@ pub unsafe fn vld2q_u32(a: *const u32) -> uint32x4x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7693,6 +8851,8 @@ pub unsafe fn vld2_p8(a: *const p8) -> poly8x8x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7704,6 +8864,8 @@ pub unsafe fn vld2_p16(a: *const p16) -> poly16x4x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7715,6 +8877,8 @@ pub unsafe fn vld2q_p8(a: *const p8) -> poly8x16x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7726,6 +8890,8 @@ pub unsafe fn vld2q_p16(a: *const p16) -> poly16x8x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -7737,6 +8903,8 @@ pub unsafe fn vld2_u64(a: *const u64) -> uint64x1x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -7748,6 +8916,8 @@ pub unsafe fn vld2_p64(a: *const p64) -> poly64x1x2_t { } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7762,6 +8932,8 @@ vld2_f32_(a as *const i8, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7777,6 +8949,8 @@ vld2_f32_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7791,6 +8965,8 @@ vld2q_f32_(a as *const i8, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7806,6 +8982,8 @@ vld2q_f32_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7820,6 +8998,8 @@ vld2_dup_s8_(a as *const i8, 1) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7835,6 +9015,8 @@ vld2_dup_s8_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7849,6 +9031,8 @@ vld2_dup_s16_(a as *const i8, 2) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7864,6 +9048,8 @@ vld2_dup_s16_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7878,6 +9064,8 @@ vld2_dup_s32_(a as *const i8, 4) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7893,6 +9081,8 @@ vld2_dup_s32_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7907,6 +9097,8 @@ vld2q_dup_s8_(a as *const i8, 1) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7922,6 +9114,8 @@ vld2q_dup_s8_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7936,6 +9130,8 @@ vld2q_dup_s16_(a as *const i8, 2) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7951,6 +9147,8 @@ vld2q_dup_s16_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7965,6 +9163,8 @@ vld2q_dup_s32_(a as *const i8, 4) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -7980,6 +9180,8 @@ vld2q_dup_s32_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -7994,6 +9196,8 @@ vld2_dup_s64_(a as *const i8, 8) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8009,6 +9213,8 @@ vld2_dup_s64_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8020,6 +9226,8 @@ pub unsafe fn vld2_dup_u8(a: *const u8) -> uint8x8x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8031,6 +9239,8 @@ pub unsafe fn vld2_dup_u16(a: *const u16) -> uint16x4x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8042,6 +9252,8 @@ pub unsafe fn vld2_dup_u32(a: *const u32) -> uint32x2x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8053,6 +9265,8 @@ pub unsafe fn vld2q_dup_u8(a: *const u8) -> uint8x16x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8064,6 +9278,8 @@ pub unsafe fn vld2q_dup_u16(a: *const u16) -> uint16x8x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8075,6 +9291,8 @@ pub unsafe fn vld2q_dup_u32(a: *const u32) -> uint32x4x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8086,6 +9304,8 @@ pub unsafe fn vld2_dup_p8(a: *const p8) -> poly8x8x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8097,6 +9317,8 @@ pub unsafe fn vld2_dup_p16(a: *const p16) -> poly16x4x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8108,6 +9330,8 @@ pub unsafe fn vld2q_dup_p8(a: *const p8) -> poly8x16x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8119,6 +9343,8 @@ pub unsafe fn vld2q_dup_p16(a: *const p16) -> poly16x8x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8130,6 +9356,8 @@ pub unsafe fn vld2_dup_u64(a: *const u64) -> uint64x1x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -8141,6 +9369,8 @@ pub unsafe fn vld2_dup_p64(a: *const p64) -> poly64x1x2_t { } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8155,6 +9385,8 @@ vld2_dup_f32_(a as *const i8, 4) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8170,6 +9402,8 @@ vld2_dup_f32_(a as _) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8184,6 +9418,8 @@ vld2q_dup_f32_(a as *const i8, 4) } /// Load single 2-element structure and replicate to all lanes of two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8199,6 +9435,8 @@ vld2q_dup_f32_(a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8215,6 +9453,8 @@ vld2_lane_s8_(a as _, b.0, b.1, LANE, 1) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8232,6 +9472,8 @@ vld2_lane_s8_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8248,6 +9490,8 @@ vld2_lane_s16_(a as _, b.0, b.1, LANE, 2) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8265,6 +9509,8 @@ vld2_lane_s16_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8281,6 +9527,8 @@ vld2_lane_s32_(a as _, b.0, b.1, LANE, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8298,6 +9546,8 @@ vld2_lane_s32_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8314,6 +9564,8 @@ vld2q_lane_s16_(a as _, b.0, b.1, LANE, 2) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8331,6 +9583,8 @@ vld2q_lane_s16_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8347,6 +9601,8 @@ vld2q_lane_s32_(a as _, b.0, b.1, LANE, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8364,6 +9620,8 @@ vld2q_lane_s32_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8377,6 +9635,8 @@ pub unsafe fn vld2_lane_u8(a: *const u8, b: uint8x8x2_t) -> uin } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8390,6 +9650,8 @@ pub unsafe fn vld2_lane_u16(a: *const u16, b: uint16x4x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8403,6 +9665,8 @@ pub unsafe fn vld2_lane_u32(a: *const u32, b: uint32x2x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8416,6 +9680,8 @@ pub unsafe fn vld2q_lane_u16(a: *const u16, b: uint16x8x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8429,6 +9695,8 @@ pub unsafe fn vld2q_lane_u32(a: *const u32, b: uint32x4x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8442,6 +9710,8 @@ pub unsafe fn vld2_lane_p8(a: *const p8, b: poly8x8x2_t) -> pol } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8455,6 +9725,8 @@ pub unsafe fn vld2_lane_p16(a: *const p16, b: poly16x4x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8468,6 +9740,8 @@ pub unsafe fn vld2q_lane_p16(a: *const p16, b: poly16x8x2_t) -> } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8484,6 +9758,8 @@ vld2_lane_f32_(a as _, b.0, b.1, LANE, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8501,6 +9777,8 @@ vld2_lane_f32_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8517,6 +9795,8 @@ vld2q_lane_f32_(a as _, b.0, b.1, LANE, 4) } /// Load multiple 2-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld2q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8534,6 +9814,8 @@ vld2q_lane_f32_(b.0, b.1, LANE as i64, a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8548,6 +9830,8 @@ vld3_s8_(a as *const i8, 1) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8563,6 +9847,8 @@ vld3_s8_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8577,6 +9863,8 @@ vld3_s16_(a as *const i8, 2) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8592,6 +9880,8 @@ vld3_s16_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8606,6 +9896,8 @@ vld3_s32_(a as *const i8, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8621,6 +9913,8 @@ vld3_s32_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8635,6 +9929,8 @@ vld3q_s8_(a as *const i8, 1) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8650,6 +9946,8 @@ vld3q_s8_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8664,6 +9962,8 @@ vld3q_s16_(a as *const i8, 2) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8679,6 +9979,8 @@ vld3q_s16_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8693,6 +9995,8 @@ vld3q_s32_(a as *const i8, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8708,6 +10012,8 @@ vld3q_s32_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8722,6 +10028,8 @@ vld3_s64_(a as *const i8, 8) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8737,6 +10045,8 @@ vld3_s64_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8748,6 +10058,8 @@ pub unsafe fn vld3_u8(a: *const u8) -> uint8x8x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8759,6 +10071,8 @@ pub unsafe fn vld3_u16(a: *const u16) -> uint16x4x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8770,6 +10084,8 @@ pub unsafe fn vld3_u32(a: *const u32) -> uint32x2x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8781,6 +10097,8 @@ pub unsafe fn vld3q_u8(a: *const u8) -> uint8x16x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8792,6 +10110,8 @@ pub unsafe fn vld3q_u16(a: *const u16) -> uint16x8x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8803,6 +10123,8 @@ pub unsafe fn vld3q_u32(a: *const u32) -> uint32x4x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8814,6 +10136,8 @@ pub unsafe fn vld3_p8(a: *const p8) -> poly8x8x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8825,6 +10149,8 @@ pub unsafe fn vld3_p16(a: *const p16) -> poly16x4x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8836,6 +10162,8 @@ pub unsafe fn vld3q_p8(a: *const p8) -> poly8x16x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8847,6 +10175,8 @@ pub unsafe fn vld3q_p16(a: *const p16) -> poly16x8x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -8858,6 +10188,8 @@ pub unsafe fn vld3_u64(a: *const u64) -> uint64x1x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -8869,6 +10201,8 @@ pub unsafe fn vld3_p64(a: *const p64) -> poly64x1x3_t { } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8883,6 +10217,8 @@ vld3_f32_(a as *const i8, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8898,6 +10234,8 @@ vld3_f32_(a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8912,6 +10250,8 @@ vld3q_f32_(a as *const i8, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8927,6 +10267,8 @@ vld3q_f32_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8941,6 +10283,8 @@ vld3_dup_s8_(a as *const i8, 1) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8956,6 +10300,8 @@ vld3_dup_s8_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8970,6 +10316,8 @@ vld3_dup_s16_(a as *const i8, 2) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -8985,6 +10333,8 @@ vld3_dup_s16_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -8999,6 +10349,8 @@ vld3_dup_s32_(a as *const i8, 4) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9014,6 +10366,8 @@ vld3_dup_s32_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9028,6 +10382,8 @@ vld3q_dup_s8_(a as *const i8, 1) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9043,6 +10399,8 @@ vld3q_dup_s8_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9057,6 +10415,8 @@ vld3q_dup_s16_(a as *const i8, 2) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9072,6 +10432,8 @@ vld3q_dup_s16_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9086,6 +10448,8 @@ vld3q_dup_s32_(a as *const i8, 4) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9101,6 +10465,8 @@ vld3q_dup_s32_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9115,6 +10481,8 @@ vld3_dup_s64_(a as *const i8, 8) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9130,6 +10498,8 @@ vld3_dup_s64_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9141,6 +10511,8 @@ pub unsafe fn vld3_dup_u8(a: *const u8) -> uint8x8x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9152,6 +10524,8 @@ pub unsafe fn vld3_dup_u16(a: *const u16) -> uint16x4x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9163,6 +10537,8 @@ pub unsafe fn vld3_dup_u32(a: *const u32) -> uint32x2x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9174,6 +10550,8 @@ pub unsafe fn vld3q_dup_u8(a: *const u8) -> uint8x16x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9185,6 +10563,8 @@ pub unsafe fn vld3q_dup_u16(a: *const u16) -> uint16x8x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9196,6 +10576,8 @@ pub unsafe fn vld3q_dup_u32(a: *const u32) -> uint32x4x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9207,6 +10589,8 @@ pub unsafe fn vld3_dup_p8(a: *const p8) -> poly8x8x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9218,6 +10602,8 @@ pub unsafe fn vld3_dup_p16(a: *const p16) -> poly16x4x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9229,6 +10615,8 @@ pub unsafe fn vld3q_dup_p8(a: *const p8) -> poly8x16x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9240,6 +10628,8 @@ pub unsafe fn vld3q_dup_p16(a: *const p16) -> poly16x8x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9251,6 +10641,8 @@ pub unsafe fn vld3_dup_u64(a: *const u64) -> uint64x1x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -9262,6 +10654,8 @@ pub unsafe fn vld3_dup_p64(a: *const p64) -> poly64x1x3_t { } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9276,6 +10670,8 @@ vld3_dup_f32_(a as *const i8, 4) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9291,6 +10687,8 @@ vld3_dup_f32_(a as _) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9305,6 +10703,8 @@ vld3q_dup_f32_(a as *const i8, 4) } /// Load single 3-element structure and replicate to all lanes of three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9320,6 +10720,8 @@ vld3q_dup_f32_(a as _) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9336,6 +10738,8 @@ vld3_lane_s8_(a as _, b.0, b.1, b.2, LANE, 1) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9353,6 +10757,8 @@ vld3_lane_s8_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9369,6 +10775,8 @@ vld3_lane_s16_(a as _, b.0, b.1, b.2, LANE, 2) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9386,6 +10794,8 @@ vld3_lane_s16_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9402,6 +10812,8 @@ vld3_lane_s32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9419,6 +10831,8 @@ vld3_lane_s32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9435,6 +10849,8 @@ vld3q_lane_s16_(a as _, b.0, b.1, b.2, LANE, 2) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9452,6 +10868,8 @@ vld3q_lane_s16_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9468,6 +10886,8 @@ vld3q_lane_s32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Load multiple 3-element structures to two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9485,6 +10905,8 @@ vld3q_lane_s32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9498,6 +10920,8 @@ pub unsafe fn vld3_lane_u8(a: *const u8, b: uint8x8x3_t) -> uin } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9511,6 +10935,8 @@ pub unsafe fn vld3_lane_u16(a: *const u16, b: uint16x4x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9524,6 +10950,8 @@ pub unsafe fn vld3_lane_u32(a: *const u32, b: uint32x2x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9537,6 +10965,8 @@ pub unsafe fn vld3q_lane_u16(a: *const u16, b: uint16x8x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9550,6 +10980,8 @@ pub unsafe fn vld3q_lane_u32(a: *const u32, b: uint32x4x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9563,6 +10995,8 @@ pub unsafe fn vld3_lane_p8(a: *const p8, b: poly8x8x3_t) -> pol } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9576,6 +11010,8 @@ pub unsafe fn vld3_lane_p16(a: *const p16, b: poly16x4x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9589,6 +11025,8 @@ pub unsafe fn vld3q_lane_p16(a: *const p16, b: poly16x8x3_t) -> } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9605,6 +11043,8 @@ vld3_lane_f32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9622,6 +11062,8 @@ vld3_lane_f32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9638,6 +11080,8 @@ vld3q_lane_f32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Load multiple 3-element structures to three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld3q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9655,6 +11099,8 @@ vld3q_lane_f32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9669,6 +11115,8 @@ vld4_s8_(a as *const i8, 1) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9684,6 +11132,8 @@ vld4_s8_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9698,6 +11148,8 @@ vld4_s16_(a as *const i8, 2) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9713,6 +11165,8 @@ vld4_s16_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9727,6 +11181,8 @@ vld4_s32_(a as *const i8, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9742,6 +11198,8 @@ vld4_s32_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9756,6 +11214,8 @@ vld4q_s8_(a as *const i8, 1) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9771,6 +11231,8 @@ vld4q_s8_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9785,6 +11247,8 @@ vld4q_s16_(a as *const i8, 2) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9800,6 +11264,8 @@ vld4q_s16_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9814,6 +11280,8 @@ vld4q_s32_(a as *const i8, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9829,6 +11297,8 @@ vld4q_s32_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -9843,6 +11313,8 @@ vld4_s64_(a as *const i8, 8) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -9858,6 +11330,8 @@ vld4_s64_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9869,6 +11343,8 @@ pub unsafe fn vld4_u8(a: *const u8) -> uint8x8x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9880,6 +11356,8 @@ pub unsafe fn vld4_u16(a: *const u16) -> uint16x4x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9891,6 +11369,8 @@ pub unsafe fn vld4_u32(a: *const u32) -> uint32x2x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9902,6 +11382,8 @@ pub unsafe fn vld4q_u8(a: *const u8) -> uint8x16x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9913,6 +11395,8 @@ pub unsafe fn vld4q_u16(a: *const u16) -> uint16x8x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9924,6 +11408,8 @@ pub unsafe fn vld4q_u32(a: *const u32) -> uint32x4x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9935,6 +11421,8 @@ pub unsafe fn vld4_p8(a: *const p8) -> poly8x8x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9946,6 +11434,8 @@ pub unsafe fn vld4_p16(a: *const p16) -> poly16x4x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9957,6 +11447,8 @@ pub unsafe fn vld4q_p8(a: *const p8) -> poly8x16x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9968,6 +11460,8 @@ pub unsafe fn vld4q_p16(a: *const p16) -> poly16x8x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -9979,6 +11473,8 @@ pub unsafe fn vld4_u64(a: *const u64) -> uint64x1x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -9990,6 +11486,8 @@ pub unsafe fn vld4_p64(a: *const p64) -> poly64x1x4_t { } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10004,6 +11502,8 @@ vld4_f32_(a as *const i8, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10019,6 +11519,8 @@ vld4_f32_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10033,6 +11535,8 @@ vld4q_f32_(a as *const i8, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10048,6 +11552,8 @@ vld4q_f32_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10062,6 +11568,8 @@ vld4_dup_s8_(a as *const i8, 1) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10077,6 +11585,8 @@ vld4_dup_s8_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10091,6 +11601,8 @@ vld4_dup_s16_(a as *const i8, 2) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10106,6 +11618,8 @@ vld4_dup_s16_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10120,6 +11634,8 @@ vld4_dup_s32_(a as *const i8, 4) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10135,6 +11651,8 @@ vld4_dup_s32_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10149,6 +11667,8 @@ vld4q_dup_s8_(a as *const i8, 1) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10164,6 +11684,8 @@ vld4q_dup_s8_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10178,6 +11700,8 @@ vld4q_dup_s16_(a as *const i8, 2) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10193,6 +11717,8 @@ vld4q_dup_s16_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10207,6 +11733,8 @@ vld4q_dup_s32_(a as *const i8, 4) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10222,6 +11750,8 @@ vld4q_dup_s32_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10236,6 +11766,8 @@ vld4_dup_s64_(a as *const i8, 8) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10251,6 +11783,8 @@ vld4_dup_s64_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10262,6 +11796,8 @@ pub unsafe fn vld4_dup_u8(a: *const u8) -> uint8x8x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10273,6 +11809,8 @@ pub unsafe fn vld4_dup_u16(a: *const u16) -> uint16x4x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10284,6 +11822,8 @@ pub unsafe fn vld4_dup_u32(a: *const u32) -> uint32x2x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10295,6 +11835,8 @@ pub unsafe fn vld4q_dup_u8(a: *const u8) -> uint8x16x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10306,6 +11848,8 @@ pub unsafe fn vld4q_dup_u16(a: *const u16) -> uint16x8x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10317,6 +11861,8 @@ pub unsafe fn vld4q_dup_u32(a: *const u32) -> uint32x4x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10328,6 +11874,8 @@ pub unsafe fn vld4_dup_p8(a: *const p8) -> poly8x8x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10339,6 +11887,8 @@ pub unsafe fn vld4_dup_p16(a: *const p16) -> poly16x4x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10350,6 +11900,8 @@ pub unsafe fn vld4q_dup_p8(a: *const p8) -> poly8x16x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10361,6 +11913,8 @@ pub unsafe fn vld4q_dup_p16(a: *const p16) -> poly16x8x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10372,6 +11926,8 @@ pub unsafe fn vld4_dup_u64(a: *const u64) -> uint64x1x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -10383,6 +11939,8 @@ pub unsafe fn vld4_dup_p64(a: *const p64) -> poly64x1x4_t { } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10397,6 +11955,8 @@ vld4_dup_f32_(a as *const i8, 4) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10412,6 +11972,8 @@ vld4_dup_f32_(a as _) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10426,6 +11988,8 @@ vld4q_dup_f32_(a as *const i8, 4) } /// Load single 4-element structure and replicate to all lanes of four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_dup_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10441,6 +12005,8 @@ vld4q_dup_f32_(a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10457,6 +12023,8 @@ vld4_lane_s8_(a as _, b.0, b.1, b.2, b.3, LANE, 1) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10474,6 +12042,8 @@ vld4_lane_s8_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10490,6 +12060,8 @@ vld4_lane_s16_(a as _, b.0, b.1, b.2, b.3, LANE, 2) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10507,6 +12079,8 @@ vld4_lane_s16_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10523,6 +12097,8 @@ vld4_lane_s32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10540,6 +12116,8 @@ vld4_lane_s32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10556,6 +12134,8 @@ vld4q_lane_s16_(a as _, b.0, b.1, b.2, b.3, LANE, 2) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10573,6 +12153,8 @@ vld4q_lane_s16_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10589,6 +12171,8 @@ vld4q_lane_s32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10606,6 +12190,8 @@ vld4q_lane_s32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10619,6 +12205,8 @@ pub unsafe fn vld4_lane_u8(a: *const u8, b: uint8x8x4_t) -> uin } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10632,6 +12220,8 @@ pub unsafe fn vld4_lane_u16(a: *const u16, b: uint16x4x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10645,6 +12235,8 @@ pub unsafe fn vld4_lane_u32(a: *const u32, b: uint32x2x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10658,6 +12250,8 @@ pub unsafe fn vld4q_lane_u16(a: *const u16, b: uint16x8x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10671,6 +12265,8 @@ pub unsafe fn vld4q_lane_u32(a: *const u32, b: uint32x4x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10684,6 +12280,8 @@ pub unsafe fn vld4_lane_p8(a: *const p8, b: poly8x8x4_t) -> pol } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10697,6 +12295,8 @@ pub unsafe fn vld4_lane_p16(a: *const p16, b: poly16x4x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10710,6 +12310,8 @@ pub unsafe fn vld4q_lane_p16(a: *const p16, b: poly16x8x4_t) -> } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10726,6 +12328,8 @@ vld4_lane_f32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10743,6 +12347,8 @@ vld4_lane_f32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -10759,6 +12365,8 @@ vld4q_lane_f32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Load multiple 4-element structures to four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld4q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -10776,6 +12384,8 @@ vld4q_lane_f32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10789,6 +12399,8 @@ pub unsafe fn vst1_lane_s8(a: *mut i8, b: int8x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10802,6 +12414,8 @@ pub unsafe fn vst1_lane_s16(a: *mut i16, b: int16x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10815,6 +12429,8 @@ pub unsafe fn vst1_lane_s32(a: *mut i32, b: int32x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10828,6 +12444,8 @@ pub unsafe fn vst1_lane_s64(a: *mut i64, b: int64x1_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10841,6 +12459,8 @@ pub unsafe fn vst1q_lane_s8(a: *mut i8, b: int8x16_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10854,6 +12474,8 @@ pub unsafe fn vst1q_lane_s16(a: *mut i16, b: int16x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10867,6 +12489,8 @@ pub unsafe fn vst1q_lane_s32(a: *mut i32, b: int32x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10880,6 +12504,8 @@ pub unsafe fn vst1q_lane_s64(a: *mut i64, b: int64x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10893,6 +12519,8 @@ pub unsafe fn vst1_lane_u8(a: *mut u8, b: uint8x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10906,6 +12534,8 @@ pub unsafe fn vst1_lane_u16(a: *mut u16, b: uint16x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10919,6 +12549,8 @@ pub unsafe fn vst1_lane_u32(a: *mut u32, b: uint32x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10932,6 +12564,8 @@ pub unsafe fn vst1_lane_u64(a: *mut u64, b: uint64x1_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10945,6 +12579,8 @@ pub unsafe fn vst1q_lane_u8(a: *mut u8, b: uint8x16_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10958,6 +12594,8 @@ pub unsafe fn vst1q_lane_u16(a: *mut u16, b: uint16x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10971,6 +12609,8 @@ pub unsafe fn vst1q_lane_u32(a: *mut u32, b: uint32x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10984,6 +12624,8 @@ pub unsafe fn vst1q_lane_u64(a: *mut u64, b: uint64x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -10997,6 +12639,8 @@ pub unsafe fn vst1_lane_p8(a: *mut p8, b: poly8x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11010,6 +12654,8 @@ pub unsafe fn vst1_lane_p16(a: *mut p16, b: poly16x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11023,6 +12669,8 @@ pub unsafe fn vst1q_lane_p8(a: *mut p8, b: poly8x16_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11036,6 +12684,8 @@ pub unsafe fn vst1q_lane_p16(a: *mut p16, b: poly16x8_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -11049,6 +12699,8 @@ pub unsafe fn vst1_lane_p64(a: *mut p64, b: poly64x1_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -11062,6 +12714,8 @@ pub unsafe fn vst1q_lane_p64(a: *mut p64, b: poly64x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11075,6 +12729,8 @@ pub unsafe fn vst1_lane_f32(a: *mut f32, b: float32x2_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11088,6 +12744,8 @@ pub unsafe fn vst1q_lane_f32(a: *mut f32, b: float32x4_t) { } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11102,6 +12760,8 @@ vst1_s8_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11117,6 +12777,8 @@ vst1_s8_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11131,6 +12793,8 @@ vst1_s16_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11146,6 +12810,8 @@ vst1_s16_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11160,6 +12826,8 @@ vst1_s32_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11175,6 +12843,8 @@ vst1_s32_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11189,6 +12859,8 @@ vst1_s64_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11204,6 +12876,8 @@ vst1_s64_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11218,6 +12892,8 @@ vst1q_s8_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11233,6 +12909,8 @@ vst1q_s8_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11247,6 +12925,8 @@ vst1q_s16_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11262,6 +12942,8 @@ vst1q_s16_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11276,6 +12958,8 @@ vst1q_s32_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11291,6 +12975,8 @@ vst1q_s32_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11305,6 +12991,8 @@ vst1q_s64_x2_(a, b.0, b.1) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11320,6 +13008,8 @@ vst1q_s64_x2_(b.0, b.1, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11334,6 +13024,8 @@ vst1_s8_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11349,6 +13041,8 @@ vst1_s8_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11363,6 +13057,8 @@ vst1_s16_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11378,6 +13074,8 @@ vst1_s16_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11392,6 +13090,8 @@ vst1_s32_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11407,6 +13107,8 @@ vst1_s32_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11421,6 +13123,8 @@ vst1_s64_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11436,6 +13140,8 @@ vst1_s64_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11450,6 +13156,8 @@ vst1q_s8_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11465,6 +13173,8 @@ vst1q_s8_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11479,6 +13189,8 @@ vst1q_s16_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11494,6 +13206,8 @@ vst1q_s16_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11508,6 +13222,8 @@ vst1q_s32_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11523,6 +13239,8 @@ vst1q_s32_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11537,6 +13255,8 @@ vst1q_s64_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11552,6 +13272,8 @@ vst1q_s64_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11566,6 +13288,8 @@ vst1_s8_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s8_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11581,6 +13305,8 @@ vst1_s8_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11595,6 +13321,8 @@ vst1_s16_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s16_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11610,6 +13338,8 @@ vst1_s16_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11624,6 +13354,8 @@ vst1_s32_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s32_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11639,6 +13371,8 @@ vst1_s32_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11653,6 +13387,8 @@ vst1_s64_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_s64_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11668,6 +13404,8 @@ vst1_s64_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11682,6 +13420,8 @@ vst1q_s8_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s8_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11697,6 +13437,8 @@ vst1q_s8_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11711,6 +13453,8 @@ vst1q_s16_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s16_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11726,6 +13470,8 @@ vst1q_s16_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11740,6 +13486,8 @@ vst1q_s32_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s32_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11755,6 +13503,8 @@ vst1q_s32_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -11769,6 +13519,8 @@ vst1q_s64_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures from one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_s64_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -11784,6 +13536,8 @@ vst1q_s64_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11795,6 +13549,8 @@ pub unsafe fn vst1_u8_x2(a: *mut u8, b: uint8x8x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11806,6 +13562,8 @@ pub unsafe fn vst1_u16_x2(a: *mut u16, b: uint16x4x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11817,6 +13575,8 @@ pub unsafe fn vst1_u32_x2(a: *mut u32, b: uint32x2x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11828,6 +13588,8 @@ pub unsafe fn vst1_u64_x2(a: *mut u64, b: uint64x1x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11839,6 +13601,8 @@ pub unsafe fn vst1q_u8_x2(a: *mut u8, b: uint8x16x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11850,6 +13614,8 @@ pub unsafe fn vst1q_u16_x2(a: *mut u16, b: uint16x8x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u32_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11861,6 +13627,8 @@ pub unsafe fn vst1q_u32_x2(a: *mut u32, b: uint32x4x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u64_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11872,6 +13640,8 @@ pub unsafe fn vst1q_u64_x2(a: *mut u64, b: uint64x2x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11883,6 +13653,8 @@ pub unsafe fn vst1_u8_x3(a: *mut u8, b: uint8x8x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11894,6 +13666,8 @@ pub unsafe fn vst1_u16_x3(a: *mut u16, b: uint16x4x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11905,6 +13679,8 @@ pub unsafe fn vst1_u32_x3(a: *mut u32, b: uint32x2x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11916,6 +13692,8 @@ pub unsafe fn vst1_u64_x3(a: *mut u64, b: uint64x1x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11927,6 +13705,8 @@ pub unsafe fn vst1q_u8_x3(a: *mut u8, b: uint8x16x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11938,6 +13718,8 @@ pub unsafe fn vst1q_u16_x3(a: *mut u16, b: uint16x8x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u32_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11949,6 +13731,8 @@ pub unsafe fn vst1q_u32_x3(a: *mut u32, b: uint32x4x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u64_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11960,6 +13744,8 @@ pub unsafe fn vst1q_u64_x3(a: *mut u64, b: uint64x2x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11971,6 +13757,8 @@ pub unsafe fn vst1_u8_x4(a: *mut u8, b: uint8x8x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11982,6 +13770,8 @@ pub unsafe fn vst1_u16_x4(a: *mut u16, b: uint16x4x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -11993,6 +13783,8 @@ pub unsafe fn vst1_u32_x4(a: *mut u32, b: uint32x2x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_u64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12004,6 +13796,8 @@ pub unsafe fn vst1_u64_x4(a: *mut u64, b: uint64x1x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12015,6 +13809,8 @@ pub unsafe fn vst1q_u8_x4(a: *mut u8, b: uint8x16x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12026,6 +13822,8 @@ pub unsafe fn vst1q_u16_x4(a: *mut u16, b: uint16x8x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u32_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12037,6 +13835,8 @@ pub unsafe fn vst1q_u32_x4(a: *mut u32, b: uint32x4x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_u64_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12048,6 +13848,8 @@ pub unsafe fn vst1q_u64_x4(a: *mut u64, b: uint64x2x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12059,6 +13861,8 @@ pub unsafe fn vst1_p8_x2(a: *mut p8, b: poly8x8x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12070,6 +13874,8 @@ pub unsafe fn vst1_p8_x3(a: *mut p8, b: poly8x8x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12081,6 +13887,8 @@ pub unsafe fn vst1_p8_x4(a: *mut p8, b: poly8x8x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p8_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12092,6 +13900,8 @@ pub unsafe fn vst1q_p8_x2(a: *mut p8, b: poly8x16x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p8_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12103,6 +13913,8 @@ pub unsafe fn vst1q_p8_x3(a: *mut p8, b: poly8x16x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p8_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12114,6 +13926,8 @@ pub unsafe fn vst1q_p8_x4(a: *mut p8, b: poly8x16x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12125,6 +13939,8 @@ pub unsafe fn vst1_p16_x2(a: *mut p16, b: poly16x4x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12136,6 +13952,8 @@ pub unsafe fn vst1_p16_x3(a: *mut p16, b: poly16x4x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12147,6 +13965,8 @@ pub unsafe fn vst1_p16_x4(a: *mut p16, b: poly16x4x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p16_x2) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12158,6 +13978,8 @@ pub unsafe fn vst1q_p16_x2(a: *mut p16, b: poly16x8x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p16_x3) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12169,6 +13991,8 @@ pub unsafe fn vst1q_p16_x3(a: *mut p16, b: poly16x8x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p16_x4) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12180,6 +14004,8 @@ pub unsafe fn vst1q_p16_x4(a: *mut p16, b: poly16x8x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p64_x2) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12191,6 +14017,8 @@ pub unsafe fn vst1_p64_x2(a: *mut p64, b: poly64x1x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p64_x3) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12202,6 +14030,8 @@ pub unsafe fn vst1_p64_x3(a: *mut p64, b: poly64x1x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_p64_x4) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12213,6 +14043,8 @@ pub unsafe fn vst1_p64_x4(a: *mut p64, b: poly64x1x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p64_x2) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12224,6 +14056,8 @@ pub unsafe fn vst1q_p64_x2(a: *mut p64, b: poly64x2x2_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p64_x3) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12235,6 +14069,8 @@ pub unsafe fn vst1q_p64_x3(a: *mut p64, b: poly64x2x3_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_p64_x4) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12246,6 +14082,8 @@ pub unsafe fn vst1q_p64_x4(a: *mut p64, b: poly64x2x4_t) { } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12260,6 +14098,8 @@ vst1_f32_x2_(a, b.0, b.1) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12275,6 +14115,8 @@ vst1_f32_x2_(b.0, b.1, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x2) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12289,6 +14131,8 @@ vst1q_f32_x2_(a, b.0, b.1) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x2) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12304,6 +14148,8 @@ vst1q_f32_x2_(b.0, b.1, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12318,6 +14164,8 @@ vst1_f32_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12333,6 +14181,8 @@ vst1_f32_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x3) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12347,6 +14197,8 @@ vst1q_f32_x3_(a, b.0, b.1, b.2) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x3) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12362,6 +14214,8 @@ vst1q_f32_x3_(b.0, b.1, b.2, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12376,6 +14230,8 @@ vst1_f32_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1_f32_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12391,6 +14247,8 @@ vst1_f32_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x4) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12405,6 +14263,8 @@ vst1q_f32_x4_(a, b.0, b.1, b.2, b.3) } /// Store multiple single-element structures to one, two, three, or four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst1q_f32_x4) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12420,6 +14280,8 @@ vst1q_f32_x4_(b.0, b.1, b.2, b.3, a) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12434,6 +14296,8 @@ vst2_s8_(a as _, b.0, b.1, 1) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12449,6 +14313,8 @@ vst2_s8_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12463,6 +14329,8 @@ vst2_s16_(a as _, b.0, b.1, 2) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12478,6 +14346,8 @@ vst2_s16_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12492,6 +14362,8 @@ vst2_s32_(a as _, b.0, b.1, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12507,6 +14379,8 @@ vst2_s32_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12521,6 +14395,8 @@ vst2q_s8_(a as _, b.0, b.1, 1) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12536,6 +14412,8 @@ vst2q_s8_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12550,6 +14428,8 @@ vst2q_s16_(a as _, b.0, b.1, 2) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12565,6 +14445,8 @@ vst2q_s16_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12579,6 +14461,8 @@ vst2q_s32_(a as _, b.0, b.1, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12594,6 +14478,8 @@ vst2q_s32_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12608,6 +14494,8 @@ vst2_s64_(a as _, b.0, b.1, 8) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12623,6 +14511,8 @@ vst2_s64_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12634,6 +14524,8 @@ pub unsafe fn vst2_u8(a: *mut u8, b: uint8x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12645,6 +14537,8 @@ pub unsafe fn vst2_u16(a: *mut u16, b: uint16x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12656,6 +14550,8 @@ pub unsafe fn vst2_u32(a: *mut u32, b: uint32x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12667,6 +14563,8 @@ pub unsafe fn vst2q_u8(a: *mut u8, b: uint8x16x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12678,6 +14576,8 @@ pub unsafe fn vst2q_u16(a: *mut u16, b: uint16x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12689,6 +14589,8 @@ pub unsafe fn vst2q_u32(a: *mut u32, b: uint32x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12700,6 +14602,8 @@ pub unsafe fn vst2_p8(a: *mut p8, b: poly8x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12711,6 +14615,8 @@ pub unsafe fn vst2_p16(a: *mut p16, b: poly16x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12722,6 +14628,8 @@ pub unsafe fn vst2q_p8(a: *mut p8, b: poly8x16x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12733,6 +14641,8 @@ pub unsafe fn vst2q_p16(a: *mut p16, b: poly16x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12744,6 +14654,8 @@ pub unsafe fn vst2_u64(a: *mut u64, b: uint64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -12755,6 +14667,8 @@ pub unsafe fn vst2_p64(a: *mut p64, b: poly64x1x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12769,6 +14683,8 @@ vst2_f32_(a as _, b.0, b.1, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12784,6 +14700,8 @@ vst2_f32_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12798,6 +14716,8 @@ vst2q_f32_(a as _, b.0, b.1, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12813,6 +14733,8 @@ vst2q_f32_(b.0, b.1, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12829,6 +14751,8 @@ vst2_lane_s8_(a as _, b.0, b.1, LANE, 1) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12846,6 +14770,8 @@ vst2_lane_s8_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12862,6 +14788,8 @@ vst2_lane_s16_(a as _, b.0, b.1, LANE, 2) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12879,6 +14807,8 @@ vst2_lane_s16_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12895,6 +14825,8 @@ vst2_lane_s32_(a as _, b.0, b.1, LANE, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12912,6 +14844,8 @@ vst2_lane_s32_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12928,6 +14862,8 @@ vst2q_lane_s16_(a as _, b.0, b.1, LANE, 2) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12945,6 +14881,8 @@ vst2q_lane_s16_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -12961,6 +14899,8 @@ vst2q_lane_s32_(a as _, b.0, b.1, LANE, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -12978,6 +14918,8 @@ vst2q_lane_s32_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -12991,6 +14933,8 @@ pub unsafe fn vst2_lane_u8(a: *mut u8, b: uint8x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13004,6 +14948,8 @@ pub unsafe fn vst2_lane_u16(a: *mut u16, b: uint16x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13017,6 +14963,8 @@ pub unsafe fn vst2_lane_u32(a: *mut u32, b: uint32x2x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13030,6 +14978,8 @@ pub unsafe fn vst2q_lane_u16(a: *mut u16, b: uint16x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13043,6 +14993,8 @@ pub unsafe fn vst2q_lane_u32(a: *mut u32, b: uint32x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13056,6 +15008,8 @@ pub unsafe fn vst2_lane_p8(a: *mut p8, b: poly8x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13069,6 +15023,8 @@ pub unsafe fn vst2_lane_p16(a: *mut p16, b: poly16x4x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13082,6 +15038,8 @@ pub unsafe fn vst2q_lane_p16(a: *mut p16, b: poly16x8x2_t) { } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13098,6 +15056,8 @@ vst2_lane_f32_(a as _, b.0, b.1, LANE, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13115,6 +15075,8 @@ vst2_lane_f32_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13131,6 +15093,8 @@ vst2q_lane_f32_(a as _, b.0, b.1, LANE, 4) } /// Store multiple 2-element structures from two registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst2q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13148,6 +15112,8 @@ vst2q_lane_f32_(b.0, b.1, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13162,6 +15128,8 @@ vst3_s8_(a as _, b.0, b.1, b.2, 1) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13177,6 +15145,8 @@ vst3_s8_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13191,6 +15161,8 @@ vst3_s16_(a as _, b.0, b.1, b.2, 2) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13206,6 +15178,8 @@ vst3_s16_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13220,6 +15194,8 @@ vst3_s32_(a as _, b.0, b.1, b.2, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13235,6 +15211,8 @@ vst3_s32_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13249,6 +15227,8 @@ vst3q_s8_(a as _, b.0, b.1, b.2, 1) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13264,6 +15244,8 @@ vst3q_s8_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13278,6 +15260,8 @@ vst3q_s16_(a as _, b.0, b.1, b.2, 2) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13293,6 +15277,8 @@ vst3q_s16_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13307,6 +15293,8 @@ vst3q_s32_(a as _, b.0, b.1, b.2, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13322,6 +15310,8 @@ vst3q_s32_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13336,6 +15326,8 @@ vst3_s64_(a as _, b.0, b.1, b.2, 8) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13351,6 +15343,8 @@ vst3_s64_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13362,6 +15356,8 @@ pub unsafe fn vst3_u8(a: *mut u8, b: uint8x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13373,6 +15369,8 @@ pub unsafe fn vst3_u16(a: *mut u16, b: uint16x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13384,6 +15382,8 @@ pub unsafe fn vst3_u32(a: *mut u32, b: uint32x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13395,6 +15395,8 @@ pub unsafe fn vst3q_u8(a: *mut u8, b: uint8x16x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13406,6 +15408,8 @@ pub unsafe fn vst3q_u16(a: *mut u16, b: uint16x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13417,6 +15421,8 @@ pub unsafe fn vst3q_u32(a: *mut u32, b: uint32x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13428,6 +15434,8 @@ pub unsafe fn vst3_p8(a: *mut p8, b: poly8x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13439,6 +15447,8 @@ pub unsafe fn vst3_p16(a: *mut p16, b: poly16x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13450,6 +15460,8 @@ pub unsafe fn vst3q_p8(a: *mut p8, b: poly8x16x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13461,6 +15473,8 @@ pub unsafe fn vst3q_p16(a: *mut p16, b: poly16x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13472,6 +15486,8 @@ pub unsafe fn vst3_u64(a: *mut u64, b: uint64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -13483,6 +15499,8 @@ pub unsafe fn vst3_p64(a: *mut p64, b: poly64x1x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13497,6 +15515,8 @@ vst3_f32_(a as _, b.0, b.1, b.2, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13512,6 +15532,8 @@ vst3_f32_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13526,6 +15548,8 @@ vst3q_f32_(a as _, b.0, b.1, b.2, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13541,6 +15565,8 @@ vst3q_f32_(b.0, b.1, b.2, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13557,6 +15583,8 @@ vst3_lane_s8_(a as _, b.0, b.1, b.2, LANE, 1) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13574,6 +15602,8 @@ vst3_lane_s8_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13590,6 +15620,8 @@ vst3_lane_s16_(a as _, b.0, b.1, b.2, LANE, 2) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13607,6 +15639,8 @@ vst3_lane_s16_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13623,6 +15657,8 @@ vst3_lane_s32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13640,6 +15676,8 @@ vst3_lane_s32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13656,6 +15694,8 @@ vst3q_lane_s16_(a as _, b.0, b.1, b.2, LANE, 2) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13673,6 +15713,8 @@ vst3q_lane_s16_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13689,6 +15731,8 @@ vst3q_lane_s32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13706,6 +15750,8 @@ vst3q_lane_s32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13719,6 +15765,8 @@ pub unsafe fn vst3_lane_u8(a: *mut u8, b: uint8x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13732,6 +15780,8 @@ pub unsafe fn vst3_lane_u16(a: *mut u16, b: uint16x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13745,6 +15795,8 @@ pub unsafe fn vst3_lane_u32(a: *mut u32, b: uint32x2x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13758,6 +15810,8 @@ pub unsafe fn vst3q_lane_u16(a: *mut u16, b: uint16x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13771,6 +15825,8 @@ pub unsafe fn vst3q_lane_u32(a: *mut u32, b: uint32x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13784,6 +15840,8 @@ pub unsafe fn vst3_lane_p8(a: *mut p8, b: poly8x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13797,6 +15855,8 @@ pub unsafe fn vst3_lane_p16(a: *mut p16, b: poly16x4x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -13810,6 +15870,8 @@ pub unsafe fn vst3q_lane_p16(a: *mut p16, b: poly16x8x3_t) { } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13826,6 +15888,8 @@ vst3_lane_f32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13843,6 +15907,8 @@ vst3_lane_f32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13859,6 +15925,8 @@ vst3q_lane_f32_(a as _, b.0, b.1, b.2, LANE, 4) } /// Store multiple 3-element structures from three registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst3q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13876,6 +15944,8 @@ vst3q_lane_f32_(b.0, b.1, b.2, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13890,6 +15960,8 @@ vst4_s8_(a as _, b.0, b.1, b.2, b.3, 1) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13905,6 +15977,8 @@ vst4_s8_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13919,6 +15993,8 @@ vst4_s16_(a as _, b.0, b.1, b.2, b.3, 2) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13934,6 +16010,8 @@ vst4_s16_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13948,6 +16026,8 @@ vst4_s32_(a as _, b.0, b.1, b.2, b.3, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13963,6 +16043,8 @@ vst4_s32_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -13977,6 +16059,8 @@ vst4q_s8_(a as _, b.0, b.1, b.2, b.3, 1) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -13992,6 +16076,8 @@ vst4q_s8_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14006,6 +16092,8 @@ vst4q_s16_(a as _, b.0, b.1, b.2, b.3, 2) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14021,6 +16109,8 @@ vst4q_s16_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14035,6 +16125,8 @@ vst4q_s32_(a as _, b.0, b.1, b.2, b.3, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14050,6 +16142,8 @@ vst4q_s32_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14064,6 +16158,8 @@ vst4_s64_(a as _, b.0, b.1, b.2, b.3, 8) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14079,6 +16175,8 @@ vst4_s64_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14090,6 +16188,8 @@ pub unsafe fn vst4_u8(a: *mut u8, b: uint8x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14101,6 +16201,8 @@ pub unsafe fn vst4_u16(a: *mut u16, b: uint16x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14112,6 +16214,8 @@ pub unsafe fn vst4_u32(a: *mut u32, b: uint32x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14123,6 +16227,8 @@ pub unsafe fn vst4q_u8(a: *mut u8, b: uint8x16x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14134,6 +16240,8 @@ pub unsafe fn vst4q_u16(a: *mut u16, b: uint16x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14145,6 +16253,8 @@ pub unsafe fn vst4q_u32(a: *mut u32, b: uint32x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14156,6 +16266,8 @@ pub unsafe fn vst4_p8(a: *mut p8, b: poly8x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14167,6 +16279,8 @@ pub unsafe fn vst4_p16(a: *mut p16, b: poly16x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14178,6 +16292,8 @@ pub unsafe fn vst4q_p8(a: *mut p8, b: poly8x16x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14189,6 +16305,8 @@ pub unsafe fn vst4q_p16(a: *mut p16, b: poly16x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14200,6 +16318,8 @@ pub unsafe fn vst4_u64(a: *mut u64, b: uint64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -14211,6 +16331,8 @@ pub unsafe fn vst4_p64(a: *mut p64, b: poly64x1x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14225,6 +16347,8 @@ vst4_f32_(a as _, b.0, b.1, b.2, b.3, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14240,6 +16364,8 @@ vst4_f32_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14254,6 +16380,8 @@ vst4q_f32_(a as _, b.0, b.1, b.2, b.3, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14269,6 +16397,8 @@ vst4q_f32_(b.0, b.1, b.2, b.3, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14285,6 +16415,8 @@ vst4_lane_s8_(a as _, b.0, b.1, b.2, b.3, LANE, 1) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14302,6 +16434,8 @@ vst4_lane_s8_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14318,6 +16452,8 @@ vst4_lane_s16_(a as _, b.0, b.1, b.2, b.3, LANE, 2) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14335,6 +16471,8 @@ vst4_lane_s16_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14351,6 +16489,8 @@ vst4_lane_s32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14368,6 +16508,8 @@ vst4_lane_s32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14384,6 +16526,8 @@ vst4q_lane_s16_(a as _, b.0, b.1, b.2, b.3, LANE, 2) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14401,6 +16545,8 @@ vst4q_lane_s16_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14417,6 +16563,8 @@ vst4q_lane_s32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14434,6 +16582,8 @@ vst4q_lane_s32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14447,6 +16597,8 @@ pub unsafe fn vst4_lane_u8(a: *mut u8, b: uint8x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14460,6 +16612,8 @@ pub unsafe fn vst4_lane_u16(a: *mut u16, b: uint16x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14473,6 +16627,8 @@ pub unsafe fn vst4_lane_u32(a: *mut u32, b: uint32x2x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14486,6 +16642,8 @@ pub unsafe fn vst4q_lane_u16(a: *mut u16, b: uint16x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14499,6 +16657,8 @@ pub unsafe fn vst4q_lane_u32(a: *mut u32, b: uint32x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14512,6 +16672,8 @@ pub unsafe fn vst4_lane_p8(a: *mut p8, b: poly8x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14525,6 +16687,8 @@ pub unsafe fn vst4_lane_p16(a: *mut p16, b: poly16x4x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14538,6 +16702,8 @@ pub unsafe fn vst4q_lane_p16(a: *mut p16, b: poly16x8x4_t) { } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14554,6 +16720,8 @@ vst4_lane_f32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14571,6 +16739,8 @@ vst4_lane_f32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_f32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -14587,6 +16757,8 @@ vst4q_lane_f32_(a as _, b.0, b.1, b.2, b.3, LANE, 4) } /// Store multiple 4-element structures from four registers +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vst4q_lane_f32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -14604,6 +16776,8 @@ vst4q_lane_f32_(b.0, b.1, b.2, b.3, LANE as i64, a as _) } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14615,6 +16789,8 @@ pub unsafe fn vmul_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14626,6 +16802,8 @@ pub unsafe fn vmulq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14637,6 +16815,8 @@ pub unsafe fn vmul_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14648,6 +16828,8 @@ pub unsafe fn vmulq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14659,6 +16841,8 @@ pub unsafe fn vmul_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14670,6 +16854,8 @@ pub unsafe fn vmulq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14681,6 +16867,8 @@ pub unsafe fn vmul_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14692,6 +16880,8 @@ pub unsafe fn vmulq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14703,6 +16893,8 @@ pub unsafe fn vmul_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14714,6 +16906,8 @@ pub unsafe fn vmulq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14725,6 +16919,8 @@ pub unsafe fn vmul_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14736,6 +16932,8 @@ pub unsafe fn vmulq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Polynomial multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14753,6 +16951,8 @@ vmul_p8_(a, b) } /// Polynomial multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14770,6 +16970,8 @@ vmulq_p8_(a, b) } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14781,6 +16983,8 @@ pub unsafe fn vmul_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14792,6 +16996,8 @@ pub unsafe fn vmulq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14803,6 +17009,8 @@ pub unsafe fn vmul_n_s16(a: int16x4_t, b: i16) -> int16x4_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14814,6 +17022,8 @@ pub unsafe fn vmulq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14825,6 +17035,8 @@ pub unsafe fn vmul_n_s32(a: int32x2_t, b: i32) -> int32x2_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14836,6 +17048,8 @@ pub unsafe fn vmulq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14847,6 +17061,8 @@ pub unsafe fn vmul_n_u16(a: uint16x4_t, b: u16) -> uint16x4_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14858,6 +17074,8 @@ pub unsafe fn vmulq_n_u16(a: uint16x8_t, b: u16) -> uint16x8_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14869,6 +17087,8 @@ pub unsafe fn vmul_n_u32(a: uint32x2_t, b: u32) -> uint32x2_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14880,6 +17100,8 @@ pub unsafe fn vmulq_n_u32(a: uint32x4_t, b: u32) -> uint32x4_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14891,6 +17113,8 @@ pub unsafe fn vmul_n_f32(a: float32x2_t, b: f32) -> float32x2_t { } /// Vector multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14902,6 +17126,8 @@ pub unsafe fn vmulq_n_f32(a: float32x4_t, b: f32) -> float32x4_t { } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14915,6 +17141,8 @@ pub unsafe fn vmul_lane_s16(a: int16x4_t, b: int16x4_t) -> int1 } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14928,6 +17156,8 @@ pub unsafe fn vmul_laneq_s16(a: int16x4_t, b: int16x8_t) -> int } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14941,6 +17171,8 @@ pub unsafe fn vmulq_lane_s16(a: int16x8_t, b: int16x4_t) -> int } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14954,6 +17186,8 @@ pub unsafe fn vmulq_laneq_s16(a: int16x8_t, b: int16x8_t) -> in } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14967,6 +17201,8 @@ pub unsafe fn vmul_lane_s32(a: int32x2_t, b: int32x2_t) -> int3 } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14980,6 +17216,8 @@ pub unsafe fn vmul_laneq_s32(a: int32x2_t, b: int32x4_t) -> int } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -14993,6 +17231,8 @@ pub unsafe fn vmulq_lane_s32(a: int32x4_t, b: int32x2_t) -> int } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15006,6 +17246,8 @@ pub unsafe fn vmulq_laneq_s32(a: int32x4_t, b: int32x4_t) -> in } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15019,6 +17261,8 @@ pub unsafe fn vmul_lane_u16(a: uint16x4_t, b: uint16x4_t) -> ui } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15032,6 +17276,8 @@ pub unsafe fn vmul_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> u } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15045,6 +17291,8 @@ pub unsafe fn vmulq_lane_u16(a: uint16x8_t, b: uint16x4_t) -> u } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15058,6 +17306,8 @@ pub unsafe fn vmulq_laneq_u16(a: uint16x8_t, b: uint16x8_t) -> } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15071,6 +17321,8 @@ pub unsafe fn vmul_lane_u32(a: uint32x2_t, b: uint32x2_t) -> ui } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15084,6 +17336,8 @@ pub unsafe fn vmul_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> u } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15097,6 +17351,8 @@ pub unsafe fn vmulq_lane_u32(a: uint32x4_t, b: uint32x2_t) -> u } /// Multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15110,6 +17366,8 @@ pub unsafe fn vmulq_laneq_u32(a: uint32x4_t, b: uint32x4_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15123,6 +17381,8 @@ pub unsafe fn vmul_lane_f32(a: float32x2_t, b: float32x2_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmul_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15136,6 +17396,8 @@ pub unsafe fn vmul_laneq_f32(a: float32x2_t, b: float32x4_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15149,6 +17411,8 @@ pub unsafe fn vmulq_lane_f32(a: float32x4_t, b: float32x2_t) -> } /// Floating-point multiply +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmulq_laneq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15162,6 +17426,8 @@ pub unsafe fn vmulq_laneq_f32(a: float32x4_t, b: float32x4_t) - } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15179,6 +17445,8 @@ vmull_s8_(a, b) } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15196,6 +17464,8 @@ vmull_s16_(a, b) } /// Signed multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15213,6 +17483,8 @@ vmull_s32_(a, b) } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15230,6 +17502,8 @@ vmull_u8_(a, b) } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15247,6 +17521,8 @@ vmull_u16_(a, b) } /// Unsigned multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15264,6 +17540,8 @@ vmull_u32_(a, b) } /// Polynomial multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15281,6 +17559,8 @@ vmull_p8_(a, b) } /// Vector long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15292,6 +17572,8 @@ pub unsafe fn vmull_n_s16(a: int16x4_t, b: i16) -> int32x4_t { } /// Vector long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15303,6 +17585,8 @@ pub unsafe fn vmull_n_s32(a: int32x2_t, b: i32) -> int64x2_t { } /// Vector long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15314,6 +17598,8 @@ pub unsafe fn vmull_n_u16(a: uint16x4_t, b: u16) -> uint32x4_t { } /// Vector long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15325,6 +17611,8 @@ pub unsafe fn vmull_n_u32(a: uint32x2_t, b: u32) -> uint64x2_t { } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15338,6 +17626,8 @@ pub unsafe fn vmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15351,6 +17641,8 @@ pub unsafe fn vmull_laneq_s16(a: int16x4_t, b: int16x8_t) -> in } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15364,6 +17656,8 @@ pub unsafe fn vmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15377,6 +17671,8 @@ pub unsafe fn vmull_laneq_s32(a: int32x2_t, b: int32x4_t) -> in } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15390,6 +17686,8 @@ pub unsafe fn vmull_lane_u16(a: uint16x4_t, b: uint16x4_t) -> u } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_laneq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15403,6 +17701,8 @@ pub unsafe fn vmull_laneq_u16(a: uint16x4_t, b: uint16x8_t) -> } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15416,6 +17716,8 @@ pub unsafe fn vmull_lane_u32(a: uint32x2_t, b: uint32x2_t) -> u } /// Vector long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmull_laneq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15429,6 +17731,8 @@ pub unsafe fn vmull_laneq_u32(a: uint32x2_t, b: uint32x4_t) -> } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15446,6 +17750,8 @@ vfma_f32_(b, c, a) } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15463,6 +17769,8 @@ vfmaq_f32_(b, c, a) } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfma_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15474,6 +17782,8 @@ pub unsafe fn vfma_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t } /// Floating-point fused Multiply-Add to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmaq_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15485,6 +17795,8 @@ pub unsafe fn vfmaq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t } /// Floating-point fused multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15497,6 +17809,8 @@ pub unsafe fn vfms_f32(a: float32x2_t, b: float32x2_t, c: float32x2_t) -> float3 } /// Floating-point fused multiply-subtract from accumulator +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15509,6 +17823,8 @@ pub unsafe fn vfmsq_f32(a: float32x4_t, b: float32x4_t, c: float32x4_t) -> float } /// Floating-point fused Multiply-subtract to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfms_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15520,6 +17836,8 @@ pub unsafe fn vfms_n_f32(a: float32x2_t, b: float32x2_t, c: f32) -> float32x2_t } /// Floating-point fused Multiply-subtract to accumulator(vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmsq_n_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "vfp4"))] @@ -15531,6 +17849,8 @@ pub unsafe fn vfmsq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15542,6 +17862,8 @@ pub unsafe fn vsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15553,6 +17875,8 @@ pub unsafe fn vsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15564,6 +17888,8 @@ pub unsafe fn vsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15575,6 +17901,8 @@ pub unsafe fn vsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15586,6 +17914,8 @@ pub unsafe fn vsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15597,6 +17927,8 @@ pub unsafe fn vsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15608,6 +17940,8 @@ pub unsafe fn vsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15619,6 +17953,8 @@ pub unsafe fn vsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15630,6 +17966,8 @@ pub unsafe fn vsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15641,6 +17979,8 @@ pub unsafe fn vsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15652,6 +17992,8 @@ pub unsafe fn vsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15663,6 +18005,8 @@ pub unsafe fn vsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15674,6 +18018,8 @@ pub unsafe fn vsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15685,6 +18031,8 @@ pub unsafe fn vsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15696,6 +18044,8 @@ pub unsafe fn vsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15707,6 +18057,8 @@ pub unsafe fn vsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsub_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15718,6 +18070,8 @@ pub unsafe fn vsub_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { } /// Subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15729,6 +18083,8 @@ pub unsafe fn vsubq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vadd_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15740,6 +18096,8 @@ pub unsafe fn vadd_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vadd_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15751,6 +18109,8 @@ pub unsafe fn vadd_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15762,6 +18122,8 @@ pub unsafe fn vaddq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15773,6 +18135,8 @@ pub unsafe fn vaddq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vadd_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15784,6 +18148,8 @@ pub unsafe fn vadd_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x1_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddq_p64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15795,6 +18161,8 @@ pub unsafe fn vaddq_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { } /// Bitwise exclusive OR +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vaddq_p128) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15806,6 +18174,8 @@ pub unsafe fn vaddq_p128(a: p128, b: p128) -> p128 { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15818,6 +18188,8 @@ pub unsafe fn vsubhn_s16(a: int16x8_t, b: int16x8_t) -> int8x8_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15830,6 +18202,8 @@ pub unsafe fn vsubhn_s32(a: int32x4_t, b: int32x4_t) -> int16x4_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15842,6 +18216,8 @@ pub unsafe fn vsubhn_s64(a: int64x2_t, b: int64x2_t) -> int32x2_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15854,6 +18230,8 @@ pub unsafe fn vsubhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15866,6 +18244,8 @@ pub unsafe fn vsubhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15878,6 +18258,8 @@ pub unsafe fn vsubhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15890,6 +18272,8 @@ pub unsafe fn vsubhn_high_s16(a: int8x8_t, b: int16x8_t, c: int16x8_t) -> int8x1 } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15902,6 +18286,8 @@ pub unsafe fn vsubhn_high_s32(a: int16x4_t, b: int32x4_t, c: int32x4_t) -> int16 } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15914,6 +18300,8 @@ pub unsafe fn vsubhn_high_s64(a: int32x2_t, b: int64x2_t, c: int64x2_t) -> int32 } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15926,6 +18314,8 @@ pub unsafe fn vsubhn_high_u16(a: uint8x8_t, b: uint16x8_t, c: uint16x8_t) -> uin } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15938,6 +18328,8 @@ pub unsafe fn vsubhn_high_u32(a: uint16x4_t, b: uint32x4_t, c: uint32x4_t) -> ui } /// Subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubhn_high_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15950,6 +18342,8 @@ pub unsafe fn vsubhn_high_u64(a: uint32x2_t, b: uint64x2_t, c: uint64x2_t) -> ui } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15967,6 +18361,8 @@ vhsub_u8_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -15984,6 +18380,8 @@ vhsubq_u8_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16001,6 +18399,8 @@ vhsub_u16_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16018,6 +18418,8 @@ vhsubq_u16_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16035,6 +18437,8 @@ vhsub_u32_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16052,6 +18456,8 @@ vhsubq_u32_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16069,6 +18475,8 @@ vhsub_s8_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16086,6 +18494,8 @@ vhsubq_s8_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16103,6 +18513,8 @@ vhsub_s16_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16120,6 +18532,8 @@ vhsubq_s16_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsub_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16137,6 +18551,8 @@ vhsub_s32_(a, b) } /// Signed halving subtract +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vhsubq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16154,6 +18570,8 @@ vhsubq_s32_(a, b) } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16165,6 +18583,8 @@ pub unsafe fn vsubw_s8(a: int16x8_t, b: int8x8_t) -> int16x8_t { } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16176,6 +18596,8 @@ pub unsafe fn vsubw_s16(a: int32x4_t, b: int16x4_t) -> int32x4_t { } /// Signed Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16187,6 +18609,8 @@ pub unsafe fn vsubw_s32(a: int64x2_t, b: int32x2_t) -> int64x2_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16198,6 +18622,8 @@ pub unsafe fn vsubw_u8(a: uint16x8_t, b: uint8x8_t) -> uint16x8_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16209,6 +18635,8 @@ pub unsafe fn vsubw_u16(a: uint32x4_t, b: uint16x4_t) -> uint32x4_t { } /// Unsigned Subtract Wide +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubw_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16220,6 +18648,8 @@ pub unsafe fn vsubw_u32(a: uint64x2_t, b: uint32x2_t) -> uint64x2_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16233,6 +18663,8 @@ pub unsafe fn vsubl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16246,6 +18678,8 @@ pub unsafe fn vsubl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { } /// Signed Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16259,6 +18693,8 @@ pub unsafe fn vsubl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16272,6 +18708,8 @@ pub unsafe fn vsubl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16285,6 +18723,8 @@ pub unsafe fn vsubl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { } /// Unsigned Subtract Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsubl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16298,6 +18738,8 @@ pub unsafe fn vsubl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16315,6 +18757,8 @@ vmax_s8_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16332,6 +18776,8 @@ vmaxq_s8_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16349,6 +18795,8 @@ vmax_s16_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16366,6 +18814,8 @@ vmaxq_s16_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16383,6 +18833,8 @@ vmax_s32_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16400,6 +18852,8 @@ vmaxq_s32_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16417,6 +18871,8 @@ vmax_u8_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16434,6 +18890,8 @@ vmaxq_u8_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16451,6 +18909,8 @@ vmax_u16_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16468,6 +18928,8 @@ vmaxq_u16_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16485,6 +18947,8 @@ vmax_u32_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16502,6 +18966,8 @@ vmaxq_u32_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmax_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16519,6 +18985,8 @@ vmax_f32_(a, b) } /// Maximum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16536,6 +19004,8 @@ vmaxq_f32_(a, b) } /// Floating-point Maximum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnm_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -16553,6 +19023,8 @@ vmaxnm_f32_(a, b) } /// Floating-point Maximum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmaxnmq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -16570,6 +19042,8 @@ vmaxnmq_f32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16587,6 +19061,8 @@ vmin_s8_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16604,6 +19080,8 @@ vminq_s8_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16621,6 +19099,8 @@ vmin_s16_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16638,6 +19118,8 @@ vminq_s16_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16655,6 +19137,8 @@ vmin_s32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16672,6 +19156,8 @@ vminq_s32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16689,6 +19175,8 @@ vmin_u8_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16706,6 +19194,8 @@ vminq_u8_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16723,6 +19213,8 @@ vmin_u16_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16740,6 +19232,8 @@ vminq_u16_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16757,6 +19251,8 @@ vmin_u32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16774,6 +19270,8 @@ vminq_u32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmin_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16791,6 +19289,8 @@ vmin_f32_(a, b) } /// Minimum (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16808,6 +19308,8 @@ vminq_f32_(a, b) } /// Floating-point Minimum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnm_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -16825,6 +19327,8 @@ vminnm_f32_(a, b) } /// Floating-point Minimum Number (vector) +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vminnmq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "fp-armv8,v8"))] @@ -16842,6 +19346,8 @@ vminnmq_f32_(a, b) } /// Floating-point add pairwise +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vpadd_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16859,6 +19365,8 @@ vpadd_f32_(a, b) } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16876,6 +19384,8 @@ vqdmull_s16_(a, b) } /// Signed saturating doubling multiply long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16893,6 +19403,8 @@ vqdmull_s32_(a, b) } /// Vector saturating doubling long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16904,6 +19416,8 @@ pub unsafe fn vqdmull_n_s16(a: int16x4_t, b: i16) -> int32x4_t { } /// Vector saturating doubling long multiply with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16915,6 +19429,8 @@ pub unsafe fn vqdmull_n_s32(a: int32x2_t, b: i32) -> int64x2_t { } /// Vector saturating doubling long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16929,6 +19445,8 @@ pub unsafe fn vqdmull_lane_s16(a: int16x4_t, b: int16x4_t) -> int3 } /// Vector saturating doubling long multiply by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmull_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16943,6 +19461,8 @@ pub unsafe fn vqdmull_lane_s32(a: int32x2_t, b: int32x2_t) -> int6 } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16954,6 +19474,8 @@ pub unsafe fn vqdmlal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t } /// Signed saturating doubling multiply-add long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16965,6 +19487,8 @@ pub unsafe fn vqdmlal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16976,6 +19500,8 @@ pub unsafe fn vqdmlal_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -16987,6 +19513,8 @@ pub unsafe fn vqdmlal_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17000,6 +19528,8 @@ pub unsafe fn vqdmlal_lane_s16(a: int32x4_t, b: int16x4_t, c: int1 } /// Vector widening saturating doubling multiply accumulate with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17013,6 +19543,8 @@ pub unsafe fn vqdmlal_lane_s32(a: int64x2_t, b: int32x2_t, c: int3 } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17024,6 +19556,8 @@ pub unsafe fn vqdmlsl_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t } /// Signed saturating doubling multiply-subtract long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17035,6 +19569,8 @@ pub unsafe fn vqdmlsl_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17046,6 +19582,8 @@ pub unsafe fn vqdmlsl_n_s16(a: int32x4_t, b: int16x4_t, c: i16) -> int32x4_t { } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17057,6 +19595,8 @@ pub unsafe fn vqdmlsl_n_s32(a: int64x2_t, b: int32x2_t, c: i32) -> int64x2_t { } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17070,6 +19610,8 @@ pub unsafe fn vqdmlsl_lane_s16(a: int32x4_t, b: int16x4_t, c: int1 } /// Vector widening saturating doubling multiply subtract with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlsl_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17083,6 +19625,8 @@ pub unsafe fn vqdmlsl_lane_s32(a: int64x2_t, b: int32x2_t, c: int3 } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17100,6 +19644,8 @@ vqdmulh_s16_(a, b) } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17117,6 +19663,8 @@ vqdmulhq_s16_(a, b) } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17134,6 +19682,8 @@ vqdmulh_s32_(a, b) } /// Signed saturating doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17151,6 +19701,8 @@ vqdmulhq_s32_(a, b) } /// Vector saturating doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17163,6 +19715,8 @@ pub unsafe fn vqdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { } /// Vector saturating doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17175,6 +19729,8 @@ pub unsafe fn vqdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { } /// Vector saturating doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17187,6 +19743,8 @@ pub unsafe fn vqdmulhq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { } /// Vector saturating doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17199,6 +19757,8 @@ pub unsafe fn vqdmulhq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17212,6 +19772,8 @@ pub unsafe fn vqdmulhq_laneq_s16(a: int16x8_t, b: int16x8_t) -> } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17225,6 +19787,8 @@ pub unsafe fn vqdmulh_laneq_s16(a: int16x4_t, b: int16x8_t) -> } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulhq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17238,6 +19802,8 @@ pub unsafe fn vqdmulhq_laneq_s32(a: int32x4_t, b: int32x4_t) -> } /// Vector saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmulh_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17251,6 +19817,8 @@ pub unsafe fn vqdmulh_laneq_s32(a: int32x2_t, b: int32x4_t) -> } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17268,6 +19836,8 @@ vqmovn_s16_(a) } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17285,6 +19855,8 @@ vqmovn_s32_(a) } /// Signed saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17302,6 +19874,8 @@ vqmovn_s64_(a) } /// Unsigned saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17319,6 +19893,8 @@ vqmovn_u16_(a) } /// Unsigned saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17336,6 +19912,8 @@ vqmovn_u32_(a) } /// Unsigned saturating extract narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovn_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17353,6 +19931,8 @@ vqmovn_u64_(a) } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17370,6 +19950,8 @@ vqmovun_s16_(a) } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17387,6 +19969,8 @@ vqmovun_s32_(a) } /// Signed saturating extract unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqmovun_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17404,6 +19988,8 @@ vqmovun_s64_(a) } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17421,6 +20007,8 @@ vqrdmulh_s16_(a, b) } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17438,6 +20026,8 @@ vqrdmulhq_s16_(a, b) } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17455,6 +20045,8 @@ vqrdmulh_s32_(a, b) } /// Signed saturating rounding doubling multiply returning high half +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17472,6 +20064,8 @@ vqrdmulhq_s32_(a, b) } /// Vector saturating rounding doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17483,6 +20077,8 @@ pub unsafe fn vqrdmulh_n_s16(a: int16x4_t, b: i16) -> int16x4_t { } /// Vector saturating rounding doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17494,6 +20090,8 @@ pub unsafe fn vqrdmulhq_n_s16(a: int16x8_t, b: i16) -> int16x8_t { } /// Vector saturating rounding doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17505,6 +20103,8 @@ pub unsafe fn vqrdmulh_n_s32(a: int32x2_t, b: i32) -> int32x2_t { } /// Vector saturating rounding doubling multiply high with scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17516,6 +20116,8 @@ pub unsafe fn vqrdmulhq_n_s32(a: int32x4_t, b: i32) -> int32x4_t { } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17530,6 +20132,8 @@ pub unsafe fn vqrdmulh_lane_s16(a: int16x4_t, b: int16x4_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17544,6 +20148,8 @@ pub unsafe fn vqrdmulh_laneq_s16(a: int16x4_t, b: int16x8_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17558,6 +20164,8 @@ pub unsafe fn vqrdmulhq_lane_s16(a: int16x8_t, b: int16x4_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_laneq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17572,6 +20180,8 @@ pub unsafe fn vqrdmulhq_laneq_s16(a: int16x8_t, b: int16x8_t) - } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17586,6 +20196,8 @@ pub unsafe fn vqrdmulh_lane_s32(a: int32x2_t, b: int32x2_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulh_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17600,6 +20212,8 @@ pub unsafe fn vqrdmulh_laneq_s32(a: int32x2_t, b: int32x4_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17614,6 +20228,8 @@ pub unsafe fn vqrdmulhq_lane_s32(a: int32x4_t, b: int32x2_t) -> } /// Vector rounding saturating doubling multiply high by scalar +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrdmulhq_laneq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17628,6 +20244,8 @@ pub unsafe fn vqrdmulhq_laneq_s32(a: int32x4_t, b: int32x4_t) - } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17645,6 +20263,8 @@ vqrshl_s8_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17662,6 +20282,8 @@ vqrshlq_s8_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17679,6 +20301,8 @@ vqrshl_s16_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17696,6 +20320,8 @@ vqrshlq_s16_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17713,6 +20339,8 @@ vqrshl_s32_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17730,6 +20358,8 @@ vqrshlq_s32_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17747,6 +20377,8 @@ vqrshl_s64_(a, b) } /// Signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17764,6 +20396,8 @@ vqrshlq_s64_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17781,6 +20415,8 @@ vqrshl_u8_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17798,6 +20434,8 @@ vqrshlq_u8_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17815,6 +20453,8 @@ vqrshl_u16_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17832,6 +20472,8 @@ vqrshlq_u16_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17849,6 +20491,8 @@ vqrshl_u32_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17866,6 +20510,8 @@ vqrshlq_u32_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshl_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17883,6 +20529,8 @@ vqrshl_u64_(a, b) } /// Unsigned signed saturating rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshlq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -17900,6 +20548,8 @@ vqrshlq_u64_(a, b) } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -17916,6 +20566,8 @@ vqrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i1 } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -17933,6 +20585,8 @@ vqrshrn_n_s16_(a, N) } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -17949,6 +20603,8 @@ vqrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -17966,6 +20622,8 @@ vqrshrn_n_s32_(a, N) } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -17982,6 +20640,8 @@ vqrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } /// Signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -17999,6 +20659,8 @@ vqrshrn_n_s64_(a, N) } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18015,6 +20677,8 @@ vqrshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18032,6 +20696,8 @@ vqrshrn_n_u16_(a, N) } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18048,6 +20714,8 @@ vqrshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18065,6 +20733,8 @@ vqrshrn_n_u32_(a, N) } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18081,6 +20751,8 @@ vqrshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) } /// Unsigned signed saturating rounded shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrn_n_u64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18098,6 +20770,8 @@ vqrshrn_n_u64_(a, N) } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18114,6 +20788,8 @@ vqrshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18131,6 +20807,8 @@ vqrshrun_n_s16_(a, N) } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18147,6 +20825,8 @@ vqrshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18164,6 +20844,8 @@ vqrshrun_n_s32_(a, N) } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18180,6 +20862,8 @@ vqrshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } /// Signed saturating rounded shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqrshrun_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18197,6 +20881,8 @@ vqrshrun_n_s64_(a, N) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18214,6 +20900,8 @@ vqshl_s8_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18231,6 +20919,8 @@ vqshlq_s8_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18248,6 +20938,8 @@ vqshl_s16_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18265,6 +20957,8 @@ vqshlq_s16_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18282,6 +20976,8 @@ vqshl_s32_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18299,6 +20995,8 @@ vqshlq_s32_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18316,6 +21014,8 @@ vqshl_s64_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18333,6 +21033,8 @@ vqshlq_s64_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18350,6 +21052,8 @@ vqshl_u8_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18367,6 +21071,8 @@ vqshlq_u8_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18384,6 +21090,8 @@ vqshl_u16_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18401,6 +21109,8 @@ vqshlq_u16_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18418,6 +21128,8 @@ vqshl_u32_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18435,6 +21147,8 @@ vqshlq_u32_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18452,6 +21166,8 @@ vqshl_u64_(a, b) } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18469,6 +21185,8 @@ vqshlq_u64_(a, b) } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18482,6 +21200,8 @@ pub unsafe fn vqshl_n_s8(a: int8x8_t) -> int8x8_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18495,6 +21215,8 @@ pub unsafe fn vqshlq_n_s8(a: int8x16_t) -> int8x16_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18508,6 +21230,8 @@ pub unsafe fn vqshl_n_s16(a: int16x4_t) -> int16x4_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18521,6 +21245,8 @@ pub unsafe fn vqshlq_n_s16(a: int16x8_t) -> int16x8_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18534,6 +21260,8 @@ pub unsafe fn vqshl_n_s32(a: int32x2_t) -> int32x2_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18547,6 +21275,8 @@ pub unsafe fn vqshlq_n_s32(a: int32x4_t) -> int32x4_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18560,6 +21290,8 @@ pub unsafe fn vqshl_n_s64(a: int64x1_t) -> int64x1_t { } /// Signed saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18573,6 +21305,8 @@ pub unsafe fn vqshlq_n_s64(a: int64x2_t) -> int64x2_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18586,6 +21320,8 @@ pub unsafe fn vqshl_n_u8(a: uint8x8_t) -> uint8x8_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18599,6 +21335,8 @@ pub unsafe fn vqshlq_n_u8(a: uint8x16_t) -> uint8x16_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18612,6 +21350,8 @@ pub unsafe fn vqshl_n_u16(a: uint16x4_t) -> uint16x4_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18625,6 +21365,8 @@ pub unsafe fn vqshlq_n_u16(a: uint16x8_t) -> uint16x8_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18638,6 +21380,8 @@ pub unsafe fn vqshl_n_u32(a: uint32x2_t) -> uint32x2_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18651,6 +21395,8 @@ pub unsafe fn vqshlq_n_u32(a: uint32x4_t) -> uint32x4_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshl_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18664,6 +21410,8 @@ pub unsafe fn vqshl_n_u64(a: uint64x1_t) -> uint64x1_t { } /// Unsigned saturating shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -18677,6 +21425,8 @@ pub unsafe fn vqshlq_n_u64(a: uint64x2_t) -> uint64x2_t { } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18693,6 +21443,8 @@ vqshlu_n_s8_(a, int8x8_t(N as i8, N as i8, N as i8, N as i8, N as i8, N as i8, N } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18710,6 +21462,8 @@ vqshlu_n_s8_(a, int8x8_t(N as i8, N as i8, N as i8, N as i8, N as i8, N as i8, N } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18726,6 +21480,8 @@ vqshlu_n_s16_(a, int16x4_t(N as i16, N as i16, N as i16, N as i16)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18743,6 +21499,8 @@ vqshlu_n_s16_(a, int16x4_t(N as i16, N as i16, N as i16, N as i16)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18759,6 +21517,8 @@ vqshlu_n_s32_(a, int32x2_t(N as i32, N as i32)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18776,6 +21536,8 @@ vqshlu_n_s32_(a, int32x2_t(N as i32, N as i32)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18792,6 +21554,8 @@ vqshlu_n_s64_(a, int64x1_t(N as i64)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshlu_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18809,6 +21573,8 @@ vqshlu_n_s64_(a, int64x1_t(N as i64)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s8) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18825,6 +21591,8 @@ vqshluq_n_s8_(a, int8x16_t(N as i8, N as i8, N as i8, N as i8, N as i8, N as i8, } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s8) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18842,6 +21610,8 @@ vqshluq_n_s8_(a, int8x16_t(N as i8, N as i8, N as i8, N as i8, N as i8, N as i8, } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18858,6 +21628,8 @@ vqshluq_n_s16_(a, int16x8_t(N as i16, N as i16, N as i16, N as i16, N as i16, N } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18875,6 +21647,8 @@ vqshluq_n_s16_(a, int16x8_t(N as i16, N as i16, N as i16, N as i16, N as i16, N } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18891,6 +21665,8 @@ vqshluq_n_s32_(a, int32x4_t(N as i32, N as i32, N as i32, N as i32)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18908,6 +21684,8 @@ vqshluq_n_s32_(a, int32x4_t(N as i32, N as i32, N as i32, N as i32)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18924,6 +21702,8 @@ vqshluq_n_s64_(a, int64x2_t(N as i64, N as i64)) } /// Signed saturating shift left unsigned +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshluq_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18941,6 +21721,8 @@ vqshluq_n_s64_(a, int64x2_t(N as i64, N as i64)) } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18957,6 +21739,8 @@ vqshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16 } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -18974,6 +21758,8 @@ vqshrn_n_s16_(a, N) } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -18990,6 +21776,8 @@ vqshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19007,6 +21795,8 @@ vqshrn_n_s32_(a, N) } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19023,6 +21813,8 @@ vqshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } /// Signed saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19040,6 +21832,8 @@ vqshrn_n_s64_(a, N) } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19056,6 +21850,8 @@ vqshrn_n_u16_(a, uint16x8_t(-N as u16, -N as u16, -N as u16, -N as u16, -N as u1 } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19073,6 +21869,8 @@ vqshrn_n_u16_(a, N) } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19089,6 +21887,8 @@ vqshrn_n_u32_(a, uint32x4_t(-N as u32, -N as u32, -N as u32, -N as u32)) } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19106,6 +21906,8 @@ vqshrn_n_u32_(a, N) } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19122,6 +21924,8 @@ vqshrn_n_u64_(a, uint64x2_t(-N as u64, -N as u64)) } /// Unsigned saturating shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrn_n_u64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19139,6 +21943,8 @@ vqshrn_n_u64_(a, N) } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19155,6 +21961,8 @@ vqshrun_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i1 } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19172,6 +21980,8 @@ vqshrun_n_s16_(a, N) } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19188,6 +21998,8 @@ vqshrun_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19205,6 +22017,8 @@ vqshrun_n_s32_(a, N) } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -19221,6 +22035,8 @@ vqshrun_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } /// Signed saturating shift right unsigned narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqshrun_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -19238,6 +22054,8 @@ vqshrun_n_s64_(a, N) } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrte_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19255,6 +22073,8 @@ vrsqrte_f32_(a) } /// Reciprocal square-root estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrteq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19272,6 +22092,8 @@ vrsqrteq_f32_(a) } /// Unsigned reciprocal square root estimate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrte_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19289,6 +22111,8 @@ vrsqrte_u32_(a) } /// Unsigned reciprocal square root estimate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrteq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19306,6 +22130,8 @@ vrsqrteq_u32_(a) } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrts_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19323,6 +22149,8 @@ vrsqrts_f32_(a, b) } /// Floating-point reciprocal square root step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsqrtsq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19340,6 +22168,8 @@ vrsqrtsq_f32_(a, b) } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpe_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19357,6 +22187,8 @@ vrecpe_f32_(a) } /// Reciprocal estimate. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpeq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19374,6 +22206,8 @@ vrecpeq_f32_(a) } /// Unsigned reciprocal estimate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpe_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19391,6 +22225,8 @@ vrecpe_u32_(a) } /// Unsigned reciprocal estimate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpeq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19408,6 +22244,8 @@ vrecpeq_u32_(a) } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecps_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19425,6 +22263,8 @@ vrecps_f32_(a, b) } /// Floating-point reciprocal step +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrecpsq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19442,6 +22282,8 @@ vrecpsq_f32_(a, b) } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19453,6 +22295,8 @@ pub unsafe fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19464,6 +22308,8 @@ pub unsafe fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19475,6 +22321,8 @@ pub unsafe fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19486,6 +22334,8 @@ pub unsafe fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19497,6 +22347,8 @@ pub unsafe fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19508,6 +22360,8 @@ pub unsafe fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19519,6 +22373,8 @@ pub unsafe fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19530,6 +22386,8 @@ pub unsafe fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19541,6 +22399,8 @@ pub unsafe fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19552,6 +22412,8 @@ pub unsafe fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19563,6 +22425,8 @@ pub unsafe fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19574,6 +22438,8 @@ pub unsafe fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19585,6 +22451,8 @@ pub unsafe fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19596,6 +22464,8 @@ pub unsafe fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19607,6 +22477,8 @@ pub unsafe fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19618,6 +22490,8 @@ pub unsafe fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19629,6 +22503,8 @@ pub unsafe fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19640,6 +22516,8 @@ pub unsafe fn vreinterpret_u64_s64(a: int64x1_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19651,6 +22529,8 @@ pub unsafe fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19662,6 +22542,8 @@ pub unsafe fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19673,6 +22555,8 @@ pub unsafe fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19684,6 +22568,8 @@ pub unsafe fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19695,6 +22581,8 @@ pub unsafe fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19706,6 +22594,8 @@ pub unsafe fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19717,6 +22607,8 @@ pub unsafe fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19728,6 +22620,8 @@ pub unsafe fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19739,6 +22633,8 @@ pub unsafe fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19750,6 +22646,8 @@ pub unsafe fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19761,6 +22659,8 @@ pub unsafe fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19772,6 +22672,8 @@ pub unsafe fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19783,6 +22685,8 @@ pub unsafe fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19794,6 +22698,8 @@ pub unsafe fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19805,6 +22711,8 @@ pub unsafe fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19816,6 +22724,8 @@ pub unsafe fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19827,6 +22737,8 @@ pub unsafe fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19838,6 +22750,8 @@ pub unsafe fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19849,6 +22763,8 @@ pub unsafe fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19860,6 +22776,8 @@ pub unsafe fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19871,6 +22789,8 @@ pub unsafe fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19882,6 +22802,8 @@ pub unsafe fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19893,6 +22815,8 @@ pub unsafe fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19904,6 +22828,8 @@ pub unsafe fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19915,6 +22841,8 @@ pub unsafe fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19926,6 +22854,8 @@ pub unsafe fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19937,6 +22867,8 @@ pub unsafe fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19948,6 +22880,8 @@ pub unsafe fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19959,6 +22893,8 @@ pub unsafe fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19970,6 +22906,8 @@ pub unsafe fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19981,6 +22919,8 @@ pub unsafe fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -19992,6 +22932,8 @@ pub unsafe fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20003,6 +22945,8 @@ pub unsafe fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20014,6 +22958,8 @@ pub unsafe fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20025,6 +22971,8 @@ pub unsafe fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20036,6 +22984,8 @@ pub unsafe fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20047,6 +22997,8 @@ pub unsafe fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20058,6 +23010,8 @@ pub unsafe fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20069,6 +23023,8 @@ pub unsafe fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20080,6 +23036,8 @@ pub unsafe fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20091,6 +23049,8 @@ pub unsafe fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20102,6 +23062,8 @@ pub unsafe fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20113,6 +23075,8 @@ pub unsafe fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20124,6 +23088,8 @@ pub unsafe fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20135,6 +23101,8 @@ pub unsafe fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20146,6 +23114,8 @@ pub unsafe fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20157,6 +23127,8 @@ pub unsafe fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20168,6 +23140,8 @@ pub unsafe fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20179,6 +23153,8 @@ pub unsafe fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20190,6 +23166,8 @@ pub unsafe fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20201,6 +23179,8 @@ pub unsafe fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20212,6 +23192,8 @@ pub unsafe fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20223,6 +23205,8 @@ pub unsafe fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20234,6 +23218,8 @@ pub unsafe fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20245,6 +23231,8 @@ pub unsafe fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20256,6 +23244,8 @@ pub unsafe fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20267,6 +23257,8 @@ pub unsafe fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20278,6 +23270,8 @@ pub unsafe fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20289,6 +23283,8 @@ pub unsafe fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20300,6 +23296,8 @@ pub unsafe fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20311,6 +23309,8 @@ pub unsafe fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20322,6 +23322,8 @@ pub unsafe fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20333,6 +23335,8 @@ pub unsafe fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20344,6 +23348,8 @@ pub unsafe fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20355,6 +23361,8 @@ pub unsafe fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20366,6 +23374,8 @@ pub unsafe fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20377,6 +23387,8 @@ pub unsafe fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20388,6 +23400,8 @@ pub unsafe fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20399,6 +23413,8 @@ pub unsafe fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20410,6 +23426,8 @@ pub unsafe fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20421,6 +23439,8 @@ pub unsafe fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20432,6 +23452,8 @@ pub unsafe fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20443,6 +23465,8 @@ pub unsafe fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20454,6 +23478,8 @@ pub unsafe fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20465,6 +23491,8 @@ pub unsafe fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20476,6 +23504,8 @@ pub unsafe fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20487,6 +23517,8 @@ pub unsafe fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20498,6 +23530,8 @@ pub unsafe fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20509,6 +23543,8 @@ pub unsafe fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20520,6 +23556,8 @@ pub unsafe fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20531,6 +23569,8 @@ pub unsafe fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20542,6 +23582,8 @@ pub unsafe fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20553,6 +23595,8 @@ pub unsafe fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20564,6 +23608,8 @@ pub unsafe fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20575,6 +23621,8 @@ pub unsafe fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20586,6 +23634,8 @@ pub unsafe fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20597,6 +23647,8 @@ pub unsafe fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20608,6 +23660,8 @@ pub unsafe fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20619,6 +23673,8 @@ pub unsafe fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20630,6 +23686,8 @@ pub unsafe fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20641,6 +23699,8 @@ pub unsafe fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20652,6 +23712,8 @@ pub unsafe fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20663,6 +23725,8 @@ pub unsafe fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20674,6 +23738,8 @@ pub unsafe fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20685,6 +23751,8 @@ pub unsafe fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20696,6 +23764,8 @@ pub unsafe fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20707,6 +23777,8 @@ pub unsafe fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20718,6 +23790,8 @@ pub unsafe fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20729,6 +23803,8 @@ pub unsafe fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20740,6 +23816,8 @@ pub unsafe fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20751,6 +23829,8 @@ pub unsafe fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20762,6 +23842,8 @@ pub unsafe fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20773,6 +23855,8 @@ pub unsafe fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -20784,6 +23868,8 @@ pub unsafe fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20795,6 +23881,8 @@ pub unsafe fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20806,6 +23894,8 @@ pub unsafe fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20817,6 +23907,8 @@ pub unsafe fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20828,6 +23920,8 @@ pub unsafe fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20839,6 +23933,8 @@ pub unsafe fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20850,6 +23946,8 @@ pub unsafe fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20861,6 +23959,8 @@ pub unsafe fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20872,6 +23972,8 @@ pub unsafe fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20883,6 +23985,8 @@ pub unsafe fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20894,6 +23998,8 @@ pub unsafe fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20905,6 +24011,8 @@ pub unsafe fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20916,6 +24024,8 @@ pub unsafe fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20927,6 +24037,8 @@ pub unsafe fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20938,6 +24050,8 @@ pub unsafe fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20949,6 +24063,8 @@ pub unsafe fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20960,6 +24076,8 @@ pub unsafe fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20971,6 +24089,8 @@ pub unsafe fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20982,6 +24102,8 @@ pub unsafe fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -20993,6 +24115,8 @@ pub unsafe fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21004,6 +24128,8 @@ pub unsafe fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21015,6 +24141,8 @@ pub unsafe fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21026,6 +24154,8 @@ pub unsafe fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21037,6 +24167,8 @@ pub unsafe fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21048,6 +24180,8 @@ pub unsafe fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21059,6 +24193,8 @@ pub unsafe fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21070,6 +24206,8 @@ pub unsafe fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21081,6 +24219,8 @@ pub unsafe fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21092,6 +24232,8 @@ pub unsafe fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21103,6 +24245,8 @@ pub unsafe fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21114,6 +24258,8 @@ pub unsafe fn vreinterpretq_p16_p64(a: poly64x2_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21125,6 +24271,8 @@ pub unsafe fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21136,6 +24284,8 @@ pub unsafe fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21147,6 +24297,8 @@ pub unsafe fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21158,6 +24310,8 @@ pub unsafe fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21169,6 +24323,8 @@ pub unsafe fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21180,6 +24336,8 @@ pub unsafe fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21191,6 +24349,8 @@ pub unsafe fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21202,6 +24362,8 @@ pub unsafe fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21213,6 +24375,8 @@ pub unsafe fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21224,6 +24388,8 @@ pub unsafe fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21235,6 +24401,8 @@ pub unsafe fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21246,6 +24414,8 @@ pub unsafe fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21257,6 +24427,8 @@ pub unsafe fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21268,6 +24440,8 @@ pub unsafe fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21279,6 +24453,8 @@ pub unsafe fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21290,6 +24466,8 @@ pub unsafe fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21301,6 +24479,8 @@ pub unsafe fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21312,6 +24492,8 @@ pub unsafe fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21323,6 +24505,8 @@ pub unsafe fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21334,6 +24518,8 @@ pub unsafe fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21345,6 +24531,8 @@ pub unsafe fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21356,6 +24544,8 @@ pub unsafe fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21367,6 +24557,8 @@ pub unsafe fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21378,6 +24570,8 @@ pub unsafe fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21389,6 +24583,8 @@ pub unsafe fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21400,6 +24596,8 @@ pub unsafe fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21411,6 +24609,8 @@ pub unsafe fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21422,6 +24622,8 @@ pub unsafe fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21433,6 +24635,8 @@ pub unsafe fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21444,6 +24648,8 @@ pub unsafe fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21455,6 +24661,8 @@ pub unsafe fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21466,6 +24674,8 @@ pub unsafe fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21477,6 +24687,8 @@ pub unsafe fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u32) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21488,6 +24700,8 @@ pub unsafe fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21499,6 +24713,8 @@ pub unsafe fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21510,6 +24726,8 @@ pub unsafe fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21521,6 +24739,8 @@ pub unsafe fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21532,6 +24752,8 @@ pub unsafe fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21543,6 +24765,8 @@ pub unsafe fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21554,6 +24778,8 @@ pub unsafe fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21565,6 +24791,8 @@ pub unsafe fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21576,6 +24804,8 @@ pub unsafe fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21587,6 +24817,8 @@ pub unsafe fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21598,6 +24830,8 @@ pub unsafe fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21609,6 +24843,8 @@ pub unsafe fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21620,6 +24856,8 @@ pub unsafe fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21631,6 +24869,8 @@ pub unsafe fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21642,6 +24882,8 @@ pub unsafe fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21653,6 +24895,8 @@ pub unsafe fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21664,6 +24908,8 @@ pub unsafe fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21675,6 +24921,8 @@ pub unsafe fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21686,6 +24934,8 @@ pub unsafe fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21697,6 +24947,8 @@ pub unsafe fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21708,6 +24960,8 @@ pub unsafe fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21719,6 +24973,8 @@ pub unsafe fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21730,6 +24986,8 @@ pub unsafe fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21741,6 +24999,8 @@ pub unsafe fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21752,6 +25012,8 @@ pub unsafe fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21763,6 +25025,8 @@ pub unsafe fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21774,6 +25038,8 @@ pub unsafe fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21785,6 +25051,8 @@ pub unsafe fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21796,6 +25064,8 @@ pub unsafe fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21807,6 +25077,8 @@ pub unsafe fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21818,6 +25090,8 @@ pub unsafe fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21829,6 +25103,8 @@ pub unsafe fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21840,6 +25116,8 @@ pub unsafe fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -21851,6 +25129,8 @@ pub unsafe fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21862,6 +25142,8 @@ pub unsafe fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21873,6 +25155,8 @@ pub unsafe fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21884,6 +25168,8 @@ pub unsafe fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21895,6 +25181,8 @@ pub unsafe fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21906,6 +25194,8 @@ pub unsafe fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21917,6 +25207,8 @@ pub unsafe fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21928,6 +25220,8 @@ pub unsafe fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21939,6 +25233,8 @@ pub unsafe fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p16) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21950,6 +25246,8 @@ pub unsafe fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21961,6 +25259,8 @@ pub unsafe fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21972,6 +25272,8 @@ pub unsafe fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p8) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21983,6 +25285,8 @@ pub unsafe fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -21994,6 +25298,8 @@ pub unsafe fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -22005,6 +25311,8 @@ pub unsafe fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p128) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -22016,6 +25324,8 @@ pub unsafe fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22027,6 +25337,8 @@ pub unsafe fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22038,6 +25350,8 @@ pub unsafe fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22049,6 +25363,8 @@ pub unsafe fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22060,6 +25376,8 @@ pub unsafe fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22071,6 +25389,8 @@ pub unsafe fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22082,6 +25402,8 @@ pub unsafe fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22093,6 +25415,8 @@ pub unsafe fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22104,6 +25428,8 @@ pub unsafe fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22115,6 +25441,8 @@ pub unsafe fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22126,6 +25454,8 @@ pub unsafe fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22137,6 +25467,8 @@ pub unsafe fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22148,6 +25480,8 @@ pub unsafe fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22159,6 +25493,8 @@ pub unsafe fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22170,6 +25506,8 @@ pub unsafe fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22181,6 +25519,8 @@ pub unsafe fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22192,6 +25532,8 @@ pub unsafe fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22203,6 +25545,8 @@ pub unsafe fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22214,6 +25558,8 @@ pub unsafe fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22225,6 +25571,8 @@ pub unsafe fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22236,6 +25584,8 @@ pub unsafe fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22247,6 +25597,8 @@ pub unsafe fn vreinterpretq_p128_f32(a: float32x4_t) -> p128 { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22258,6 +25610,8 @@ pub unsafe fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22269,6 +25623,8 @@ pub unsafe fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22280,6 +25636,8 @@ pub unsafe fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22291,6 +25649,8 @@ pub unsafe fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22302,6 +25662,8 @@ pub unsafe fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22313,6 +25675,8 @@ pub unsafe fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22324,6 +25688,8 @@ pub unsafe fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22335,6 +25701,8 @@ pub unsafe fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22346,6 +25714,8 @@ pub unsafe fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22357,6 +25727,8 @@ pub unsafe fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22368,6 +25740,8 @@ pub unsafe fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22379,6 +25753,8 @@ pub unsafe fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22390,6 +25766,8 @@ pub unsafe fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22401,6 +25779,8 @@ pub unsafe fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22412,6 +25792,8 @@ pub unsafe fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22423,6 +25805,8 @@ pub unsafe fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22434,6 +25818,8 @@ pub unsafe fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22445,6 +25831,8 @@ pub unsafe fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22456,6 +25844,8 @@ pub unsafe fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22467,6 +25857,8 @@ pub unsafe fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { } /// Vector reinterpret cast operation +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p128) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22478,6 +25870,8 @@ pub unsafe fn vreinterpretq_f32_p128(a: p128) -> float32x4_t { } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22495,6 +25889,8 @@ vrshl_s8_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22512,6 +25908,8 @@ vrshlq_s8_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22529,6 +25927,8 @@ vrshl_s16_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22546,6 +25946,8 @@ vrshlq_s16_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22563,6 +25965,8 @@ vrshl_s32_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22580,6 +25984,8 @@ vrshlq_s32_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22597,6 +26003,8 @@ vrshl_s64_(a, b) } /// Signed rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22614,6 +26022,8 @@ vrshlq_s64_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22631,6 +26041,8 @@ vrshl_u8_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22648,6 +26060,8 @@ vrshlq_u8_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22665,6 +26079,8 @@ vrshl_u16_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22682,6 +26098,8 @@ vrshlq_u16_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22699,6 +26117,8 @@ vrshl_u32_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22716,6 +26136,8 @@ vrshlq_u32_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshl_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22733,6 +26155,8 @@ vrshl_u64_(a, b) } /// Unsigned rounding shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshlq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22750,6 +26174,8 @@ vrshlq_u64_(a, b) } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22763,6 +26189,8 @@ pub unsafe fn vrshr_n_s8(a: int8x8_t) -> int8x8_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22776,6 +26204,8 @@ pub unsafe fn vrshrq_n_s8(a: int8x16_t) -> int8x16_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22789,6 +26219,8 @@ pub unsafe fn vrshr_n_s16(a: int16x4_t) -> int16x4_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22802,6 +26234,8 @@ pub unsafe fn vrshrq_n_s16(a: int16x8_t) -> int16x8_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22815,6 +26249,8 @@ pub unsafe fn vrshr_n_s32(a: int32x2_t) -> int32x2_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22828,6 +26264,8 @@ pub unsafe fn vrshrq_n_s32(a: int32x4_t) -> int32x4_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22841,6 +26279,8 @@ pub unsafe fn vrshr_n_s64(a: int64x1_t) -> int64x1_t { } /// Signed rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22854,6 +26294,8 @@ pub unsafe fn vrshrq_n_s64(a: int64x2_t) -> int64x2_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22867,6 +26309,8 @@ pub unsafe fn vrshr_n_u8(a: uint8x8_t) -> uint8x8_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22880,6 +26324,8 @@ pub unsafe fn vrshrq_n_u8(a: uint8x16_t) -> uint8x16_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22893,6 +26339,8 @@ pub unsafe fn vrshr_n_u16(a: uint16x4_t) -> uint16x4_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22906,6 +26354,8 @@ pub unsafe fn vrshrq_n_u16(a: uint16x8_t) -> uint16x8_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22919,6 +26369,8 @@ pub unsafe fn vrshr_n_u32(a: uint32x2_t) -> uint32x2_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22932,6 +26384,8 @@ pub unsafe fn vrshrq_n_u32(a: uint32x4_t) -> uint32x4_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshr_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22945,6 +26399,8 @@ pub unsafe fn vrshr_n_u64(a: uint64x1_t) -> uint64x1_t { } /// Unsigned rounding shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -22958,6 +26414,8 @@ pub unsafe fn vrshrq_n_u64(a: uint64x2_t) -> uint64x2_t { } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s16) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -22974,6 +26432,8 @@ vrshrn_n_s16_(a, int16x8_t(-N as i16, -N as i16, -N as i16, -N as i16, -N as i16 } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s16) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -22991,6 +26451,8 @@ vrshrn_n_s16_(a, N) } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s32) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -23007,6 +26469,8 @@ vrshrn_n_s32_(a, int32x4_t(-N as i32, -N as i32, -N as i32, -N as i32)) } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s32) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -23024,6 +26488,8 @@ vrshrn_n_s32_(a, N) } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s64) #[inline] #[cfg(target_arch = "arm")] #[target_feature(enable = "neon,v7")] @@ -23040,6 +26506,8 @@ vrshrn_n_s64_(a, int64x2_t(-N as i64, -N as i64)) } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_s64) #[inline] #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] @@ -23057,6 +26525,8 @@ vrshrn_n_s64_(a, N) } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23070,6 +26540,8 @@ pub unsafe fn vrshrn_n_u16(a: uint16x8_t) -> uint8x8_t { } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23083,6 +26555,8 @@ pub unsafe fn vrshrn_n_u32(a: uint32x4_t) -> uint16x4_t { } /// Rounding shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrshrn_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23096,6 +26570,8 @@ pub unsafe fn vrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23109,6 +26585,8 @@ pub unsafe fn vrsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23122,6 +26600,8 @@ pub unsafe fn vrsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23135,6 +26615,8 @@ pub unsafe fn vrsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23148,6 +26630,8 @@ pub unsafe fn vrsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_ } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23161,6 +26645,8 @@ pub unsafe fn vrsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23174,6 +26660,8 @@ pub unsafe fn vrsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_ } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23187,6 +26675,8 @@ pub unsafe fn vrsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t } /// Signed rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23200,6 +26690,8 @@ pub unsafe fn vrsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_ } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23213,6 +26705,8 @@ pub unsafe fn vrsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23226,6 +26720,8 @@ pub unsafe fn vrsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x1 } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23239,6 +26735,8 @@ pub unsafe fn vrsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23252,6 +26750,8 @@ pub unsafe fn vrsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16 } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23265,6 +26765,8 @@ pub unsafe fn vrsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23278,6 +26780,8 @@ pub unsafe fn vrsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32 } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsra_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23291,6 +26795,8 @@ pub unsafe fn vrsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x } /// Unsigned rounding shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsraq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23304,6 +26810,8 @@ pub unsafe fn vrsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64 } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23321,6 +26829,8 @@ vrsubhn_s16_(a, b) } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23338,6 +26848,8 @@ vrsubhn_s32_(a, b) } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23355,6 +26867,8 @@ vrsubhn_s64_(a, b) } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23366,6 +26880,8 @@ pub unsafe fn vrsubhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23377,6 +26893,8 @@ pub unsafe fn vrsubhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { } /// Rounding subtract returning high narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrsubhn_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23388,6 +26906,8 @@ pub unsafe fn vrsubhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23401,6 +26921,8 @@ pub unsafe fn vset_lane_s8(a: i8, b: int8x8_t) -> int8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23414,6 +26936,8 @@ pub unsafe fn vset_lane_s16(a: i16, b: int16x4_t) -> int16x4_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23427,6 +26951,8 @@ pub unsafe fn vset_lane_s32(a: i32, b: int32x2_t) -> int32x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23440,6 +26966,8 @@ pub unsafe fn vset_lane_s64(a: i64, b: int64x1_t) -> int64x1_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23453,6 +26981,8 @@ pub unsafe fn vset_lane_u8(a: u8, b: uint8x8_t) -> uint8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23466,6 +26996,8 @@ pub unsafe fn vset_lane_u16(a: u16, b: uint16x4_t) -> uint16x4_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23479,6 +27011,8 @@ pub unsafe fn vset_lane_u32(a: u32, b: uint32x2_t) -> uint32x2_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23492,6 +27026,8 @@ pub unsafe fn vset_lane_u64(a: u64, b: uint64x1_t) -> uint64x1_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23505,6 +27041,8 @@ pub unsafe fn vset_lane_p8(a: p8, b: poly8x8_t) -> poly8x8_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23518,6 +27056,8 @@ pub unsafe fn vset_lane_p16(a: p16, b: poly16x4_t) -> poly16x4_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -23531,6 +27071,8 @@ pub unsafe fn vset_lane_p64(a: p64, b: poly64x1_t) -> poly64x1_ } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23544,6 +27086,8 @@ pub unsafe fn vsetq_lane_s8(a: i8, b: int8x16_t) -> int8x16_t { } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23557,6 +27101,8 @@ pub unsafe fn vsetq_lane_s16(a: i16, b: int16x8_t) -> int16x8_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23570,6 +27116,8 @@ pub unsafe fn vsetq_lane_s32(a: i32, b: int32x4_t) -> int32x4_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23583,6 +27131,8 @@ pub unsafe fn vsetq_lane_s64(a: i64, b: int64x2_t) -> int64x2_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23596,6 +27146,8 @@ pub unsafe fn vsetq_lane_u8(a: u8, b: uint8x16_t) -> uint8x16_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23609,6 +27161,8 @@ pub unsafe fn vsetq_lane_u16(a: u16, b: uint16x8_t) -> uint16x8 } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23622,6 +27176,8 @@ pub unsafe fn vsetq_lane_u32(a: u32, b: uint32x4_t) -> uint32x4 } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23635,6 +27191,8 @@ pub unsafe fn vsetq_lane_u64(a: u64, b: uint64x2_t) -> uint64x2 } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23648,6 +27206,8 @@ pub unsafe fn vsetq_lane_p8(a: p8, b: poly8x16_t) -> poly8x16_t } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23661,6 +27221,8 @@ pub unsafe fn vsetq_lane_p16(a: p16, b: poly16x8_t) -> poly16x8 } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "aes,v8"))] @@ -23674,6 +27236,8 @@ pub unsafe fn vsetq_lane_p64(a: p64, b: poly64x2_t) -> poly64x2 } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vset_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23687,6 +27251,8 @@ pub unsafe fn vset_lane_f32(a: f32, b: float32x2_t) -> float32x } /// Insert vector element from another vector element +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsetq_lane_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23700,6 +27266,8 @@ pub unsafe fn vsetq_lane_f32(a: f32, b: float32x4_t) -> float32 } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23717,6 +27285,8 @@ vshl_s8_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23734,6 +27304,8 @@ vshlq_s8_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23751,6 +27323,8 @@ vshl_s16_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23768,6 +27342,8 @@ vshlq_s16_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23785,6 +27361,8 @@ vshl_s32_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23802,6 +27380,8 @@ vshlq_s32_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23819,6 +27399,8 @@ vshl_s64_(a, b) } /// Signed Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23836,6 +27418,8 @@ vshlq_s64_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23853,6 +27437,8 @@ vshl_u8_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23870,6 +27456,8 @@ vshlq_u8_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23887,6 +27475,8 @@ vshl_u16_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23904,6 +27494,8 @@ vshlq_u16_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23921,6 +27513,8 @@ vshl_u32_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23938,6 +27532,8 @@ vshlq_u32_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23955,6 +27551,8 @@ vshl_u64_(a, b) } /// Unsigned Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23972,6 +27570,8 @@ vshlq_u64_(a, b) } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23985,6 +27585,8 @@ pub unsafe fn vshl_n_s8(a: int8x8_t) -> int8x8_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -23998,6 +27600,8 @@ pub unsafe fn vshlq_n_s8(a: int8x16_t) -> int8x16_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24011,6 +27615,8 @@ pub unsafe fn vshl_n_s16(a: int16x4_t) -> int16x4_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24024,6 +27630,8 @@ pub unsafe fn vshlq_n_s16(a: int16x8_t) -> int16x8_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24037,6 +27645,8 @@ pub unsafe fn vshl_n_s32(a: int32x2_t) -> int32x2_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24050,6 +27660,8 @@ pub unsafe fn vshlq_n_s32(a: int32x4_t) -> int32x4_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24063,6 +27675,8 @@ pub unsafe fn vshl_n_u8(a: uint8x8_t) -> uint8x8_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24076,6 +27690,8 @@ pub unsafe fn vshlq_n_u8(a: uint8x16_t) -> uint8x16_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24089,6 +27705,8 @@ pub unsafe fn vshl_n_u16(a: uint16x4_t) -> uint16x4_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24102,6 +27720,8 @@ pub unsafe fn vshlq_n_u16(a: uint16x8_t) -> uint16x8_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24115,6 +27735,8 @@ pub unsafe fn vshl_n_u32(a: uint32x2_t) -> uint32x2_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24128,6 +27750,8 @@ pub unsafe fn vshlq_n_u32(a: uint32x4_t) -> uint32x4_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24141,6 +27765,8 @@ pub unsafe fn vshl_n_s64(a: int64x1_t) -> int64x1_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24154,6 +27780,8 @@ pub unsafe fn vshlq_n_s64(a: int64x2_t) -> int64x2_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshl_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24167,6 +27795,8 @@ pub unsafe fn vshl_n_u64(a: uint64x1_t) -> uint64x1_t { } /// Shift left +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshlq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24180,6 +27810,8 @@ pub unsafe fn vshlq_n_u64(a: uint64x2_t) -> uint64x2_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24193,6 +27825,8 @@ pub unsafe fn vshll_n_s8(a: int8x8_t) -> int16x8_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24206,6 +27840,8 @@ pub unsafe fn vshll_n_s16(a: int16x4_t) -> int32x4_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24219,6 +27855,8 @@ pub unsafe fn vshll_n_s32(a: int32x2_t) -> int64x2_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24232,6 +27870,8 @@ pub unsafe fn vshll_n_u8(a: uint8x8_t) -> uint16x8_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24245,6 +27885,8 @@ pub unsafe fn vshll_n_u16(a: uint16x4_t) -> uint32x4_t { } /// Signed shift left long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshll_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24258,6 +27900,8 @@ pub unsafe fn vshll_n_u32(a: uint32x2_t) -> uint64x2_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24272,6 +27916,8 @@ pub unsafe fn vshr_n_s8(a: int8x8_t) -> int8x8_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24286,6 +27932,8 @@ pub unsafe fn vshrq_n_s8(a: int8x16_t) -> int8x16_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24300,6 +27948,8 @@ pub unsafe fn vshr_n_s16(a: int16x4_t) -> int16x4_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24314,6 +27964,8 @@ pub unsafe fn vshrq_n_s16(a: int16x8_t) -> int16x8_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24328,6 +27980,8 @@ pub unsafe fn vshr_n_s32(a: int32x2_t) -> int32x2_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24342,6 +27996,8 @@ pub unsafe fn vshrq_n_s32(a: int32x4_t) -> int32x4_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24356,6 +28012,8 @@ pub unsafe fn vshr_n_s64(a: int64x1_t) -> int64x1_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24370,6 +28028,8 @@ pub unsafe fn vshrq_n_s64(a: int64x2_t) -> int64x2_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24384,6 +28044,8 @@ pub unsafe fn vshr_n_u8(a: uint8x8_t) -> uint8x8_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24398,6 +28060,8 @@ pub unsafe fn vshrq_n_u8(a: uint8x16_t) -> uint8x16_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24412,6 +28076,8 @@ pub unsafe fn vshr_n_u16(a: uint16x4_t) -> uint16x4_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24426,6 +28092,8 @@ pub unsafe fn vshrq_n_u16(a: uint16x8_t) -> uint16x8_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24440,6 +28108,8 @@ pub unsafe fn vshr_n_u32(a: uint32x2_t) -> uint32x2_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24454,6 +28124,8 @@ pub unsafe fn vshrq_n_u32(a: uint32x4_t) -> uint32x4_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshr_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24468,6 +28140,8 @@ pub unsafe fn vshr_n_u64(a: uint64x1_t) -> uint64x1_t { } /// Shift right +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24482,6 +28156,8 @@ pub unsafe fn vshrq_n_u64(a: uint64x2_t) -> uint64x2_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24495,6 +28171,8 @@ pub unsafe fn vshrn_n_s16(a: int16x8_t) -> int8x8_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24508,6 +28186,8 @@ pub unsafe fn vshrn_n_s32(a: int32x4_t) -> int16x4_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24521,6 +28201,8 @@ pub unsafe fn vshrn_n_s64(a: int64x2_t) -> int32x2_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24534,6 +28216,8 @@ pub unsafe fn vshrn_n_u16(a: uint16x8_t) -> uint8x8_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24547,6 +28231,8 @@ pub unsafe fn vshrn_n_u32(a: uint32x4_t) -> uint16x4_t { } /// Shift right narrow +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vshrn_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24560,6 +28246,8 @@ pub unsafe fn vshrn_n_u64(a: uint64x2_t) -> uint32x2_t { } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24573,6 +28261,8 @@ pub unsafe fn vsra_n_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24586,6 +28276,8 @@ pub unsafe fn vsraq_n_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24599,6 +28291,8 @@ pub unsafe fn vsra_n_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24612,6 +28306,8 @@ pub unsafe fn vsraq_n_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24625,6 +28321,8 @@ pub unsafe fn vsra_n_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24638,6 +28336,8 @@ pub unsafe fn vsraq_n_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24651,6 +28351,8 @@ pub unsafe fn vsra_n_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t } /// Signed shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_s64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24664,6 +28366,8 @@ pub unsafe fn vsraq_n_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24677,6 +28381,8 @@ pub unsafe fn vsra_n_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24690,6 +28396,8 @@ pub unsafe fn vsraq_n_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16 } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24703,6 +28411,8 @@ pub unsafe fn vsra_n_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4 } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24716,6 +28426,8 @@ pub unsafe fn vsraq_n_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24729,6 +28441,8 @@ pub unsafe fn vsra_n_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2 } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24742,6 +28456,8 @@ pub unsafe fn vsraq_n_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsra_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24755,6 +28471,8 @@ pub unsafe fn vsra_n_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1 } /// Unsigned shift right and accumulate +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsraq_n_u64) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24768,6 +28486,8 @@ pub unsafe fn vsraq_n_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24781,6 +28501,8 @@ pub unsafe fn vtrn_s8(a: int8x8_t, b: int8x8_t) -> int8x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24794,6 +28516,8 @@ pub unsafe fn vtrn_s16(a: int16x4_t, b: int16x4_t) -> int16x4x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24807,6 +28531,8 @@ pub unsafe fn vtrnq_s8(a: int8x16_t, b: int8x16_t) -> int8x16x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24820,6 +28546,8 @@ pub unsafe fn vtrnq_s16(a: int16x8_t, b: int16x8_t) -> int16x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24833,6 +28561,8 @@ pub unsafe fn vtrnq_s32(a: int32x4_t, b: int32x4_t) -> int32x4x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24846,6 +28576,8 @@ pub unsafe fn vtrn_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24859,6 +28591,8 @@ pub unsafe fn vtrn_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24872,6 +28606,8 @@ pub unsafe fn vtrnq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24885,6 +28621,8 @@ pub unsafe fn vtrnq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24898,6 +28636,8 @@ pub unsafe fn vtrnq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24911,6 +28651,8 @@ pub unsafe fn vtrn_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24924,6 +28666,8 @@ pub unsafe fn vtrn_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24937,6 +28681,8 @@ pub unsafe fn vtrnq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24950,6 +28696,8 @@ pub unsafe fn vtrnq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24963,6 +28711,8 @@ pub unsafe fn vtrn_s32(a: int32x2_t, b: int32x2_t) -> int32x2x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24976,6 +28726,8 @@ pub unsafe fn vtrn_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrn_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -24989,6 +28741,8 @@ pub unsafe fn vtrn_f32(a: float32x2_t, b: float32x2_t) -> float32x2x2_t { } /// Transpose elements +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtrnq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25002,6 +28756,8 @@ pub unsafe fn vtrnq_f32(a: float32x4_t, b: float32x4_t) -> float32x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25015,6 +28771,8 @@ pub unsafe fn vzip_s8(a: int8x8_t, b: int8x8_t) -> int8x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25028,6 +28786,8 @@ pub unsafe fn vzip_s16(a: int16x4_t, b: int16x4_t) -> int16x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25041,6 +28801,8 @@ pub unsafe fn vzip_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25054,6 +28816,8 @@ pub unsafe fn vzip_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25067,6 +28831,8 @@ pub unsafe fn vzip_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25080,6 +28846,8 @@ pub unsafe fn vzip_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25093,6 +28861,8 @@ pub unsafe fn vzip_s32(a: int32x2_t, b: int32x2_t) -> int32x2x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25106,6 +28876,8 @@ pub unsafe fn vzip_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25119,6 +28891,8 @@ pub unsafe fn vzipq_s8(a: int8x16_t, b: int8x16_t) -> int8x16x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25132,6 +28906,8 @@ pub unsafe fn vzipq_s16(a: int16x8_t, b: int16x8_t) -> int16x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25145,6 +28921,8 @@ pub unsafe fn vzipq_s32(a: int32x4_t, b: int32x4_t) -> int32x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25158,6 +28936,8 @@ pub unsafe fn vzipq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25171,6 +28951,8 @@ pub unsafe fn vzipq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25184,6 +28966,8 @@ pub unsafe fn vzipq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25197,6 +28981,8 @@ pub unsafe fn vzipq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25210,6 +28996,8 @@ pub unsafe fn vzipq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzip_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25223,6 +29011,8 @@ pub unsafe fn vzip_f32(a: float32x2_t, b: float32x2_t) -> float32x2x2_t { } /// Zip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vzipq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25236,6 +29026,8 @@ pub unsafe fn vzipq_f32(a: float32x4_t, b: float32x4_t) -> float32x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25249,6 +29041,8 @@ pub unsafe fn vuzp_s8(a: int8x8_t, b: int8x8_t) -> int8x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25262,6 +29056,8 @@ pub unsafe fn vuzp_s16(a: int16x4_t, b: int16x4_t) -> int16x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25275,6 +29071,8 @@ pub unsafe fn vuzpq_s8(a: int8x16_t, b: int8x16_t) -> int8x16x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25288,6 +29086,8 @@ pub unsafe fn vuzpq_s16(a: int16x8_t, b: int16x8_t) -> int16x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25301,6 +29101,8 @@ pub unsafe fn vuzpq_s32(a: int32x4_t, b: int32x4_t) -> int32x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25314,6 +29116,8 @@ pub unsafe fn vuzp_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25327,6 +29131,8 @@ pub unsafe fn vuzp_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25340,6 +29146,8 @@ pub unsafe fn vuzpq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25353,6 +29161,8 @@ pub unsafe fn vuzpq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25366,6 +29176,8 @@ pub unsafe fn vuzpq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25379,6 +29191,8 @@ pub unsafe fn vuzp_p8(a: poly8x8_t, b: poly8x8_t) -> poly8x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25392,6 +29206,8 @@ pub unsafe fn vuzp_p16(a: poly16x4_t, b: poly16x4_t) -> poly16x4x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_p8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25405,6 +29221,8 @@ pub unsafe fn vuzpq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_p16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25418,6 +29236,8 @@ pub unsafe fn vuzpq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25431,6 +29251,8 @@ pub unsafe fn vuzp_s32(a: int32x2_t, b: int32x2_t) -> int32x2x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25444,6 +29266,8 @@ pub unsafe fn vuzp_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzp_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25457,6 +29281,8 @@ pub unsafe fn vuzp_f32(a: float32x2_t, b: float32x2_t) -> float32x2x2_t { } /// Unzip vectors +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vuzpq_f32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25470,6 +29296,8 @@ pub unsafe fn vuzpq_f32(a: float32x4_t, b: float32x4_t) -> float32x4x2_t { } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_u8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25482,6 +29310,8 @@ pub unsafe fn vabal_u8(a: uint16x8_t, b: uint8x8_t, c: uint8x8_t) -> uint16x8_t } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_u16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25494,6 +29324,8 @@ pub unsafe fn vabal_u16(a: uint32x4_t, b: uint16x4_t, c: uint16x4_t) -> uint32x4 } /// Unsigned Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_u32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25506,6 +29338,8 @@ pub unsafe fn vabal_u32(a: uint64x2_t, b: uint32x2_t, c: uint32x2_t) -> uint64x2 } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25519,6 +29353,8 @@ pub unsafe fn vabal_s8(a: int16x8_t, b: int8x8_t, c: int8x8_t) -> int16x8_t { } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25532,6 +29368,8 @@ pub unsafe fn vabal_s16(a: int32x4_t, b: int16x4_t, c: int16x4_t) -> int32x4_t { } /// Signed Absolute difference and Accumulate Long +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vabal_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25545,6 +29383,8 @@ pub unsafe fn vabal_s32(a: int64x2_t, b: int32x2_t, c: int32x2_t) -> int64x2_t { } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabs_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25562,6 +29402,8 @@ vqabs_s8_(a) } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsq_s8) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25579,6 +29421,8 @@ vqabsq_s8_(a) } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabs_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25596,6 +29440,8 @@ vqabs_s16_(a) } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsq_s16) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25613,6 +29459,8 @@ vqabsq_s16_(a) } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabs_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -25630,6 +29478,8 @@ vqabs_s32_(a) } /// Singned saturating Absolute value +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqabsq_s32) #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -28096,181 +31946,181 @@ mod test { #[simd_test(enable = "neon")] unsafe fn test_vext_s8() { - let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i8x8 = transmute(vext_s8::<4>(transmute(a), transmute(b))); + let a: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: i8x8 = i8x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: i8x8 = transmute(vext_s8::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_s8() { - let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: i8x16 = transmute(vextq_s8::<8>(transmute(a), transmute(b))); + let a: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i8x16 = i8x16::new(1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r: i8x16 = transmute(vextq_s8::<15>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_s16() { - let a: i16x4 = i16x4::new(0, 8, 8, 9); - let b: i16x4 = i16x4::new(9, 11, 14, 15); - let e: i16x4 = i16x4::new(8, 9, 9, 11); - let r: i16x4 = transmute(vext_s16::<2>(transmute(a), transmute(b))); + let a: i16x4 = i16x4::new(1, 1, 1, 1); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let e: i16x4 = i16x4::new(1, 2, 2, 2); + let r: i16x4 = transmute(vext_s16::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_s16() { - let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i16x8 = transmute(vextq_s16::<4>(transmute(a), transmute(b))); + let a: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: i16x8 = i16x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: i16x8 = transmute(vextq_s16::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_s32() { - let a: i32x2 = i32x2::new(0, 8); - let b: i32x2 = i32x2::new(9, 11); - let e: i32x2 = i32x2::new(8, 9); + let a: i32x2 = i32x2::new(1, 1); + let b: i32x2 = i32x2::new(2, 2); + let e: i32x2 = i32x2::new(1, 2); let r: i32x2 = transmute(vext_s32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_s32() { - let a: i32x4 = i32x4::new(0, 8, 8, 9); - let b: i32x4 = i32x4::new(9, 11, 14, 15); - let e: i32x4 = i32x4::new(8, 9, 9, 11); - let r: i32x4 = transmute(vextq_s32::<2>(transmute(a), transmute(b))); + let a: i32x4 = i32x4::new(1, 1, 1, 1); + let b: i32x4 = i32x4::new(2, 2, 2, 2); + let e: i32x4 = i32x4::new(1, 2, 2, 2); + let r: i32x4 = transmute(vextq_s32::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_u8() { - let a: u8x8 = u8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: u8x8 = u8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: u8x8 = u8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: u8x8 = transmute(vext_u8::<4>(transmute(a), transmute(b))); + let a: u8x8 = u8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: u8x8 = u8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: u8x8 = u8x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: u8x8 = transmute(vext_u8::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_u8() { - let a: u8x16 = u8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: u8x16 = u8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: u8x16 = u8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: u8x16 = transmute(vextq_u8::<8>(transmute(a), transmute(b))); + let a: u8x16 = u8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b: u8x16 = u8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let e: u8x16 = u8x16::new(1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r: u8x16 = transmute(vextq_u8::<15>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_u16() { - let a: u16x4 = u16x4::new(0, 8, 8, 9); - let b: u16x4 = u16x4::new(9, 11, 14, 15); - let e: u16x4 = u16x4::new(8, 9, 9, 11); - let r: u16x4 = transmute(vext_u16::<2>(transmute(a), transmute(b))); + let a: u16x4 = u16x4::new(1, 1, 1, 1); + let b: u16x4 = u16x4::new(2, 2, 2, 2); + let e: u16x4 = u16x4::new(1, 2, 2, 2); + let r: u16x4 = transmute(vext_u16::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_u16() { - let a: u16x8 = u16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: u16x8 = u16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: u16x8 = u16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: u16x8 = transmute(vextq_u16::<4>(transmute(a), transmute(b))); + let a: u16x8 = u16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: u16x8 = u16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: u16x8 = u16x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: u16x8 = transmute(vextq_u16::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_u32() { - let a: u32x2 = u32x2::new(0, 8); - let b: u32x2 = u32x2::new(9, 11); - let e: u32x2 = u32x2::new(8, 9); + let a: u32x2 = u32x2::new(1, 1); + let b: u32x2 = u32x2::new(2, 2); + let e: u32x2 = u32x2::new(1, 2); let r: u32x2 = transmute(vext_u32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_u32() { - let a: u32x4 = u32x4::new(0, 8, 8, 9); - let b: u32x4 = u32x4::new(9, 11, 14, 15); - let e: u32x4 = u32x4::new(8, 9, 9, 11); - let r: u32x4 = transmute(vextq_u32::<2>(transmute(a), transmute(b))); + let a: u32x4 = u32x4::new(1, 1, 1, 1); + let b: u32x4 = u32x4::new(2, 2, 2, 2); + let e: u32x4 = u32x4::new(1, 2, 2, 2); + let r: u32x4 = transmute(vextq_u32::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_p8() { - let a: i8x8 = i8x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i8x8 = i8x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i8x8 = i8x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i8x8 = transmute(vext_p8::<4>(transmute(a), transmute(b))); + let a: i8x8 = i8x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: i8x8 = i8x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: i8x8 = i8x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: i8x8 = transmute(vext_p8::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_p8() { - let a: i8x16 = i8x16::new(0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15); - let b: i8x16 = i8x16::new(9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11); - let e: i8x16 = i8x16::new(8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19); - let r: i8x16 = transmute(vextq_p8::<8>(transmute(a), transmute(b))); + let a: i8x16 = i8x16::new(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b: i8x16 = i8x16::new(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i8x16 = i8x16::new(1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r: i8x16 = transmute(vextq_p8::<15>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_p16() { - let a: i16x4 = i16x4::new(0, 8, 8, 9); - let b: i16x4 = i16x4::new(9, 11, 14, 15); - let e: i16x4 = i16x4::new(8, 9, 9, 11); - let r: i16x4 = transmute(vext_p16::<2>(transmute(a), transmute(b))); + let a: i16x4 = i16x4::new(1, 1, 1, 1); + let b: i16x4 = i16x4::new(2, 2, 2, 2); + let e: i16x4 = i16x4::new(1, 2, 2, 2); + let r: i16x4 = transmute(vext_p16::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_p16() { - let a: i16x8 = i16x8::new(0, 8, 8, 9, 8, 9, 9, 11); - let b: i16x8 = i16x8::new(9, 11, 14, 15, 16, 17, 18, 19); - let e: i16x8 = i16x8::new(8, 9, 9, 11, 9, 11, 14, 15); - let r: i16x8 = transmute(vextq_p16::<4>(transmute(a), transmute(b))); + let a: i16x8 = i16x8::new(1, 1, 1, 1, 1, 1, 1, 1); + let b: i16x8 = i16x8::new(2, 2, 2, 2, 2, 2, 2, 2); + let e: i16x8 = i16x8::new(1, 2, 2, 2, 2, 2, 2, 2); + let r: i16x8 = transmute(vextq_p16::<7>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_s64() { - let a: i64x2 = i64x2::new(0, 8); - let b: i64x2 = i64x2::new(9, 11); - let e: i64x2 = i64x2::new(8, 9); + let a: i64x2 = i64x2::new(1, 1); + let b: i64x2 = i64x2::new(2, 2); + let e: i64x2 = i64x2::new(1, 2); let r: i64x2 = transmute(vextq_s64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_u64() { - let a: u64x2 = u64x2::new(0, 8); - let b: u64x2 = u64x2::new(9, 11); - let e: u64x2 = u64x2::new(8, 9); + let a: u64x2 = u64x2::new(1, 1); + let b: u64x2 = u64x2::new(2, 2); + let e: u64x2 = u64x2::new(1, 2); let r: u64x2 = transmute(vextq_u64::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vext_f32() { - let a: f32x2 = f32x2::new(0., 2.); - let b: f32x2 = f32x2::new(3., 4.); - let e: f32x2 = f32x2::new(2., 3.); + let a: f32x2 = f32x2::new(1., 1.); + let b: f32x2 = f32x2::new(2., 2.); + let e: f32x2 = f32x2::new(1., 2.); let r: f32x2 = transmute(vext_f32::<1>(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vextq_f32() { - let a: f32x4 = f32x4::new(0., 2., 2., 3.); - let b: f32x4 = f32x4::new(3., 4., 5., 6.); - let e: f32x4 = f32x4::new(2., 3., 3., 4.); - let r: f32x4 = transmute(vextq_f32::<2>(transmute(a), transmute(b))); + let a: f32x4 = f32x4::new(1., 1., 1., 1.); + let b: f32x4 = f32x4::new(2., 2., 2., 2.); + let e: f32x4 = f32x4::new(1., 2., 2., 2.); + let r: f32x4 = transmute(vextq_f32::<3>(transmute(a), transmute(b))); assert_eq!(r, e); } diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs index 952d1ca2e..043f7ed51 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs @@ -106,6 +106,7 @@ types! { } /// ARM-specific type containing two `int8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -113,6 +114,7 @@ types! { )] pub struct int8x8x2_t(pub int8x8_t, pub int8x8_t); /// ARM-specific type containing three `int8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -120,6 +122,7 @@ pub struct int8x8x2_t(pub int8x8_t, pub int8x8_t); )] pub struct int8x8x3_t(pub int8x8_t, pub int8x8_t, pub int8x8_t); /// ARM-specific type containing four `int8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -128,6 +131,7 @@ pub struct int8x8x3_t(pub int8x8_t, pub int8x8_t, pub int8x8_t); pub struct int8x8x4_t(pub int8x8_t, pub int8x8_t, pub int8x8_t, pub int8x8_t); /// ARM-specific type containing two `int8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -135,6 +139,7 @@ pub struct int8x8x4_t(pub int8x8_t, pub int8x8_t, pub int8x8_t, pub int8x8_t); )] pub struct int8x16x2_t(pub int8x16_t, pub int8x16_t); /// ARM-specific type containing three `int8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -142,6 +147,7 @@ pub struct int8x16x2_t(pub int8x16_t, pub int8x16_t); )] pub struct int8x16x3_t(pub int8x16_t, pub int8x16_t, pub int8x16_t); /// ARM-specific type containing four `int8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -150,6 +156,7 @@ pub struct int8x16x3_t(pub int8x16_t, pub int8x16_t, pub int8x16_t); pub struct int8x16x4_t(pub int8x16_t, pub int8x16_t, pub int8x16_t, pub int8x16_t); /// ARM-specific type containing two `uint8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -157,6 +164,7 @@ pub struct int8x16x4_t(pub int8x16_t, pub int8x16_t, pub int8x16_t, pub int8x16_ )] pub struct uint8x8x2_t(pub uint8x8_t, pub uint8x8_t); /// ARM-specific type containing three `uint8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -164,6 +172,7 @@ pub struct uint8x8x2_t(pub uint8x8_t, pub uint8x8_t); )] pub struct uint8x8x3_t(pub uint8x8_t, pub uint8x8_t, pub uint8x8_t); /// ARM-specific type containing four `uint8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -172,6 +181,7 @@ pub struct uint8x8x3_t(pub uint8x8_t, pub uint8x8_t, pub uint8x8_t); pub struct uint8x8x4_t(pub uint8x8_t, pub uint8x8_t, pub uint8x8_t, pub uint8x8_t); /// ARM-specific type containing two `uint8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -179,6 +189,7 @@ pub struct uint8x8x4_t(pub uint8x8_t, pub uint8x8_t, pub uint8x8_t, pub uint8x8_ )] pub struct uint8x16x2_t(pub uint8x16_t, pub uint8x16_t); /// ARM-specific type containing three `uint8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -186,6 +197,7 @@ pub struct uint8x16x2_t(pub uint8x16_t, pub uint8x16_t); )] pub struct uint8x16x3_t(pub uint8x16_t, pub uint8x16_t, pub uint8x16_t); /// ARM-specific type containing four `uint8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -199,6 +211,7 @@ pub struct uint8x16x4_t( ); /// ARM-specific type containing two `poly8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -206,6 +219,7 @@ pub struct uint8x16x4_t( )] pub struct poly8x8x2_t(pub poly8x8_t, pub poly8x8_t); /// ARM-specific type containing three `poly8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -213,6 +227,7 @@ pub struct poly8x8x2_t(pub poly8x8_t, pub poly8x8_t); )] pub struct poly8x8x3_t(pub poly8x8_t, pub poly8x8_t, pub poly8x8_t); /// ARM-specific type containing four `poly8x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -221,6 +236,7 @@ pub struct poly8x8x3_t(pub poly8x8_t, pub poly8x8_t, pub poly8x8_t); pub struct poly8x8x4_t(pub poly8x8_t, pub poly8x8_t, pub poly8x8_t, pub poly8x8_t); /// ARM-specific type containing two `poly8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -228,6 +244,7 @@ pub struct poly8x8x4_t(pub poly8x8_t, pub poly8x8_t, pub poly8x8_t, pub poly8x8_ )] pub struct poly8x16x2_t(pub poly8x16_t, pub poly8x16_t); /// ARM-specific type containing three `poly8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -235,6 +252,7 @@ pub struct poly8x16x2_t(pub poly8x16_t, pub poly8x16_t); )] pub struct poly8x16x3_t(pub poly8x16_t, pub poly8x16_t, pub poly8x16_t); /// ARM-specific type containing four `poly8x16_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -248,6 +266,7 @@ pub struct poly8x16x4_t( ); /// ARM-specific type containing two `int16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -255,6 +274,7 @@ pub struct poly8x16x4_t( )] pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); /// ARM-specific type containing three `int16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -262,6 +282,7 @@ pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); )] pub struct int16x4x3_t(pub int16x4_t, pub int16x4_t, pub int16x4_t); /// ARM-specific type containing four `int16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -270,6 +291,7 @@ pub struct int16x4x3_t(pub int16x4_t, pub int16x4_t, pub int16x4_t); pub struct int16x4x4_t(pub int16x4_t, pub int16x4_t, pub int16x4_t, pub int16x4_t); /// ARM-specific type containing two `int16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -277,6 +299,7 @@ pub struct int16x4x4_t(pub int16x4_t, pub int16x4_t, pub int16x4_t, pub int16x4_ )] pub struct int16x8x2_t(pub int16x8_t, pub int16x8_t); /// ARM-specific type containing three `int16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -284,6 +307,7 @@ pub struct int16x8x2_t(pub int16x8_t, pub int16x8_t); )] pub struct int16x8x3_t(pub int16x8_t, pub int16x8_t, pub int16x8_t); /// ARM-specific type containing four `int16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -292,6 +316,7 @@ pub struct int16x8x3_t(pub int16x8_t, pub int16x8_t, pub int16x8_t); pub struct int16x8x4_t(pub int16x8_t, pub int16x8_t, pub int16x8_t, pub int16x8_t); /// ARM-specific type containing two `uint16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -299,6 +324,7 @@ pub struct int16x8x4_t(pub int16x8_t, pub int16x8_t, pub int16x8_t, pub int16x8_ )] pub struct uint16x4x2_t(pub uint16x4_t, pub uint16x4_t); /// ARM-specific type containing three `uint16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -306,6 +332,7 @@ pub struct uint16x4x2_t(pub uint16x4_t, pub uint16x4_t); )] pub struct uint16x4x3_t(pub uint16x4_t, pub uint16x4_t, pub uint16x4_t); /// ARM-specific type containing four `uint16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -319,6 +346,7 @@ pub struct uint16x4x4_t( ); /// ARM-specific type containing two `uint16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -326,6 +354,7 @@ pub struct uint16x4x4_t( )] pub struct uint16x8x2_t(pub uint16x8_t, pub uint16x8_t); /// ARM-specific type containing three `uint16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -333,6 +362,7 @@ pub struct uint16x8x2_t(pub uint16x8_t, pub uint16x8_t); )] pub struct uint16x8x3_t(pub uint16x8_t, pub uint16x8_t, pub uint16x8_t); /// ARM-specific type containing four `uint16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -346,6 +376,7 @@ pub struct uint16x8x4_t( ); /// ARM-specific type containing two `poly16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -353,6 +384,7 @@ pub struct uint16x8x4_t( )] pub struct poly16x4x2_t(pub poly16x4_t, pub poly16x4_t); /// ARM-specific type containing three `poly16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -360,6 +392,7 @@ pub struct poly16x4x2_t(pub poly16x4_t, pub poly16x4_t); )] pub struct poly16x4x3_t(pub poly16x4_t, pub poly16x4_t, pub poly16x4_t); /// ARM-specific type containing four `poly16x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -373,6 +406,7 @@ pub struct poly16x4x4_t( ); /// ARM-specific type containing two `poly16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -380,6 +414,7 @@ pub struct poly16x4x4_t( )] pub struct poly16x8x2_t(pub poly16x8_t, pub poly16x8_t); /// ARM-specific type containing three `poly16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -387,6 +422,7 @@ pub struct poly16x8x2_t(pub poly16x8_t, pub poly16x8_t); )] pub struct poly16x8x3_t(pub poly16x8_t, pub poly16x8_t, pub poly16x8_t); /// ARM-specific type containing four `poly16x8_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -400,6 +436,7 @@ pub struct poly16x8x4_t( ); /// ARM-specific type containing two `int32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -407,6 +444,7 @@ pub struct poly16x8x4_t( )] pub struct int32x2x2_t(pub int32x2_t, pub int32x2_t); /// ARM-specific type containing three `int32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -414,6 +452,7 @@ pub struct int32x2x2_t(pub int32x2_t, pub int32x2_t); )] pub struct int32x2x3_t(pub int32x2_t, pub int32x2_t, pub int32x2_t); /// ARM-specific type containing four `int32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -422,6 +461,7 @@ pub struct int32x2x3_t(pub int32x2_t, pub int32x2_t, pub int32x2_t); pub struct int32x2x4_t(pub int32x2_t, pub int32x2_t, pub int32x2_t, pub int32x2_t); /// ARM-specific type containing two `int32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -429,6 +469,7 @@ pub struct int32x2x4_t(pub int32x2_t, pub int32x2_t, pub int32x2_t, pub int32x2_ )] pub struct int32x4x2_t(pub int32x4_t, pub int32x4_t); /// ARM-specific type containing three `int32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -436,6 +477,7 @@ pub struct int32x4x2_t(pub int32x4_t, pub int32x4_t); )] pub struct int32x4x3_t(pub int32x4_t, pub int32x4_t, pub int32x4_t); /// ARM-specific type containing four `int32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -444,6 +486,7 @@ pub struct int32x4x3_t(pub int32x4_t, pub int32x4_t, pub int32x4_t); pub struct int32x4x4_t(pub int32x4_t, pub int32x4_t, pub int32x4_t, pub int32x4_t); /// ARM-specific type containing two `uint32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -451,6 +494,7 @@ pub struct int32x4x4_t(pub int32x4_t, pub int32x4_t, pub int32x4_t, pub int32x4_ )] pub struct uint32x2x2_t(pub uint32x2_t, pub uint32x2_t); /// ARM-specific type containing three `uint32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -458,6 +502,7 @@ pub struct uint32x2x2_t(pub uint32x2_t, pub uint32x2_t); )] pub struct uint32x2x3_t(pub uint32x2_t, pub uint32x2_t, pub uint32x2_t); /// ARM-specific type containing four `uint32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -471,6 +516,7 @@ pub struct uint32x2x4_t( ); /// ARM-specific type containing two `uint32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -478,6 +524,7 @@ pub struct uint32x2x4_t( )] pub struct uint32x4x2_t(pub uint32x4_t, pub uint32x4_t); /// ARM-specific type containing three `uint32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -485,6 +532,7 @@ pub struct uint32x4x2_t(pub uint32x4_t, pub uint32x4_t); )] pub struct uint32x4x3_t(pub uint32x4_t, pub uint32x4_t, pub uint32x4_t); /// ARM-specific type containing four `uint32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -498,6 +546,7 @@ pub struct uint32x4x4_t( ); /// ARM-specific type containing two `float32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -505,6 +554,7 @@ pub struct uint32x4x4_t( )] pub struct float32x2x2_t(pub float32x2_t, pub float32x2_t); /// ARM-specific type containing three `float32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -512,6 +562,7 @@ pub struct float32x2x2_t(pub float32x2_t, pub float32x2_t); )] pub struct float32x2x3_t(pub float32x2_t, pub float32x2_t, pub float32x2_t); /// ARM-specific type containing four `float32x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -525,6 +576,7 @@ pub struct float32x2x4_t( ); /// ARM-specific type containing two `float32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -532,6 +584,7 @@ pub struct float32x2x4_t( )] pub struct float32x4x2_t(pub float32x4_t, pub float32x4_t); /// ARM-specific type containing three `float32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -539,6 +592,7 @@ pub struct float32x4x2_t(pub float32x4_t, pub float32x4_t); )] pub struct float32x4x3_t(pub float32x4_t, pub float32x4_t, pub float32x4_t); /// ARM-specific type containing four `float32x4_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -552,6 +606,7 @@ pub struct float32x4x4_t( ); /// ARM-specific type containing four `int64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -559,6 +614,7 @@ pub struct float32x4x4_t( )] pub struct int64x1x2_t(pub int64x1_t, pub int64x1_t); /// ARM-specific type containing four `int64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -566,6 +622,7 @@ pub struct int64x1x2_t(pub int64x1_t, pub int64x1_t); )] pub struct int64x1x3_t(pub int64x1_t, pub int64x1_t, pub int64x1_t); /// ARM-specific type containing four `int64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -574,6 +631,7 @@ pub struct int64x1x3_t(pub int64x1_t, pub int64x1_t, pub int64x1_t); pub struct int64x1x4_t(pub int64x1_t, pub int64x1_t, pub int64x1_t, pub int64x1_t); /// ARM-specific type containing four `int64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -581,6 +639,7 @@ pub struct int64x1x4_t(pub int64x1_t, pub int64x1_t, pub int64x1_t, pub int64x1_ )] pub struct int64x2x2_t(pub int64x2_t, pub int64x2_t); /// ARM-specific type containing four `int64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -588,6 +647,7 @@ pub struct int64x2x2_t(pub int64x2_t, pub int64x2_t); )] pub struct int64x2x3_t(pub int64x2_t, pub int64x2_t, pub int64x2_t); /// ARM-specific type containing four `int64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -596,6 +656,7 @@ pub struct int64x2x3_t(pub int64x2_t, pub int64x2_t, pub int64x2_t); pub struct int64x2x4_t(pub int64x2_t, pub int64x2_t, pub int64x2_t, pub int64x2_t); /// ARM-specific type containing four `uint64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -603,6 +664,7 @@ pub struct int64x2x4_t(pub int64x2_t, pub int64x2_t, pub int64x2_t, pub int64x2_ )] pub struct uint64x1x2_t(pub uint64x1_t, pub uint64x1_t); /// ARM-specific type containing four `uint64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -610,6 +672,7 @@ pub struct uint64x1x2_t(pub uint64x1_t, pub uint64x1_t); )] pub struct uint64x1x3_t(pub uint64x1_t, pub uint64x1_t, pub uint64x1_t); /// ARM-specific type containing four `uint64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -623,6 +686,7 @@ pub struct uint64x1x4_t( ); /// ARM-specific type containing four `uint64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -630,6 +694,7 @@ pub struct uint64x1x4_t( )] pub struct uint64x2x2_t(pub uint64x2_t, pub uint64x2_t); /// ARM-specific type containing four `uint64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -637,6 +702,7 @@ pub struct uint64x2x2_t(pub uint64x2_t, pub uint64x2_t); )] pub struct uint64x2x3_t(pub uint64x2_t, pub uint64x2_t, pub uint64x2_t); /// ARM-specific type containing four `uint64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -650,6 +716,7 @@ pub struct uint64x2x4_t( ); /// ARM-specific type containing four `poly64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -657,6 +724,7 @@ pub struct uint64x2x4_t( )] pub struct poly64x1x2_t(pub poly64x1_t, pub poly64x1_t); /// ARM-specific type containing four `poly64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -664,6 +732,7 @@ pub struct poly64x1x2_t(pub poly64x1_t, pub poly64x1_t); )] pub struct poly64x1x3_t(pub poly64x1_t, pub poly64x1_t, pub poly64x1_t); /// ARM-specific type containing four `poly64x1_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -677,6 +746,7 @@ pub struct poly64x1x4_t( ); /// ARM-specific type containing four `poly64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -684,6 +754,7 @@ pub struct poly64x1x4_t( )] pub struct poly64x2x2_t(pub poly64x2_t, pub poly64x2_t); /// ARM-specific type containing four `poly64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -691,6 +762,7 @@ pub struct poly64x2x2_t(pub poly64x2_t, pub poly64x2_t); )] pub struct poly64x2x3_t(pub poly64x2_t, pub poly64x2_t, pub poly64x2_t); /// ARM-specific type containing four `poly64x2_t` vectors. +#[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg_attr( target_arch = "aarch64", @@ -1212,6 +1284,8 @@ pub unsafe fn vld1q_lane_p16(ptr: *const p16, src: poly16x8_t) } /// Load one single-element structure to one lane of one register. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1228,6 +1302,8 @@ pub unsafe fn vld1_lane_p64(ptr: *const p64, src: poly64x1_t) - } /// Load one single-element structure to one lane of one register. +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_lane_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1603,6 +1679,8 @@ pub unsafe fn vld1_dup_f32(ptr: *const f32) -> float32x2_t { } /// Load one single-element structure and Replicate to all lanes (of one register). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -1624,6 +1702,8 @@ pub unsafe fn vld1_dup_p64(ptr: *const p64) -> poly64x1_t { } /// Load one single-element structure and Replicate to all lanes (of one register). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vld1q_dup_p64) #[inline] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -3733,7 +3813,11 @@ pub unsafe fn vbicq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_s8(a: uint8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { - simd_select(transmute::<_, int8x8_t>(a), b, c) + let not = int8x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3747,7 +3831,11 @@ pub unsafe fn vbsl_s8(a: uint8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_s16(a: uint16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { - simd_select(transmute::<_, int16x4_t>(a), b, c) + let not = int16x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3761,7 +3849,11 @@ pub unsafe fn vbsl_s16(a: uint16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_s32(a: uint32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { - simd_select(transmute::<_, int32x2_t>(a), b, c) + let not = int32x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3775,7 +3867,11 @@ pub unsafe fn vbsl_s32(a: uint32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_s64(a: uint64x1_t, b: int64x1_t, c: int64x1_t) -> int64x1_t { - simd_select(transmute::<_, int64x1_t>(a), b, c) + let not = int64x1_t(-1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3789,7 +3885,11 @@ pub unsafe fn vbsl_s64(a: uint64x1_t, b: int64x1_t, c: int64x1_t) -> int64x1_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { - simd_select(transmute::<_, int8x8_t>(a), b, c) + let not = int8x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3803,7 +3903,11 @@ pub unsafe fn vbsl_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_u16(a: uint16x4_t, b: uint16x4_t, c: uint16x4_t) -> uint16x4_t { - simd_select(transmute::<_, int16x4_t>(a), b, c) + let not = int16x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3817,7 +3921,11 @@ pub unsafe fn vbsl_u16(a: uint16x4_t, b: uint16x4_t, c: uint16x4_t) -> uint16x4_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_u32(a: uint32x2_t, b: uint32x2_t, c: uint32x2_t) -> uint32x2_t { - simd_select(transmute::<_, int32x2_t>(a), b, c) + let not = int32x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3831,7 +3939,11 @@ pub unsafe fn vbsl_u32(a: uint32x2_t, b: uint32x2_t, c: uint32x2_t) -> uint32x2_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_u64(a: uint64x1_t, b: uint64x1_t, c: uint64x1_t) -> uint64x1_t { - simd_select(transmute::<_, int64x1_t>(a), b, c) + let not = int64x1_t(-1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3845,7 +3957,11 @@ pub unsafe fn vbsl_u64(a: uint64x1_t, b: uint64x1_t, c: uint64x1_t) -> uint64x1_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_f32(a: uint32x2_t, b: float32x2_t, c: float32x2_t) -> float32x2_t { - simd_select(transmute::<_, int32x2_t>(a), b, c) + let not = int32x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3859,7 +3975,11 @@ pub unsafe fn vbsl_f32(a: uint32x2_t, b: float32x2_t, c: float32x2_t) -> float32 stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_p8(a: uint8x8_t, b: poly8x8_t, c: poly8x8_t) -> poly8x8_t { - simd_select(transmute::<_, int8x8_t>(a), b, c) + let not = int8x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. @@ -3873,7 +3993,11 @@ pub unsafe fn vbsl_p8(a: uint8x8_t, b: poly8x8_t, c: poly8x8_t) -> poly8x8_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbsl_p16(a: uint16x4_t, b: poly16x4_t, c: poly16x4_t) -> poly16x4_t { - simd_select(transmute::<_, int16x4_t>(a), b, c) + let not = int16x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3887,7 +4011,13 @@ pub unsafe fn vbsl_p16(a: uint16x4_t, b: poly16x4_t, c: poly16x4_t) -> poly16x4_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_s8(a: uint8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { - simd_select(transmute::<_, int8x16_t>(a), b, c) + let not = int8x16_t( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3901,7 +4031,11 @@ pub unsafe fn vbslq_s8(a: uint8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t { stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_s16(a: uint16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t { - simd_select(transmute::<_, int16x8_t>(a), b, c) + let not = int16x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3915,7 +4049,11 @@ pub unsafe fn vbslq_s16(a: uint16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_s32(a: uint32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t { - simd_select(transmute::<_, int32x4_t>(a), b, c) + let not = int32x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3929,7 +4067,11 @@ pub unsafe fn vbslq_s32(a: uint32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_s64(a: uint64x2_t, b: int64x2_t, c: int64x2_t) -> int64x2_t { - simd_select(transmute::<_, int64x2_t>(a), b, c) + let not = int64x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3943,7 +4085,13 @@ pub unsafe fn vbslq_s64(a: uint64x2_t, b: int64x2_t, c: int64x2_t) -> int64x2_t stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_t { - simd_select(transmute::<_, int8x16_t>(a), b, c) + let not = int8x16_t( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3957,7 +4105,11 @@ pub unsafe fn vbslq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x8_t { - simd_select(transmute::<_, int16x8_t>(a), b, c) + let not = int16x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3971,7 +4123,11 @@ pub unsafe fn vbslq_u16(a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x8 stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x4_t { - simd_select(transmute::<_, int32x4_t>(a), b, c) + let not = int32x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3985,7 +4141,11 @@ pub unsafe fn vbslq_u32(a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x4 stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x2_t { - simd_select(transmute::<_, int64x2_t>(a), b, c) + let not = int64x2_t(-1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -3999,7 +4159,13 @@ pub unsafe fn vbslq_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x2 stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_p8(a: uint8x16_t, b: poly8x16_t, c: poly8x16_t) -> poly8x16_t { - simd_select(transmute::<_, int8x16_t>(a), b, c) + let not = int8x16_t( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -4013,7 +4179,11 @@ pub unsafe fn vbslq_p8(a: uint8x16_t, b: poly8x16_t, c: poly8x16_t) -> poly8x16_ stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_p16(a: uint16x8_t, b: poly16x8_t, c: poly16x8_t) -> poly16x8_t { - simd_select(transmute::<_, int16x8_t>(a), b, c) + let not = int16x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Bitwise Select. (128-bit) @@ -4027,7 +4197,11 @@ pub unsafe fn vbslq_p16(a: uint16x8_t, b: poly16x8_t, c: poly16x8_t) -> poly16x8 stable(feature = "neon_intrinsics", since = "1.59.0") )] pub unsafe fn vbslq_f32(a: uint32x4_t, b: float32x4_t, c: float32x4_t) -> float32x4_t { - simd_select(transmute::<_, int32x4_t>(a), b, c) + let not = int32x4_t(-1, -1, -1, -1); + transmute(simd_or( + simd_and(a, transmute(b)), + simd_and(simd_xor(a, transmute(not)), transmute(c)), + )) } /// Vector bitwise inclusive OR NOT @@ -9206,7 +9380,7 @@ mod tests { #[simd_test(enable = "neon")] unsafe fn test_vbsl_s8() { - let a = u8x8::new(u8::MAX, 0, u8::MAX, 0, u8::MAX, 0, u8::MAX, 0); + let a = u8x8::new(u8::MAX, 1, u8::MAX, 2, u8::MAX, 0, u8::MAX, 0); let b = i8x8::new( i8::MAX, i8::MAX, @@ -9229,9 +9403,9 @@ mod tests { ); let e = i8x8::new( i8::MAX, - i8::MIN, + i8::MIN | 1, i8::MAX, - i8::MIN, + i8::MIN | 2, i8::MAX, i8::MIN, i8::MAX, @@ -9242,34 +9416,34 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbsl_s16() { - let a = u16x4::new(u16::MAX, 0, u16::MAX, 0); + let a = u16x4::new(u16::MAX, 0, 1, 2); let b = i16x4::new(i16::MAX, i16::MAX, i16::MAX, i16::MAX); let c = i16x4::new(i16::MIN, i16::MIN, i16::MIN, i16::MIN); - let e = i16x4::new(i16::MAX, i16::MIN, i16::MAX, i16::MIN); + let e = i16x4::new(i16::MAX, i16::MIN, i16::MIN | 1, i16::MIN | 2); let r: i16x4 = transmute(vbsl_s16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_s32() { - let a = u32x2::new(u32::MAX, u32::MIN); + let a = u32x2::new(u32::MAX, 1); let b = i32x2::new(i32::MAX, i32::MAX); let c = i32x2::new(i32::MIN, i32::MIN); - let e = i32x2::new(i32::MAX, i32::MIN); + let e = i32x2::new(i32::MAX, i32::MIN | 1); let r: i32x2 = transmute(vbsl_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_s64() { - let a = u64x1::new(u64::MAX); + let a = u64x1::new(1); let b = i64x1::new(i64::MAX); let c = i64x1::new(i64::MIN); - let e = i64x1::new(i64::MAX); + let e = i64x1::new(i64::MIN | 1); let r: i64x1 = transmute(vbsl_s64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_u8() { - let a = u8x8::new(u8::MAX, 0, u8::MAX, 0, u8::MAX, 0, u8::MAX, 0); + let a = u8x8::new(u8::MAX, 1, u8::MAX, 2, u8::MAX, 0, u8::MAX, 0); let b = u8x8::new( u8::MAX, u8::MAX, @@ -9290,58 +9464,49 @@ mod tests { u8::MIN, u8::MIN, ); - let e = u8x8::new( - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - ); + let e = u8x8::new(u8::MAX, 1, u8::MAX, 2, u8::MAX, u8::MIN, u8::MAX, u8::MIN); let r: u8x8 = transmute(vbsl_u8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_u16() { - let a = u16x4::new(u16::MAX, 0, u16::MAX, 0); + let a = u16x4::new(u16::MAX, 0, 1, 2); let b = u16x4::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX); let c = u16x4::new(u16::MIN, u16::MIN, u16::MIN, u16::MIN); - let e = u16x4::new(u16::MAX, u16::MIN, u16::MAX, u16::MIN); + let e = u16x4::new(u16::MAX, 0, 1, 2); let r: u16x4 = transmute(vbsl_u16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_u32() { - let a = u32x2::new(u32::MAX, 0); + let a = u32x2::new(u32::MAX, 2); let b = u32x2::new(u32::MAX, u32::MAX); let c = u32x2::new(u32::MIN, u32::MIN); - let e = u32x2::new(u32::MAX, u32::MIN); + let e = u32x2::new(u32::MAX, 2); let r: u32x2 = transmute(vbsl_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_u64() { - let a = u64x1::new(u64::MAX); + let a = u64x1::new(2); let b = u64x1::new(u64::MAX); let c = u64x1::new(u64::MIN); - let e = u64x1::new(u64::MAX); + let e = u64x1::new(2); let r: u64x1 = transmute(vbsl_u64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_f32() { - let a = u32x2::new(u32::MAX, 0); - let b = f32x2::new(f32::MAX, f32::MAX); - let c = f32x2::new(f32::MIN, f32::MIN); - let e = f32x2::new(f32::MAX, f32::MIN); + let a = u32x2::new(1, 0x80000000); + let b = f32x2::new(8388609f32, -1.23f32); + let c = f32x2::new(2097152f32, 2.34f32); + let e = f32x2::new(2097152.25f32, -2.34f32); let r: f32x2 = transmute(vbsl_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_p8() { - let a = u8x8::new(u8::MAX, 0, u8::MAX, 0, u8::MAX, 0, u8::MAX, 0); + let a = u8x8::new(u8::MAX, 1, u8::MAX, 2, u8::MAX, 0, u8::MAX, 0); let b = u8x8::new( u8::MAX, u8::MAX, @@ -9362,25 +9527,16 @@ mod tests { u8::MIN, u8::MIN, ); - let e = u8x8::new( - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - u8::MAX, - u8::MIN, - ); + let e = u8x8::new(u8::MAX, 1, u8::MAX, 2, u8::MAX, u8::MIN, u8::MAX, u8::MIN); let r: u8x8 = transmute(vbsl_p8(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbsl_p16() { - let a = u16x4::new(u16::MAX, 0, u16::MAX, 0); + let a = u16x4::new(u16::MAX, 0, 1, 2); let b = u16x4::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX); let c = u16x4::new(u16::MIN, u16::MIN, u16::MIN, u16::MIN); - let e = u16x4::new(u16::MAX, u16::MIN, u16::MAX, u16::MIN); + let e = u16x4::new(u16::MAX, 0, 1, 2); let r: u16x4 = transmute(vbsl_p16(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } @@ -9388,9 +9544,9 @@ mod tests { unsafe fn test_vbslq_s8() { let a = u8x16::new( u8::MAX, - 0, + 1, u8::MAX, - 0, + 2, u8::MAX, 0, u8::MAX, @@ -9442,9 +9598,9 @@ mod tests { ); let e = i8x16::new( i8::MAX, - i8::MIN, + i8::MIN | 1, i8::MAX, - i8::MIN, + i8::MIN | 2, i8::MAX, i8::MIN, i8::MAX, @@ -9463,7 +9619,7 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbslq_s16() { - let a = u16x8::new(u16::MAX, 0, u16::MAX, 0, u16::MAX, 0, u16::MAX, 0); + let a = u16x8::new(u16::MAX, 1, u16::MAX, 2, u16::MAX, 0, u16::MAX, 0); let b = i16x8::new( i16::MAX, i16::MAX, @@ -9486,9 +9642,9 @@ mod tests { ); let e = i16x8::new( i16::MAX, - i16::MIN, + i16::MIN | 1, i16::MAX, - i16::MIN, + i16::MIN | 2, i16::MAX, i16::MIN, i16::MAX, @@ -9499,19 +9655,19 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbslq_s32() { - let a = u32x4::new(u32::MAX, 0, u32::MAX, 0); + let a = u32x4::new(u32::MAX, 1, u32::MAX, 2); let b = i32x4::new(i32::MAX, i32::MAX, i32::MAX, i32::MAX); let c = i32x4::new(i32::MIN, i32::MIN, i32::MIN, i32::MIN); - let e = i32x4::new(i32::MAX, i32::MIN, i32::MAX, i32::MIN); + let e = i32x4::new(i32::MAX, i32::MIN | 1, i32::MAX, i32::MIN | 2); let r: i32x4 = transmute(vbslq_s32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbslq_s64() { - let a = u64x2::new(u64::MAX, 0); + let a = u64x2::new(u64::MAX, 1); let b = i64x2::new(i64::MAX, i64::MAX); let c = i64x2::new(i64::MIN, i64::MIN); - let e = i64x2::new(i64::MAX, i64::MIN); + let e = i64x2::new(i64::MAX, i64::MIN | 1); let r: i64x2 = transmute(vbslq_s64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } @@ -9519,9 +9675,9 @@ mod tests { unsafe fn test_vbslq_u8() { let a = u8x16::new( u8::MAX, - 0, + 1, u8::MAX, - 0, + 2, u8::MAX, 0, u8::MAX, @@ -9573,9 +9729,9 @@ mod tests { ); let e = u8x16::new( u8::MAX, - u8::MIN, + 1, u8::MAX, - u8::MIN, + 2, u8::MAX, u8::MIN, u8::MAX, @@ -9594,7 +9750,7 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbslq_u16() { - let a = u16x8::new(u16::MAX, 0, u16::MAX, 0, u16::MAX, 0, u16::MAX, 0); + let a = u16x8::new(u16::MAX, 1, u16::MAX, 2, u16::MAX, 0, u16::MAX, 0); let b = u16x8::new( u16::MAX, u16::MAX, @@ -9617,9 +9773,9 @@ mod tests { ); let e = u16x8::new( u16::MAX, - u16::MIN, + 1, u16::MAX, - u16::MIN, + 2, u16::MAX, u16::MIN, u16::MAX, @@ -9630,28 +9786,28 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbslq_u32() { - let a = u32x4::new(u32::MAX, 0, u32::MAX, 0); + let a = u32x4::new(u32::MAX, 1, u32::MAX, 2); let b = u32x4::new(u32::MAX, u32::MAX, u32::MAX, u32::MAX); let c = u32x4::new(u32::MIN, u32::MIN, u32::MIN, u32::MIN); - let e = u32x4::new(u32::MAX, u32::MIN, u32::MAX, u32::MIN); + let e = u32x4::new(u32::MAX, 1, u32::MAX, 2); let r: u32x4 = transmute(vbslq_u32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbslq_u64() { - let a = u64x2::new(u64::MAX, 0); + let a = u64x2::new(u64::MAX, 1); let b = u64x2::new(u64::MAX, u64::MAX); let c = u64x2::new(u64::MIN, u64::MIN); - let e = u64x2::new(u64::MAX, u64::MIN); + let e = u64x2::new(u64::MAX, 1); let r: u64x2 = transmute(vbslq_u64(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } #[simd_test(enable = "neon")] unsafe fn test_vbslq_f32() { - let a = u32x4::new(u32::MAX, 0, u32::MAX, 0); - let b = f32x4::new(f32::MAX, f32::MAX, f32::MAX, f32::MAX); - let c = f32x4::new(f32::MIN, f32::MIN, f32::MIN, f32::MIN); - let e = f32x4::new(f32::MAX, f32::MIN, f32::MAX, f32::MIN); + let a = u32x4::new(u32::MAX, 0, 1, 0x80000000); + let b = f32x4::new(-1.23f32, -1.23f32, 8388609f32, -1.23f32); + let c = f32x4::new(2.34f32, 2.34f32, 2097152f32, 2.34f32); + let e = f32x4::new(-1.23f32, 2.34f32, 2097152.25f32, -2.34f32); let r: f32x4 = transmute(vbslq_f32(transmute(a), transmute(b), transmute(c))); assert_eq!(r, e); } @@ -9659,9 +9815,9 @@ mod tests { unsafe fn test_vbslq_p8() { let a = u8x16::new( u8::MAX, - 0, + 1, u8::MAX, - 0, + 2, u8::MAX, 0, u8::MAX, @@ -9713,9 +9869,9 @@ mod tests { ); let e = u8x16::new( u8::MAX, - u8::MIN, + 1, u8::MAX, - u8::MIN, + 2, u8::MAX, u8::MIN, u8::MAX, @@ -9734,7 +9890,7 @@ mod tests { } #[simd_test(enable = "neon")] unsafe fn test_vbslq_p16() { - let a = u16x8::new(u16::MAX, 0, u16::MAX, 0, u16::MAX, 0, u16::MAX, 0); + let a = u16x8::new(u16::MAX, 1, u16::MAX, 2, u16::MAX, 0, u16::MAX, 0); let b = u16x8::new( u16::MAX, u16::MAX, @@ -9757,9 +9913,9 @@ mod tests { ); let e = u16x8::new( u16::MAX, - u16::MIN, + 1, u16::MAX, - u16::MIN, + 2, u16::MAX, u16::MIN, u16::MAX, diff --git a/library/stdarch/crates/core_arch/src/powerpc/altivec.rs b/library/stdarch/crates/core_arch/src/powerpc/altivec.rs index 8b2be39dc..70344c88b 100644 --- a/library/stdarch/crates/core_arch/src/powerpc/altivec.rs +++ b/library/stdarch/crates/core_arch/src/powerpc/altivec.rs @@ -51,6 +51,8 @@ types! { #[allow(improper_ctypes)] extern "C" { + #[link_name = "llvm.ppc.altivec.lvx"] + fn lvx(p: *const i8) -> vector_unsigned_int; #[link_name = "llvm.ppc.altivec.vperm"] fn vperm( a: vector_signed_int, @@ -442,8 +444,7 @@ mod sealed { #[inline(always)] unsafe fn load(off: i32, p: *const i8) -> u32x4 { let addr = p.offset(off as isize); - - *(addr as *const u32x4) + transmute(lvx(addr)) } pub trait VectorLd { diff --git a/library/stdarch/crates/core_arch/src/x86/avx2.rs b/library/stdarch/crates/core_arch/src/x86/avx2.rs index 081609ece..24f9c0301 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx2.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx2.rs @@ -1195,7 +1195,7 @@ pub unsafe fn _mm_mask_i32gather_epi64( /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` should be 1, 2, 4 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i32gather_epi64) #[inline] diff --git a/library/stdarch/crates/core_arch/src/x86/avx512bw.rs b/library/stdarch/crates/core_arch/src/x86/avx512bw.rs index 47d565cea..49d78ed60 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512bw.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512bw.rs @@ -8545,9 +8545,6 @@ pub unsafe fn _mm_movm_epi8(k: __mmask16) -> __m128i { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask32&expand=3207) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(all(test, target_arch = "x86"), assert_instr(add))] -#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(lea))] // generate normal lea/add code instead of kaddd - //llvm.x86.avx512.kadd.d pub unsafe fn _kadd_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(a + b) } @@ -8557,9 +8554,6 @@ pub unsafe fn _kadd_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask64&expand=3208) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(all(test, target_arch = "x86"), assert_instr(add))] -#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(lea))] // generate normal lea/add code instead of kaddd - //llvm.x86.avx512.kadd.d pub unsafe fn _kadd_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(a + b) } @@ -8569,7 +8563,6 @@ pub unsafe fn _kadd_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kand_mask32&expand=3213) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandd pub unsafe fn _kand_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(a & b) } @@ -8579,7 +8572,6 @@ pub unsafe fn _kand_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kand_mask64&expand=3214) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandq pub unsafe fn _kand_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(a & b) } @@ -8607,7 +8599,6 @@ pub unsafe fn _knot_mask64(a: __mmask64) -> __mmask64 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kandn_mask32&expand=3219) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandnd pub unsafe fn _kandn_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(_knot_mask32(a) & b) } @@ -8617,7 +8608,6 @@ pub unsafe fn _kandn_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kandn_mask64&expand=3220) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandnq pub unsafe fn _kandn_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(_knot_mask64(a) & b) } @@ -8627,7 +8617,6 @@ pub unsafe fn _kandn_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kor_mask32&expand=3240) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(or))] // generate normal and code instead of kord pub unsafe fn _kor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(a | b) } @@ -8637,7 +8626,6 @@ pub unsafe fn _kor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kor_mask64&expand=3241) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(or))] // generate normal and code instead of korq pub unsafe fn _kor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(a | b) } @@ -8647,7 +8635,6 @@ pub unsafe fn _kor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxor_mask32&expand=3292) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxord pub unsafe fn _kxor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(a ^ b) } @@ -8657,7 +8644,6 @@ pub unsafe fn _kxor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxor_mask64&expand=3293) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxorq pub unsafe fn _kxor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(a ^ b) } @@ -8667,7 +8653,6 @@ pub unsafe fn _kxor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxnor_mask32&expand=3286) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxnord pub unsafe fn _kxnor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { transmute(_knot_mask32(a ^ b)) } @@ -8677,7 +8662,6 @@ pub unsafe fn _kxnor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxnor_mask64&expand=3287) #[inline] #[target_feature(enable = "avx512bw")] -#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxnorq pub unsafe fn _kxnor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { transmute(_knot_mask64(a ^ b)) } diff --git a/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs b/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs index d8ac5c29c..66fd1c2e1 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs @@ -829,21 +829,21 @@ mod tests { #[target_feature(enable = "sse2")] unsafe fn load_m128i_word(data: &[T], word_index: usize) -> __m128i { let byte_offset = word_index * 16 / size_of::(); - let pointer = data.as_ptr().offset(byte_offset as isize) as *const __m128i; + let pointer = data.as_ptr().add(byte_offset) as *const __m128i; _mm_loadu_si128(black_box(pointer)) } #[target_feature(enable = "avx")] unsafe fn load_m256i_word(data: &[T], word_index: usize) -> __m256i { let byte_offset = word_index * 32 / size_of::(); - let pointer = data.as_ptr().offset(byte_offset as isize) as *const __m256i; + let pointer = data.as_ptr().add(byte_offset) as *const __m256i; _mm256_loadu_si256(black_box(pointer)) } #[target_feature(enable = "avx512f")] unsafe fn load_m512i_word(data: &[T], word_index: usize) -> __m512i { let byte_offset = word_index * 64 / size_of::(); - let pointer = data.as_ptr().offset(byte_offset as isize) as *const i32; + let pointer = data.as_ptr().add(byte_offset) as *const i32; _mm512_loadu_si512(black_box(pointer)) } diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index 2c4295ef6..03c3a14a5 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -1185,9 +1185,9 @@ pub unsafe fn _mm_loadu_ps(p: *const f32) -> __m128 { /// /// ```text /// let a0 = *p; -/// let a1 = *p.offset(1); -/// let a2 = *p.offset(2); -/// let a3 = *p.offset(3); +/// let a1 = *p.add(1); +/// let a2 = *p.add(2); +/// let a3 = *p.add(3); /// __m128::new(a3, a2, a1, a0) /// ``` /// @@ -1241,9 +1241,9 @@ pub unsafe fn _mm_store_ss(p: *mut f32, a: __m128) { /// ```text /// let x = a.extract(0); /// *p = x; -/// *p.offset(1) = x; -/// *p.offset(2) = x; -/// *p.offset(3) = x; +/// *p.add(1) = x; +/// *p.add(2) = x; +/// *p.add(3) = x; /// ``` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps) @@ -1317,9 +1317,9 @@ pub unsafe fn _mm_storeu_ps(p: *mut f32, a: __m128) { /// /// ```text /// *p = a.extract(3); -/// *p.offset(1) = a.extract(2); -/// *p.offset(2) = a.extract(1); -/// *p.offset(3) = a.extract(0); +/// *p.add(1) = a.extract(2); +/// *p.add(2) = a.extract(1); +/// *p.add(3) = a.extract(0); /// ``` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps) @@ -3006,9 +3006,9 @@ mod tests { let unalignment = (p as usize) & 0xf; if unalignment != 0 { - let delta = ((16 - unalignment) >> 2) as isize; + let delta = (16 - unalignment) >> 2; fixup = delta as f32; - p = p.offset(delta); + p = p.add(delta); } let r = _mm_load_ps(p); @@ -3019,7 +3019,7 @@ mod tests { #[simd_test(enable = "sse")] unsafe fn test_mm_loadu_ps() { let vals = &[1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]; - let p = vals.as_ptr().offset(3); + let p = vals.as_ptr().add(3); let r = _mm_loadu_ps(black_box(p)); assert_eq_m128(r, _mm_setr_ps(4.0, 5.0, 6.0, 7.0)); } @@ -3036,9 +3036,9 @@ mod tests { let unalignment = (p as usize) & 0xf; if unalignment != 0 { - let delta = ((16 - unalignment) >> 2) as isize; + let delta = (16 - unalignment) >> 2; fixup = delta as f32; - p = p.offset(delta); + p = p.add(delta); } let r = _mm_loadr_ps(p); @@ -3057,7 +3057,7 @@ mod tests { unsafe fn test_mm_store_ss() { let mut vals = [0.0f32; 8]; let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - _mm_store_ss(vals.as_mut_ptr().offset(1), a); + _mm_store_ss(vals.as_mut_ptr().add(1), a); assert_eq!(vals[0], 0.0); assert_eq!(vals[1], 1.0); @@ -3152,7 +3152,7 @@ mod tests { // Make sure p is **not** aligned to 16-byte boundary if (p as usize) & 0xf == 0 { ofs = 1; - p = p.offset(1); + p = p.add(1); } _mm_storeu_ps(p, *black_box(&a)); diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index 5a9120042..d82b8641f 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -4518,7 +4518,7 @@ mod tests { // Make sure p is **not** aligned to 16-byte boundary if (p as usize) & 0xf == 0 { ofs = 1; - p = p.offset(1); + p = p.add(1); } _mm_storeu_pd(p, *black_box(&a)); @@ -4606,7 +4606,7 @@ mod tests { let mut offset = 0; if (d as usize) & 0xf == 0 { offset = 1; - d = d.offset(offset as isize); + d = d.add(offset); } let r = _mm_loadu_pd(d); diff --git a/library/stdarch/crates/core_arch/src/x86_64/cmpxchg16b.rs b/library/stdarch/crates/core_arch/src/x86_64/cmpxchg16b.rs index 391daed20..a262932af 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/cmpxchg16b.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/cmpxchg16b.rs @@ -34,11 +34,11 @@ use stdarch_test::assert_instr; /// support `cmpxchg16b` and the program enters an execution path that /// eventually would reach this function the behavior is undefined. /// -/// The `success` ordering must also be stronger or equal to `failure`, or this -/// function call is undefined. See the `Atomic*` documentation's -/// `compare_exchange` function for more information. When `compare_exchange` -/// panics, this is undefined behavior. Currently this function aborts the -/// process with an undefined instruction. +/// The failure ordering must be [`Ordering::SeqCst`], [`Ordering::Acquire`] or +/// [`Ordering::Relaxed`], or this function call is undefined. See the `Atomic*` +/// documentation's `compare_exchange` function for more information. When +/// `compare_exchange` panics, this is undefined behavior. Currently this +/// function aborts the process with an undefined instruction. #[inline] #[cfg_attr(test, assert_instr(cmpxchg16b, success = Ordering::SeqCst, failure = Ordering::SeqCst))] #[target_feature(enable = "cmpxchg16b")] @@ -54,15 +54,21 @@ pub unsafe fn cmpxchg16b( debug_assert!(dst as usize % 16 == 0); let (val, _ok) = match (success, failure) { - (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), - (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), + (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), + (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), + (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), + (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), + (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), + (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), + (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), + (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), // The above block is all copied from libcore, and this statement is // also copied from libcore except that it's a panic in libcore and we diff --git a/library/stdarch/crates/intrinsic-test/missing_aarch64.txt b/library/stdarch/crates/intrinsic-test/missing_aarch64.txt index 56ec274b5..93fc126e5 100644 --- a/library/stdarch/crates/intrinsic-test/missing_aarch64.txt +++ b/library/stdarch/crates/intrinsic-test/missing_aarch64.txt @@ -67,20 +67,6 @@ vrnd64xq_f64 vrnd64z_f64 vrnd64zq_f64 -# Takes too long to compile tests -vcopyq_laneq_u8 -vcopyq_laneq_s8 -vcopyq_laneq_p8 -vcopyq_lane_u8 -vcopyq_lane_s8 -vcopyq_lane_p8 -vcopy_laneq_u8 -vcopy_laneq_s8 -vcopy_laneq_p8 -vcopy_lane_u8 -vcopy_lane_s8 -vcopy_lane_p8 - # QEMU 6.0 doesn't support these instructions vmmlaq_s32 vmmlaq_u32 diff --git a/library/stdarch/crates/intrinsic-test/src/argument.rs b/library/stdarch/crates/intrinsic-test/src/argument.rs index f4cb77992..798854c03 100644 --- a/library/stdarch/crates/intrinsic-test/src/argument.rs +++ b/library/stdarch/crates/intrinsic-test/src/argument.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::types::IntrinsicType; +use crate::types::{IntrinsicType, TypeKind}; use crate::Language; /// An argument for the intrinsic. @@ -90,49 +90,108 @@ impl ArgumentList { .join(", ") } - /// Creates a line that initializes this argument for C code. - /// e.g. `int32x2_t a = { 0x1, 0x2 };` - pub fn init_random_values_c(&self, pass: usize) -> String { + /// Creates a line for each argument that initializes an array for C from which `loads` argument + /// values can be loaded as a sliding window. + /// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2. + pub fn gen_arglists_c(&self, loads: u32) -> String { self.iter() .filter_map(|arg| { (!arg.has_constraint()).then(|| { format!( - "{ty} {name} = {{ {values} }};", - ty = arg.to_c_type(), + "const {ty} {name}_vals[] = {{ {values} }};", + ty = arg.ty.c_scalar_type(), name = arg.name, - values = arg.ty.populate_random(pass, &Language::C) + values = arg.ty.populate_random(loads, &Language::C) ) }) }) .collect::>() - .join("\n ") + .join("\n") } - /// Creates a line that initializes this argument for Rust code. - /// e.g. `let a = transmute([0x1, 0x2]);` - pub fn init_random_values_rust(&self, pass: usize) -> String { + /// Creates a line for each argument that initializes an array for Rust from which `loads` argument + /// values can be loaded as a sliding window, e.g `const A_VALS: [u32; 20] = [...];` + pub fn gen_arglists_rust(&self, loads: u32) -> String { self.iter() .filter_map(|arg| { (!arg.has_constraint()).then(|| { - if arg.is_simd() { - format!( - "let {name} = ::std::mem::transmute([{values}]);", - name = arg.name, - values = arg.ty.populate_random(pass, &Language::Rust), - ) - } else { - format!( - "let {name} = {value};", - name = arg.name, - value = arg.ty.populate_random(pass, &Language::Rust) - ) - } + format!( + "const {upper_name}_VALS: [{ty}; {load_size}] = unsafe{{ [{values}] }};", + upper_name = arg.name.to_uppercase(), + ty = arg.ty.rust_scalar_type(), + load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1, + values = arg.ty.populate_random(loads, &Language::Rust) + ) + }) + }) + .collect::>() + .join("\n") + } + + /// Creates a line for each argument that initalizes the argument from an array [arg]_vals at + /// an offset i using a load intrinsic, in C. + /// e.g `uint8x8_t a = vld1_u8(&a_vals[i]);` + pub fn load_values_c(&self, p64_armv7_workaround: bool) -> String { + self.iter() + .filter_map(|arg| { + // The ACLE doesn't support 64-bit polynomial loads on Armv7 + // This and the cast are a workaround for this + let armv7_p64 = if let TypeKind::Poly = arg.ty.kind() { + p64_armv7_workaround + } else { + false + }; + + (!arg.has_constraint()).then(|| { + format!( + "{ty} {name} = {open_cast}{load}(&{name}_vals[i]){close_cast};", + ty = arg.to_c_type(), + name = arg.name, + load = if arg.is_simd() { + arg.ty.get_load_function(p64_armv7_workaround) + } else { + "*".to_string() + }, + open_cast = if armv7_p64 { + format!("cast<{}>(", arg.to_c_type()) + } else { + "".to_string() + }, + close_cast = if armv7_p64 { + ")".to_string() + } else { + "".to_string() + } + ) }) }) .collect::>() .join("\n ") } + /// Creates a line for each argument that initalizes the argument from array [ARG]_VALS at + /// an offset i using a load intrinsic, in Rust. + /// e.g `let a = vld1_u8(A_VALS.as_ptr().offset(i));` + pub fn load_values_rust(&self) -> String { + self.iter() + .filter_map(|arg| { + (!arg.has_constraint()).then(|| { + format!( + "let {name} = {load}({upper_name}_VALS.as_ptr().offset(i));", + name = arg.name, + upper_name = arg.name.to_uppercase(), + load = if arg.is_simd() { + arg.ty.get_load_function(false) + } else { + "*".to_string() + }, + ) + }) + }) + .collect::>() + .join("\n ") + } + pub fn iter(&self) -> std::slice::Iter<'_, Argument> { self.args.iter() } diff --git a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs index 2b7130440..e0645a36b 100644 --- a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs @@ -20,8 +20,9 @@ pub struct Intrinsic { impl Intrinsic { /// Generates a std::cout for the intrinsics results that will match the - /// rust debug output format for the return type. - pub fn print_result_c(&self, index: usize, additional: &str) -> String { + /// rust debug output format for the return type. The generated line assumes + /// there is an int i in scope which is the current pass number. + pub fn print_result_c(&self, additional: &str) -> String { let lanes = if self.results.num_vectors() > 1 { (0..self.results.num_vectors()) .map(|vector| { @@ -72,7 +73,7 @@ impl Intrinsic { }; format!( - r#"std::cout << "Result {additional}-{idx}: {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, + r#"std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, ty = if self.results.is_simd() { format!("{}(", self.results.c_type()) } else { @@ -81,11 +82,31 @@ impl Intrinsic { close = if self.results.is_simd() { ")" } else { "" }, lanes = lanes, additional = additional, - idx = index, ) } - pub fn generate_pass_rust(&self, index: usize, additional: &str) -> String { + pub fn generate_loop_c( + &self, + additional: &str, + passes: u32, + p64_armv7_workaround: bool, + ) -> String { + format!( + r#" {{ + for (int i=0; i<{passes}; i++) {{ + {loaded_args} + auto __return_value = {intrinsic_call}({args}); + {print_result} + }} + }}"#, + loaded_args = self.arguments.load_values_c(p64_armv7_workaround), + intrinsic_call = self.name, + args = self.arguments.as_call_param_c(), + print_result = self.print_result_c(additional) + ) + } + + pub fn generate_loop_rust(&self, additional: &str, passes: u32) -> String { let constraints = self.arguments.as_constraint_parameters_rust(); let constraints = if !constraints.is_empty() { format!("::<{}>", constraints) @@ -93,33 +114,21 @@ impl Intrinsic { constraints }; - format!( - r#" - unsafe {{ - {initialized_args} - let res = {intrinsic_call}{const}({args}); - println!("Result {additional}-{idx}: {{:.150?}}", res); - }}"#, - initialized_args = self.arguments.init_random_values_rust(index), - intrinsic_call = self.name, - args = self.arguments.as_call_param_rust(), - additional = additional, - idx = index, - const = constraints, - ) - } - - pub fn generate_pass_c(&self, index: usize, additional: &str) -> String { format!( r#" {{ - {initialized_args} - auto __return_value = {intrinsic_call}({args}); - {print_result} + for i in 0..{passes} {{ + unsafe {{ + {loaded_args} + let __return_value = {intrinsic_call}{const}({args}); + println!("Result {additional}-{{}}: {{:.150?}}", i+1, __return_value); + }} + }} }}"#, - initialized_args = self.arguments.init_random_values_c(index), + loaded_args = self.arguments.load_values_rust(), intrinsic_call = self.name, - args = self.arguments.as_call_param_c(), - print_result = self.print_result_c(index, additional) + const = constraints, + args = self.arguments.as_call_param_rust(), + additional = additional, ) } } diff --git a/library/stdarch/crates/intrinsic-test/src/main.rs b/library/stdarch/crates/intrinsic-test/src/main.rs index 1b58da2fd..43f2df08b 100644 --- a/library/stdarch/crates/intrinsic-test/src/main.rs +++ b/library/stdarch/crates/intrinsic-test/src/main.rs @@ -23,13 +23,21 @@ mod intrinsic; mod types; mod values; +// The number of times each intrinsic will be called. +const PASSES: u32 = 20; + #[derive(Debug, PartialEq)] pub enum Language { Rust, C, } -fn gen_code_c(intrinsic: &Intrinsic, constraints: &[&Argument], name: String) -> String { +fn gen_code_c( + intrinsic: &Intrinsic, + constraints: &[&Argument], + name: String, + p64_armv7_workaround: bool, +) -> String { if let Some((current, constraints)) = constraints.split_last() { let range = current .constraints @@ -47,19 +55,25 @@ fn gen_code_c(intrinsic: &Intrinsic, constraints: &[&Argument], name: String) -> name = current.name, ty = current.ty.c_type(), val = i, - pass = gen_code_c(intrinsic, constraints, format!("{}-{}", name, i)) + pass = gen_code_c( + intrinsic, + constraints, + format!("{}-{}", name, i), + p64_armv7_workaround + ) ) }) .collect() } else { - (1..20) - .map(|idx| intrinsic.generate_pass_c(idx, &name)) - .collect::>() - .join("\n") + intrinsic.generate_loop_c(&name, PASSES, p64_armv7_workaround) } } -fn generate_c_program(header_files: &[&str], intrinsic: &Intrinsic) -> String { +fn generate_c_program( + header_files: &[&str], + intrinsic: &Intrinsic, + p64_armv7_workaround: bool, +) -> String { let constraints = intrinsic .arguments .iter() @@ -75,7 +89,7 @@ fn generate_c_program(header_files: &[&str], intrinsic: &Intrinsic) -> String { template T1 cast(T2 x) {{ static_assert(sizeof(T1) == sizeof(T2), "sizeof T1 and T2 must be the same"); - T1 ret = 0; + T1 ret{{}}; memcpy(&ret, &x, sizeof(T1)); return ret; }} @@ -95,6 +109,8 @@ std::ostream& operator<<(std::ostream& os, poly128_t value) {{ }} #endif +{arglists} + int main(int argc, char **argv) {{ {passes} return 0; @@ -104,7 +120,13 @@ int main(int argc, char **argv) {{ .map(|header| format!("#include <{}>", header)) .collect::>() .join("\n"), - passes = gen_code_c(intrinsic, constraints.as_slice(), Default::default()), + arglists = intrinsic.arguments.gen_arglists_c(PASSES), + passes = gen_code_c( + intrinsic, + constraints.as_slice(), + Default::default(), + p64_armv7_workaround + ), ) } @@ -131,10 +153,7 @@ fn gen_code_rust(intrinsic: &Intrinsic, constraints: &[&Argument], name: String) }) .collect() } else { - (1..20) - .map(|idx| intrinsic.generate_pass_rust(idx, &name)) - .collect::>() - .join("\n") + intrinsic.generate_loop_rust(&name, PASSES) } } @@ -153,11 +172,14 @@ fn generate_rust_program(intrinsic: &Intrinsic, a32: bool) -> String { #![allow(non_upper_case_globals)] use core_arch::arch::{target_arch}::*; +{arglists} + fn main() {{ {passes} }} "#, target_arch = if a32 { "arm" } else { "aarch64" }, + arglists = intrinsic.arguments.gen_arglists_rust(PASSES), passes = gen_code_rust(intrinsic, &constraints, Default::default()) ) } @@ -203,7 +225,7 @@ fn build_c(intrinsics: &Vec, compiler: &str, a32: bool) -> bool { let c_filename = format!(r#"c_programs/{}.cpp"#, i.name); let mut file = File::create(&c_filename).unwrap(); - let c_code = generate_c_program(&["arm_neon.h", "arm_acle.h"], &i); + let c_code = generate_c_program(&["arm_neon.h", "arm_acle.h"], &i, a32); file.write_all(c_code.into_bytes().as_slice()).unwrap(); compile_c(&c_filename, &i, compiler, a32) }) @@ -259,7 +281,7 @@ path = "{intrinsic}/main.rs""#, .current_dir("rust_programs") .arg("-c") .arg(format!( - "cargo {toolchain} build --target {target}", + "cargo {toolchain} build --target {target} --release", toolchain = toolchain, target = if a32 { "armv7-unknown-linux-gnueabihf" @@ -407,7 +429,7 @@ fn compare_outputs(intrinsics: &Vec, toolchain: &str, runner: &str, a .current_dir("rust_programs") .arg("-c") .arg(format!( - "cargo {toolchain} run --target {target} --bin {intrinsic}", + "cargo {toolchain} run --target {target} --bin {intrinsic} --release", intrinsic = intrinsic.name, toolchain = toolchain, target = if a32 { diff --git a/library/stdarch/crates/intrinsic-test/src/types.rs b/library/stdarch/crates/intrinsic-test/src/types.rs index e51e61649..dd23586e7 100644 --- a/library/stdarch/crates/intrinsic-test/src/types.rs +++ b/library/stdarch/crates/intrinsic-test/src/types.rs @@ -1,7 +1,7 @@ use std::fmt; use std::str::FromStr; -use crate::values::values_for_pass; +use crate::values::value_for_array; use crate::Language; #[derive(Debug, PartialEq, Copy, Clone)] @@ -160,8 +160,7 @@ impl IntrinsicType { } } - #[allow(unused)] - fn c_scalar_type(&self) -> String { + pub fn c_scalar_type(&self) -> String { format!( "{prefix}{bits}_t", prefix = self.kind().c_prefix(), @@ -169,7 +168,7 @@ impl IntrinsicType { ) } - fn rust_scalar_type(&self) -> String { + pub fn rust_scalar_type(&self) -> String { format!( "{prefix}{bits}", prefix = self.kind().rust_prefix(), @@ -289,18 +288,19 @@ impl IntrinsicType { } } - /// Generates a comma list of values that can be used to initialize an - /// argument for the intrinsic call. + /// Generates a comma list of values that can be used to initialize the array that + /// an argument for the intrinsic call is loaded from. /// This is determistic based on the pass number. /// - /// * `pass`: The pass index, i.e. the iteration index for the call to an intrinsic + /// * `loads`: The number of values that need to be loaded from the argument array + /// * e.g for argument type uint32x2, loads=2 results in a string representing 4 32-bit values /// /// Returns a string such as /// * `0x1, 0x7F, 0xFF` if `language` is `Language::C` /// * `0x1 as _, 0x7F as _, 0xFF as _` if `language` is `Language::Rust` - pub fn populate_random(&self, pass: usize, language: &Language) -> String { + pub fn populate_random(&self, loads: u32, language: &Language) -> String { match self { - IntrinsicType::Ptr { child, .. } => child.populate_random(pass, language), + IntrinsicType::Ptr { child, .. } => child.populate_random(loads, language), IntrinsicType::Type { bit_len: Some(bit_len), kind, @@ -308,11 +308,11 @@ impl IntrinsicType { vec_len, .. } if kind == &TypeKind::Int || kind == &TypeKind::UInt || kind == &TypeKind::Poly => (0 - ..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + ..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1)) .map(|i| { format!( "{}{}", - values_for_pass(*bit_len, i, pass), + value_for_array(*bit_len, i), match language { &Language::Rust => format!(" as {ty} ", ty = self.rust_scalar_type()), &Language::C => String::from(""), @@ -327,15 +327,15 @@ impl IntrinsicType { simd_len, vec_len, .. - } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1)) .map(|i| { format!( "{}({})", match language { - &Language::Rust => "f32::from_bits", + &Language::Rust => "std::mem::transmute", &Language::C => "cast", }, - values_for_pass(32, i, pass), + value_for_array(32, i), ) }) .collect::>() @@ -346,15 +346,15 @@ impl IntrinsicType { simd_len, vec_len, .. - } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1))) + } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1)) .map(|i| { format!( "{}({}{})", match language { - &Language::Rust => "f64::from_bits", + &Language::Rust => "std::mem::transmute", &Language::C => "cast", }, - values_for_pass(64, i, pass), + value_for_array(64, i), match language { &Language::Rust => " as u64", &Language::C => "", @@ -368,10 +368,9 @@ impl IntrinsicType { } /// Determines the load function for this type. - #[allow(unused)] - pub fn get_load_function(&self) -> String { + pub fn get_load_function(&self, armv7_p64_workaround: bool) -> String { match self { - IntrinsicType::Ptr { child, .. } => child.get_load_function(), + IntrinsicType::Ptr { child, .. } => child.get_load_function(armv7_p64_workaround), IntrinsicType::Type { kind: k, bit_len: Some(bl), @@ -379,7 +378,7 @@ impl IntrinsicType { vec_len, .. } => { - let quad = if (simd_len.unwrap_or(1) * bl) > 64 { + let quad = if simd_len.unwrap_or(1) * bl > 64 { "q" } else { "" @@ -390,7 +389,8 @@ impl IntrinsicType { TypeKind::UInt => "u", TypeKind::Int => "s", TypeKind::Float => "f", - TypeKind::Poly => "p", + // The ACLE doesn't support 64-bit polynomial loads on Armv7 + TypeKind::Poly => if armv7_p64_workaround && *bl == 64 {"s"} else {"p"}, x => todo!("get_load_function TypeKind: {:#?}", x), }, size = bl, diff --git a/library/stdarch/crates/intrinsic-test/src/values.rs b/library/stdarch/crates/intrinsic-test/src/values.rs index 4565edca0..64b4d9fc9 100644 --- a/library/stdarch/crates/intrinsic-test/src/values.rs +++ b/library/stdarch/crates/intrinsic-test/src/values.rs @@ -1,9 +1,8 @@ -/// Gets a hex constant value for a single lane in in a determistic way +/// Gets a hex constant value for a single value in the argument values array in a determistic way /// * `bits`: The number of bits for the type, only 8, 16, 32, 64 are valid values -/// * `simd`: The index of the simd lane we are generating for -/// * `pass`: The index of the pass we are generating the values for -pub fn values_for_pass(bits: u32, simd: u32, pass: usize) -> String { - let index = pass + (simd as usize); +/// * `index`: The position in the array we are generating for +pub fn value_for_array(bits: u32, index: u32) -> String { + let index = index as usize; if bits == 8 { format!("{:#X}", VALUES_8[index % VALUES_8.len()]) diff --git a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs index f32f961ae..5f46c7696 100644 --- a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs +++ b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs @@ -72,7 +72,8 @@ features! { @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pmull: "pmull"; /// FEAT_PMULL (Polynomial Multiply) @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp: "fp"; - /// FEAT_FP (Floating point support) + implied by target_features: ["neon"]; + /// FEAT_FP (Floating point support) - Implied by `neon` target_feature @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp16: "fp16"; /// FEAT_FP16 (Half-float support) @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve: "sve"; diff --git a/library/stdarch/crates/std_detect/src/detect/macros.rs b/library/stdarch/crates/std_detect/src/detect/macros.rs index 7548c9780..a467f9db6 100644 --- a/library/stdarch/crates/std_detect/src/detect/macros.rs +++ b/library/stdarch/crates/std_detect/src/detect/macros.rs @@ -1,3 +1,15 @@ +#[macro_export] +#[allow_internal_unstable(stdsimd)] +macro_rules! detect_feature { + ($feature:tt, $feature_lit:tt) => { + $crate::detect_feature!($feature, $feature_lit : $feature_lit) + }; + ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { + $(cfg!(target_feature = $target_feature_lit) ||)* + $crate::detect::__is_feature_detected::$feature() + }; +} + #[allow(unused)] macro_rules! features { ( @@ -7,7 +19,9 @@ macro_rules! features { @MACRO_ATTRS: $(#[$macro_attrs:meta])* $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; )* $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )* - $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; $(#[$feature_comment:meta])*)* + $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; + $(implied by target_features: [$($target_feature_lit:tt),*];)? + $(#[$feature_comment:meta])*)* ) => { #[macro_export] $(#[$macro_attrs])* @@ -17,12 +31,11 @@ macro_rules! features { macro_rules! $macro_name { $( ($feature_lit) => { - cfg!(target_feature = $feature_lit) || - $crate::detect::__is_feature_detected::$feature() + $crate::detect_feature!($feature, $feature_lit $(: $($target_feature_lit),*)?) }; )* $( - ($bind_feature) => { $macro_name!($feature_impl) }; + ($bind_feature) => { $crate::$macro_name!($feature_impl) }; )* $( ($nort_feature) => { @@ -35,7 +48,7 @@ macro_rules! features { }; )* ($t:tt,) => { - $macro_name!($t); + $crate::$macro_name!($t); }; ($t:tt) => { compile_error!( @@ -66,7 +79,7 @@ macro_rules! features { }; )* $( - ($bind_feature) => { $macro_name!($feature_impl) }; + ($bind_feature) => { $crate::$macro_name!($feature_impl) }; )* $( ($nort_feature) => { @@ -79,7 +92,7 @@ macro_rules! features { }; )* ($t:tt,) => { - $macro_name!($t); + $crate::$macro_name!($t); }; ($t:tt) => { compile_error!( diff --git a/library/stdarch/crates/stdarch-gen/neon.spec b/library/stdarch/crates/stdarch-gen/neon.spec index 68a50fbe9..95fbc354c 100644 --- a/library/stdarch/crates/stdarch-gen/neon.spec +++ b/library/stdarch/crates/stdarch-gen/neon.spec @@ -1570,10 +1570,10 @@ name = vext constn = N multi_fn = static_assert_imm-out_exp_len-N multi_fn = matchn-out_exp_len-N, simd_shuffle-out_len-!, a, b, {asc-n-out_len} -a = 0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15 -b = 9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11 -n = HFLEN -validate 8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19 +a = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +n = LEN_M1 +validate 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 arm = "vext.8" aarch64 = ext @@ -1584,10 +1584,10 @@ name = vext constn = N multi_fn = static_assert_imm-out_exp_len-N multi_fn = matchn-out_exp_len-N, simd_shuffle-out_len-!, a, b, {asc-n-out_len} -a = 0, 8, 8, 9, 8, 9, 9, 11, 8, 9, 9, 11, 9, 11, 14, 15 -b = 9, 11, 14, 15, 16, 17, 18, 19, 0, 8, 8, 9, 8, 9, 9, 11 -n = HFLEN -validate 8, 9, 9, 11, 9, 11, 14, 15, 9, 11, 14, 15, 16, 17, 18, 19 +a = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +b = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +n = LEN_M1 +validate 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 aarch64 = ext generate poly64x2_t @@ -1600,10 +1600,10 @@ name = vext constn = N multi_fn = static_assert_imm-out_exp_len-N multi_fn = matchn-out_exp_len-N, simd_shuffle-out_len-!, a, b, {asc-n-out_len} -a = 0., 2., 2., 3. -b = 3., 4., 5., 6., -n = HFLEN -validate 2., 3., 3., 4. +a = 1., 1., 1., 1. +b = 2., 2., 2., 2., +n = LEN_M1 +validate 1., 2., 2., 2. aarch64 = ext generate float64x2_t diff --git a/library/stdarch/crates/stdarch-gen/src/main.rs b/library/stdarch/crates/stdarch-gen/src/main.rs index a2ae250a7..d2f865753 100644 --- a/library/stdarch/crates/stdarch-gen/src/main.rs +++ b/library/stdarch/crates/stdarch-gen/src/main.rs @@ -856,6 +856,40 @@ fn type_len_str(t: &str) -> &'static str { } } +fn type_len_minus_one_str(t: &str) -> &'static str { + match t { + "int8x8_t" => "7", + "int8x16_t" => "15", + "int16x4_t" => "3", + "int16x8_t" => "7", + "int32x2_t" => "1", + "int32x4_t" => "3", + "int64x1_t" => "0", + "int64x2_t" => "1", + "uint8x8_t" => "7", + "uint8x16_t" => "15", + "uint16x4_t" => "3", + "uint16x8_t" => "7", + "uint32x2_t" => "1", + "uint32x4_t" => "3", + "uint64x1_t" => "0", + "uint64x2_t" => "1", + "float16x4_t" => "3", + "float16x8_t" => "7", + "float32x2_t" => "1", + "float32x4_t" => "3", + "float64x1_t" => "0", + "float64x2_t" => "1", + "poly8x8_t" => "7", + "poly8x16_t" => "15", + "poly16x4_t" => "3", + "poly16x8_t" => "7", + "poly64x1_t" => "0", + "poly64x2_t" => "1", + _ => panic!("unknown type: {}", t), + } +} + fn type_half_len_str(t: &str) -> &'static str { match t { "int8x8_t" => "4", @@ -901,6 +935,7 @@ fn map_val<'v>(t: &str, v: &'v str) -> &'v str { "BITS_M1" => bits_minus_one(t), "HFBITS" => half_bits(t), "LEN" => type_len_str(t), + "LEN_M1" => type_len_minus_one_str(t), "HFLEN" => type_half_len_str(t), o => o, } @@ -971,6 +1006,15 @@ fn is_vstx(name: &str) -> bool { && (s[1].starts_with("s") || s[1].starts_with("f")) } +fn create_doc_string(comment_string: &str, fn_name: &str) -> String { + format!( + r#"{} +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/{})"#, + comment_string, fn_name + ) +} + #[allow(clippy::too_many_arguments)] fn gen_aarch64( current_comment: &str, @@ -1374,6 +1418,7 @@ fn gen_aarch64( RDM => String::from("\n#[stable(feature = \"rdm_intrinsics\", since = \"1.62.0\")]"), _ => String::new(), }; + let function_doc = create_doc_string(current_comment, &name); let function = format!( r#" {} @@ -1384,7 +1429,7 @@ fn gen_aarch64( {} }} "#, - current_comment, + function_doc, current_target, current_aarch64, const_assert, @@ -2342,6 +2387,7 @@ fn gen_arm( RDM => String::from("\n#[stable(feature = \"rdm_intrinsics\", since = \"1.62.0\")]"), _ => String::new(), }; + let function_doc = create_doc_string(current_comment, &name); format!( r#" {} @@ -2358,13 +2404,13 @@ fn gen_arm( #[cfg_attr(test, assert_instr({}{}))]{}{} {} "#, - current_comment, + function_doc, current_target_arm, expand_intrinsic(¤t_arm, in_t[1]), const_assert, const_legacy, call_arm, - current_comment, + function_doc, current_target_aarch64, expand_intrinsic(¤t_aarch64, in_t[1]), const_assert, @@ -2410,6 +2456,7 @@ fn gen_arm( RDM => String::from("\n#[cfg_attr(target_arch = \"aarch64\", stable(feature = \"rdm_intrinsics\", since = \"1.62.0\"))]"), _ => String::new(), }; + let function_doc = create_doc_string(current_comment, &name); format!( r#" {} @@ -2420,7 +2467,7 @@ fn gen_arm( #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr({}{}))]{}{} {} "#, - current_comment, + function_doc, current_target_aarch64, current_target_arm, expand_intrinsic(¤t_arm, in_t[1]), diff --git a/library/stdarch/examples/hex.rs b/library/stdarch/examples/hex.rs index 812836d66..d982a71b9 100644 --- a/library/stdarch/examples/hex.rs +++ b/library/stdarch/examples/hex.rs @@ -76,7 +76,7 @@ unsafe fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a s let ascii_a = _mm256_set1_epi8((b'a' - 9 - 1) as i8); let and4bits = _mm256_set1_epi8(0xf); - let mut i = 0_isize; + let mut i = 0_usize; while src.len() >= 32 { let invec = _mm256_loadu_si256(src.as_ptr() as *const _); @@ -96,18 +96,17 @@ unsafe fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a s let res2 = _mm256_unpackhi_epi8(masked2, masked1); // Store everything into the right destination now - let base = dst.as_mut_ptr().offset(i * 2); - let base1 = base.offset(0) as *mut _; - let base2 = base.offset(16) as *mut _; - let base3 = base.offset(32) as *mut _; - let base4 = base.offset(48) as *mut _; + let base = dst.as_mut_ptr().add(i * 2); + let base1 = base.add(0) as *mut _; + let base2 = base.add(16) as *mut _; + let base3 = base.add(32) as *mut _; + let base4 = base.add(48) as *mut _; _mm256_storeu2_m128i(base3, base1, res1); _mm256_storeu2_m128i(base4, base2, res2); src = &src[32..]; i += 32; } - let i = i as usize; let _ = hex_encode_sse41(src, &mut dst[i * 2..]); Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) @@ -122,7 +121,7 @@ unsafe fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a let ascii_a = _mm_set1_epi8((b'a' - 9 - 1) as i8); let and4bits = _mm_set1_epi8(0xf); - let mut i = 0_isize; + let mut i = 0_usize; while src.len() >= 16 { let invec = _mm_loadu_si128(src.as_ptr() as *const _); @@ -141,13 +140,12 @@ unsafe fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a let res1 = _mm_unpacklo_epi8(masked2, masked1); let res2 = _mm_unpackhi_epi8(masked2, masked1); - _mm_storeu_si128(dst.as_mut_ptr().offset(i * 2) as *mut _, res1); - _mm_storeu_si128(dst.as_mut_ptr().offset(i * 2 + 16) as *mut _, res2); + _mm_storeu_si128(dst.as_mut_ptr().add(i * 2) as *mut _, res1); + _mm_storeu_si128(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2); src = &src[16..]; i += 16; } - let i = i as usize; let _ = hex_encode_fallback(src, &mut dst[i * 2..]); Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) @@ -163,7 +161,7 @@ unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&' let ascii_a = u8x16_splat(b'a' - 9 - 1); let and4bits = u8x16_splat(0xf); - let mut i = 0_isize; + let mut i = 0_usize; while src.len() >= 16 { let invec = v128_load(src.as_ptr() as *const _); @@ -189,13 +187,12 @@ unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&' masked2, masked1, ); - v128_store(dst.as_mut_ptr().offset(i * 2) as *mut _, res1); - v128_store(dst.as_mut_ptr().offset(i * 2 + 16) as *mut _, res2); + v128_store(dst.as_mut_ptr().add(i * 2) as *mut _, res1); + v128_store(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2); src = &src[16..]; i += 16; } - let i = i as usize; let _ = hex_encode_fallback(src, &mut dst[i * 2..]); Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 40b05704b..b33b08012 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -14,7 +14,7 @@ pub trait Stats { /// Sum of the samples. /// /// Note: this method sacrifices performance at the altar of accuracy - /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: + /// Depends on IEEE 754 arithmetic guarantees. See proof of correctness at: /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric /// Predicates"][paper] /// diff --git a/library/test/src/term/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index 694473f52..355859019 100644 --- a/library/test/src/term/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -80,6 +80,17 @@ impl TermInfo { /// Creates a TermInfo for the named terminal. pub(crate) fn from_name(name: &str) -> Result { + if cfg!(miri) { + // Avoid all the work of parsing the terminfo (it's pretty slow under Miri), and just + // assume that the standard color codes work (like e.g. the 'colored' crate). + return Ok(TermInfo { + names: Default::default(), + bools: Default::default(), + numbers: Default::default(), + strings: Default::default(), + }); + } + get_dbpath_for_term(name) .ok_or_else(|| { Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found")) @@ -119,6 +130,12 @@ pub(crate) struct TerminfoTerminal { impl Terminal for TerminfoTerminal { fn fg(&mut self, color: color::Color) -> io::Result { let color = self.dim_if_necessary(color); + if cfg!(miri) && color < 8 { + // The Miri logic for this only works for the most basic 8 colors, which we just assume + // the terminal will support. (`num_colors` is always 0 in Miri, so higher colors will + // just fail. But libtest doesn't use any higher colors anyway.) + return write!(self.out, "\x1B[3{color}m").and(Ok(true)); + } if self.num_colors > color { return self.apply_cap("setaf", &[Param::Number(color as i32)]); } @@ -126,6 +143,9 @@ impl Terminal for TerminfoTerminal { } fn reset(&mut self) -> io::Result { + if cfg!(miri) { + return write!(self.out, "\x1B[0m").and(Ok(true)); + } // are there any terminals that have color/attrs and not sgr0? // Try falling back to sgr, then op let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) { diff --git a/library/unwind/build.rs b/library/unwind/build.rs index f88e6a924..31af39025 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -2,8 +2,14 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); - let target = env::var("TARGET").expect("TARGET was not set"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_MIRI"); + + if env::var_os("CARGO_CFG_MIRI").is_some() { + // Miri doesn't need the linker flags or a libunwind build. + return; + } + let target = env::var("TARGET").expect("TARGET was not set"); if target.contains("android") { let build = cc::Build::new(); @@ -13,13 +19,8 @@ fn main() { let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler"); if has_unwind { - println!("cargo:rustc-link-lib=unwind"); - } else { - println!("cargo:rustc-link-lib=gcc"); + println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\""); } - - // Android's unwinding library depends on dl_iterate_phdr in `libdl`. - println!("cargo:rustc-link-lib=dl"); } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("netbsd") { diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 4a6ba6e10..46fe50cb9 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -55,6 +55,26 @@ cfg_if::cfg_if! { } } +#[cfg(target_os = "android")] +cfg_if::cfg_if! { + if #[cfg(feature = "llvm-libunwind")] { + compile_error!("`llvm-libunwind` is not supported for Android targets"); + } else if #[cfg(feature = "system-llvm-libunwind")] { + #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] + #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } else { + #[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] + #[link(name = "gcc", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } +} +// Android's unwinding library depends on dl_iterate_phdr in `libdl`. +#[cfg(target_os = "android")] +#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "dl", cfg(not(target_feature = "crt-static")))] +extern "C" {} + // When building with crt-static, we get `gcc_eh` from the `libc` crate, since // glibc needs it, and needs it listed later on the linker command line. We // don't want to duplicate it here. diff --git a/src/README.md b/src/README.md index 9752bc3f6..3d2e6acd5 100644 --- a/src/README.md +++ b/src/README.md @@ -2,7 +2,7 @@ This directory contains the source code of the rust project, including: - The test suite - The bootstrapping build system -- Various submodules for tools, like rustdoc, rls, etc. +- Various submodules for tools, like cargo, miri, etc. For more information on how various parts of the compiler work, see the [rustc dev guide]. diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 664ffa1dd..84c06fdce 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -53,7 +53,6 @@ dependencies = [ "hex", "ignore", "libc", - "num_cpus", "once_cell", "opener", "pretty_assertions", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 84f6aaf99..95e711737 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -38,7 +38,6 @@ test = false cmake = "0.1.38" fd-lock = "3.0.6" filetime = "0.2" -num_cpus = "1.0" getopts = "0.2.19" cc = "1.0.69" libc = "0.2" @@ -68,6 +67,7 @@ features = [ "psapi", "impl-default", "timezoneapi", + "winbase", ] [dev-dependencies] diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 40a3cc6d1..e96f8b0d3 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -25,10 +25,11 @@ use std::time::Instant; fn main() { let args = env::args_os().skip(1).collect::>(); + let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str()); + let target = arg("--target"); let version = args.iter().find(|w| &**w == "-vV"); let verbose = match env::var("RUSTC_VERBOSE") { @@ -59,8 +60,7 @@ fn main() { cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. - let crate_name = - args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str()); + let crate_name = arg("--crate-name"); if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { @@ -106,6 +106,15 @@ fn main() { { cmd.arg("-C").arg("panic=abort"); } + + // `-Ztls-model=initial-exec` must not be applied to proc-macros, see + // issue https://github.com/rust-lang/rust/issues/100530 + if env::var("RUSTC_TLS_MODEL_INITIAL_EXEC").is_ok() + && arg("--crate-type") != Some("proc-macro") + && !matches!(crate_name, Some("proc_macro2" | "quote" | "syn" | "synstructure")) + { + cmd.arg("-Ztls-model=initial-exec"); + } } else { // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars // here, but rather Cargo should know what flags to pass rustc itself. @@ -130,10 +139,8 @@ fn main() { // Cargo doesn't pass RUSTFLAGS to proc_macros: // https://github.com/rust-lang/cargo/issues/4423 // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. - // We also declare that the flag is expected, which is mainly needed for - // later stages so that they don't warn about #[cfg(bootstrap)], - // but enabling it for stage 0 too lets any warnings, if they occur, - // occur more early on, e.g. about #[cfg(bootstrap = "foo")]. + // We also declare that the flag is expected, which we need to do to not + // get warnings about it being unexpected. if stage == "0" { cmd.arg("--cfg=bootstrap"); } diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 87c1d22e7..e69cab956 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -11,6 +11,7 @@ include!("../dylib_util.rs"); fn main() { let args = env::args_os().skip(1).collect::>(); + let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); @@ -62,6 +63,16 @@ fn main() { cmd.arg("-Clink-arg=-Wl,--threads=1"); } } + // Cargo doesn't pass RUSTDOCFLAGS to proc_macros: + // https://github.com/rust-lang/cargo/issues/4423 + // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. + // We also declare that the flag is expected, which we need to do to not + // get warnings about it being unexpected. + if stage == "0" { + cmd.arg("--cfg=bootstrap"); + } + cmd.arg("-Zunstable-options"); + cmd.arg("--check-cfg=values(bootstrap)"); if verbose > 1 { eprintln!( diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 03eec02a8..cc08ae5f9 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -85,7 +85,7 @@ def _download(path, url, probably_big, verbose, exception): option = "-#" else: option = "-s" - # If curl is not present on Win32, we shoud not sys.exit + # If curl is not present on Win32, we should not sys.exit # but raise `CalledProcessError` or `OSError` instead require(["curl", "--version"], exception=platform_is_win32) run(["curl", option, diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0ab4824ac..14e8ebd68 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -647,9 +647,9 @@ impl<'a> Builder<'a> { test::CrateRustdocJsonTypes, test::Linkcheck, test::TierCheck, + test::ReplacePlaceholderTest, test::Cargotest, test::Cargo, - test::Rls, test::RustAnalyzer, test::ErrorIndex, test::Distcheck, @@ -736,7 +736,6 @@ impl<'a> Builder<'a> { install::Docs, install::Std, install::Cargo, - install::Rls, install::RustAnalyzer, install::Rustfmt, install::RustDemangler, @@ -746,7 +745,12 @@ impl<'a> Builder<'a> { install::Src, install::Rustc ), - Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0), + Kind::Run => describe!( + run::ExpandYamlAnchors, + run::BuildManifest, + run::BumpStage0, + run::ReplaceVersionPlaceholder, + ), // These commands either don't use paths, or they're special-cased in Build::build() Kind::Clean | Kind::Format | Kind::Setup => vec![], } @@ -942,7 +946,7 @@ impl<'a> Builder<'a> { }; patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]); if !fname.extension().map_or(false, |ext| ext == "so") { - // Finally, set the corret .interp for binaries + // Finally, set the correct .interp for binaries let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker"); // FIXME: can we support utf8 here? `args` doesn't accept Vec, only OsString ... let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path)))); @@ -958,7 +962,7 @@ impl<'a> Builder<'a> { let tempfile = self.tempdir().join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might // need to download components from other protocols. The match allows them adding more - // protocols without worrying about merge conficts if we change the HTTP implementation. + // protocols without worrying about merge conflicts if we change the HTTP implementation. match url.split_once("://").map(|(proto, _)| proto) { Some("http") | Some("https") => { self.download_http_with_retries(&tempfile, url, help_on_error) @@ -1759,23 +1763,21 @@ impl<'a> Builder<'a> { }, ); - if !target.contains("windows") { - let needs_unstable_opts = target.contains("linux") - || target.contains("solaris") - || target.contains("windows") - || target.contains("bsd") - || target.contains("dragonfly") - || target.contains("illumos"); + let split_debuginfo_is_stable = target.contains("linux") + || target.contains("apple") + || (target.contains("msvc") + && self.config.rust_split_debuginfo == SplitDebuginfo::Packed) + || (target.contains("windows") + && self.config.rust_split_debuginfo == SplitDebuginfo::Off); - if needs_unstable_opts { - rustflags.arg("-Zunstable-options"); - } - match self.config.rust_split_debuginfo { - SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"), - SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"), - SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"), - }; + if !split_debuginfo_is_stable { + rustflags.arg("-Zunstable-options"); } + match self.config.rust_split_debuginfo { + SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"), + SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"), + SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"), + }; if self.config.cmd.bless() { // Bless `expect!` tests. @@ -1850,7 +1852,7 @@ impl<'a> Builder<'a> { // so we can't use it by default in general, but we can use it for tools // and our own internal libraries. if !mode.must_support_dlopen() && !target.triple.starts_with("powerpc-") { - rustflags.arg("-Ztls-model=initial-exec"); + cargo.env("RUSTC_TLS_MODEL_INITIAL_EXEC", "1"); } if self.config.incremental { diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index c084e77d3..280eba75f 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -547,7 +547,6 @@ mod dist { config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], - skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, @@ -618,7 +617,6 @@ mod dist { let mut config = configure(&["A"], &["A"]); config.cmd = Subcommand::Test { paths: vec![], - skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 4e1e8ef9d..5c085bedf 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -457,7 +457,7 @@ tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InT // rejected. tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule); -tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule); +tool_check_step!(Rls, "src/tools/rls", SourceType::InTree); tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree); tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index dd2b9d593..c13e83f6c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -658,7 +658,12 @@ impl Step for Rustc { // With LLD, we can use ICF (identical code folding) to reduce the executable size // of librustc_driver/rustc and to improve i-cache utilization. - if builder.config.use_lld { + // + // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF) + // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: + // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 + // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 + if builder.config.use_lld && !compiler.host.contains("msvc") { cargo.rustflag("-Clink-args=-Wl,--icf=all"); } @@ -1276,7 +1281,9 @@ impl Step for Assemble { compiler: build_compiler, target: target_compiler.host, }); - builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host))); + for name in crate::LLD_FILE_NAMES { + builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host))); + } } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4325a237c..f1a150e0f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -388,6 +388,7 @@ impl PartialEq<&str> for TargetSelection { pub struct Target { /// Some(path to llvm-config) if using an external LLVM. pub llvm_config: Option, + pub llvm_has_rust_patches: Option, /// Some(path to FileCheck) if one was specified. pub llvm_filecheck: Option, pub llvm_libunwind: Option, @@ -733,6 +734,7 @@ define_config! { default_linker: Option = "default-linker", linker: Option = "linker", llvm_config: Option = "llvm-config", + llvm_has_rust_patches: Option = "llvm-has-rust-patches", llvm_filecheck: Option = "llvm-filecheck", llvm_libunwind: Option = "llvm-libunwind", android_ndk: Option = "android-ndk", @@ -990,42 +992,7 @@ impl Config { config.llvm_from_ci = match llvm.download_ci_llvm { Some(StringOrBool::String(s)) => { assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s); - // This is currently all tier 1 targets and tier 2 targets with host tools - // (since others may not have CI artifacts) - // https://doc.rust-lang.org/rustc/platform-support.html#tier-1 - // FIXME: this is duplicated in bootstrap.py - let supported_platforms = [ - // tier 1 - "aarch64-unknown-linux-gnu", - "i686-pc-windows-gnu", - "i686-pc-windows-msvc", - "i686-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-pc-windows-gnu", - "x86_64-pc-windows-msvc", - // tier 2 with host tools - "aarch64-apple-darwin", - "aarch64-pc-windows-msvc", - "aarch64-unknown-linux-musl", - "arm-unknown-linux-gnueabi", - "arm-unknown-linux-gnueabihf", - "armv7-unknown-linux-gnueabihf", - "mips-unknown-linux-gnu", - "mips64-unknown-linux-gnuabi64", - "mips64el-unknown-linux-gnuabi64", - "mipsel-unknown-linux-gnu", - "powerpc-unknown-linux-gnu", - "powerpc64-unknown-linux-gnu", - "powerpc64le-unknown-linux-gnu", - "riscv64gc-unknown-linux-gnu", - "s390x-unknown-linux-gnu", - "x86_64-unknown-freebsd", - "x86_64-unknown-illumos", - "x86_64-unknown-linux-musl", - "x86_64-unknown-netbsd", - ]; - supported_platforms.contains(&&*config.build.triple) + crate::native::is_ci_llvm_available(&config, llvm_assertions.unwrap_or(false)) } Some(StringOrBool::Bool(b)) => b, None => false, @@ -1144,6 +1111,7 @@ impl Config { if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); } + target.llvm_has_rust_patches = cfg.llvm_has_rust_patches; if let Some(ref s) = cfg.llvm_filecheck { target.llvm_filecheck = Some(config.src.join(s)); } @@ -1176,6 +1144,7 @@ impl Config { if config.llvm_from_ci { let triple = &config.build.triple; + let ci_llvm_bin = config.ci_llvm_root().join("bin"); let mut build_target = config .target_config .entry(config.build) @@ -1183,7 +1152,6 @@ impl Config { check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); - let ci_llvm_bin = config.out.join(&*config.build.triple).join("ci-llvm/bin"); build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build))); build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); } @@ -1312,11 +1280,21 @@ impl Config { git } - pub(crate) fn artifact_channel(&self, commit: &str) -> String { + pub(crate) fn artifact_version_part(&self, commit: &str) -> String { let mut channel = self.git(); channel.arg("show").arg(format!("{}:src/ci/channel", commit)); let channel = output(&mut channel); - channel.trim().to_owned() + + let mut version = self.git(); + version.arg("show").arg(format!("{}:src/version", commit)); + let version = output(&mut version); + + match channel.trim() { + "stable" => version.trim().to_owned(), + "beta" => channel.trim().to_owned(), + "nightly" => channel.trim().to_owned(), + other => unreachable!("{:?} is not recognized as a valid channel", other), + } } /// Try to find the relative path of `bindir`, otherwise return it in full. @@ -1445,7 +1423,11 @@ impl Config { .get(&target) .and_then(|t| t.llvm_libunwind) .or(self.llvm_libunwind_default) - .unwrap_or(LlvmLibunwind::No) + .unwrap_or(if target.contains("fuchsia") { + LlvmLibunwind::InTree + } else { + LlvmLibunwind::No + }) } pub fn submodules(&self, rust_info: &GitInfo) -> bool { @@ -1461,7 +1443,7 @@ fn set(field: &mut T, val: Option) { fn threads_from_config(v: u32) -> u32 { match v { - 0 => num_cpus::get() as u32, + 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, n => n, } } @@ -1554,7 +1536,7 @@ fn maybe_download_rustfmt(builder: &Builder<'_>) -> Option { fn download_ci_rustc(builder: &Builder<'_>, commit: &str) { builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})")); - let channel = builder.config.artifact_channel(commit); + let version = builder.config.artifact_version_part(commit); let host = builder.config.build.triple; let bin_root = builder.out.join(host).join("ci-rustc"); let rustc_stamp = bin_root.join(".rustc-stamp"); @@ -1563,13 +1545,13 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) { if bin_root.exists() { t!(fs::remove_dir_all(&bin_root)); } - let filename = format!("rust-std-{channel}-{host}.tar.xz"); + let filename = format!("rust-std-{version}-{host}.tar.xz"); let pattern = format!("rust-std-{host}"); download_ci_component(builder, filename, &pattern, commit); - let filename = format!("rustc-{channel}-{host}.tar.xz"); + let filename = format!("rustc-{version}-{host}.tar.xz"); download_ci_component(builder, filename, "rustc", commit); // download-rustc doesn't need its own cargo, it can just use beta's. - let filename = format!("rustc-dev-{channel}-{host}.tar.xz"); + let filename = format!("rustc-dev-{version}-{host}.tar.xz"); download_ci_component(builder, filename, "rustc-dev", commit); builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc")); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6291b204e..1a59b3958 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -423,8 +423,11 @@ impl Step for Rustc { let gcc_lld_src_dir = src_dir.join("gcc-ld"); let gcc_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&gcc_lld_dst_dir)); - let exe_name = exe("ld", compiler.host); - builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); + for name in crate::LLD_FILE_NAMES { + let exe_name = exe(name, compiler.host); + builder + .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); + } } // Man pages @@ -1018,10 +1021,7 @@ impl Step for Rls { let rls = builder .ensure(tool::Rls { compiler, target, extra_features: Vec::new() }) - .or_else(|| { - missing_tool("RLS", builder.build.config.missing_tools); - None - })?; + .expect("rls expected to build"); let mut tarball = Tarball::new(builder, "rls", &target.triple); tarball.set_overlay(OverlayKind::RLS); @@ -1226,17 +1226,10 @@ impl Step for Rustfmt { let rustfmt = builder .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() }) - .or_else(|| { - missing_tool("Rustfmt", builder.build.config.missing_tools); - None - })?; + .expect("rustfmt expected to build - essential tool"); let cargofmt = builder .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() }) - .or_else(|| { - missing_tool("Cargofmt", builder.build.config.missing_tools); - None - })?; - + .expect("cargo fmt expected to build - essential tool"); let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); tarball.set_overlay(OverlayKind::Rustfmt); tarball.is_preview(true); @@ -1419,7 +1412,7 @@ impl Step for Extended { let xform = |p: &Path| { let mut contents = t!(fs::read_to_string(p)); - for tool in &["rust-demangler", "rls", "rust-analyzer", "miri", "rustfmt"] { + for tool in &["rust-demangler", "rust-analyzer", "miri", "rustfmt"] { if !built_tools.contains(tool) { contents = filter(&contents, tool); } @@ -1459,7 +1452,7 @@ impl Step for Extended { prepare("rust-std"); prepare("rust-analysis"); prepare("clippy"); - for tool in &["rust-docs", "rust-demangler", "rls", "rust-analyzer", "miri"] { + for tool in &["rust-docs", "rust-demangler", "rust-analyzer", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1495,8 +1488,6 @@ impl Step for Extended { builder.create_dir(&exe.join(name)); let dir = if name == "rust-std" || name == "rust-analysis" { format!("{}-{}", name, target.triple) - } else if name == "rls" { - "rls-preview".to_string() } else if name == "rust-analyzer" { "rust-analyzer-preview".to_string() } else if name == "clippy" { @@ -1520,7 +1511,7 @@ impl Step for Extended { prepare("rust-docs"); prepare("rust-std"); prepare("clippy"); - for tool in &["rust-demangler", "rls", "rust-analyzer", "miri"] { + for tool in &["rust-demangler", "rust-analyzer", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1604,25 +1595,6 @@ impl Step for Extended { .arg("-out") .arg(exe.join("StdGroup.wxs")), ); - if built_tools.contains("rls") { - builder.run( - Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rls") - .args(&heat_flags) - .arg("-cg") - .arg("RlsGroup") - .arg("-dr") - .arg("Rls") - .arg("-var") - .arg("var.RlsDir") - .arg("-out") - .arg(exe.join("RlsGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - } if built_tools.contains("rust-analyzer") { builder.run( Command::new(&heat) @@ -1754,9 +1726,6 @@ impl Step for Extended { if built_tools.contains("rust-demangler") { cmd.arg("-dRustDemanglerDir=rust-demangler"); } - if built_tools.contains("rls") { - cmd.arg("-dRlsDir=rls"); - } if built_tools.contains("rust-analyzer") { cmd.arg("-dRustAnalyzerDir=rust-analyzer"); } @@ -1779,9 +1748,6 @@ impl Step for Extended { if built_tools.contains("rust-demangler") { candle("RustDemanglerGroup.wxs".as_ref()); } - if built_tools.contains("rls") { - candle("RlsGroup.wxs".as_ref()); - } if built_tools.contains("rust-analyzer") { candle("RustAnalyzerGroup.wxs".as_ref()); } @@ -1819,9 +1785,6 @@ impl Step for Extended { .arg("ClippyGroup.wixobj") .current_dir(&exe); - if built_tools.contains("rls") { - cmd.arg("RlsGroup.wixobj"); - } if built_tools.contains("rust-analyzer") { cmd.arg("RustAnalyzerGroup.wixobj"); } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2852442d0..f909ecc0a 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -793,7 +793,7 @@ impl Step for ErrorIndex { t!(fs::create_dir_all(&out)); let mut index = tool::ErrorIndex::command(builder); index.arg("html"); - index.arg(out.join("error-index.html")); + index.arg(out); index.arg(&builder.version); builder.run(&mut index); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 80b3bcce8..789da7481 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -80,6 +80,7 @@ pub struct Flags { pub llvm_profile_generate: bool, } +#[derive(Debug)] #[cfg_attr(test, derive(Clone))] pub enum Subcommand { Build { @@ -115,7 +116,6 @@ pub enum Subcommand { compare_mode: Option, pass: Option, run: Option, - skip: Vec, test_args: Vec, rustc_args: Vec, fail_fast: bool, @@ -220,7 +220,7 @@ To learn more about a subcommand, run `./x.py -h`", let j_msg = format!( "number of jobs to run in parallel; \ defaults to {} (this host's logical CPU count)", - num_cpus::get() + std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) ); opts.optopt("j", "jobs", &j_msg, "JOBS"); opts.optflag("h", "help", "print this help message"); @@ -568,7 +568,6 @@ Arguments: compare_mode: matches.opt_str("compare-mode"), pass: matches.opt_str("pass"), run: matches.opt_str("run"), - skip: matches.opt_strs("skip"), test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), @@ -707,16 +706,6 @@ impl Subcommand { pub fn test_args(&self) -> Vec<&str> { let mut args = vec![]; - match *self { - Subcommand::Test { ref skip, .. } => { - for s in skip { - args.push("--skip"); - args.push(s.as_str()); - } - } - _ => (), - }; - match *self { Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { args.extend(test_args.iter().flat_map(|s| s.split_whitespace())) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 6e49f39ff..d34aa15c5 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -182,15 +182,6 @@ install!((self, builder, _config), .expect("missing cargo"); install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball); }; - Rls, alias = "rls", Self::should_build(_config), only_hosts: true, { - if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) { - install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball); - } else { - builder.info( - &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target), - ); - } - }; RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target }) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d265277b4..cc0cf12bd 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -112,6 +112,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; +use config::Target; use filetime::FileTime; use once_cell::sync::OnceCell; @@ -186,6 +187,9 @@ const LLVM_TOOLS: &[&str] = &[ "opt", // used to optimize LLVM bytecode ]; +/// LLD file names for all flavors. +const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; + pub const VERSION: usize = 2; /// Extra --check-cfg to add when building @@ -273,7 +277,6 @@ pub struct Build { bootstrap_out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, - rls_info: channel::GitInfo, rust_analyzer_info: channel::GitInfo, clippy_info: channel::GitInfo, miri_info: channel::GitInfo, @@ -412,7 +415,6 @@ impl Build { let ignore_git = config.ignore_git; let rust_info = channel::GitInfo::new(ignore_git, &src); let cargo_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/cargo")); - let rls_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/rls")); let rust_analyzer_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/rust-analyzer")); let clippy_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/clippy")); @@ -490,7 +492,6 @@ impl Build { rust_info, cargo_info, - rls_info, rust_analyzer_info, clippy_info, miri_info, @@ -542,7 +543,6 @@ impl Build { let rust_submodules = [ "src/tools/rust-installer", "src/tools/cargo", - "src/tools/rls", "src/tools/miri", "library/backtrace", "library/stdarch", @@ -843,12 +843,13 @@ impl Build { /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: TargetSelection) -> bool { - if self.config.llvm_from_ci && target == self.config.build { - return true; - } - match self.config.target_config.get(&target) { - Some(ref c) => c.llvm_config.is_none(), + Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched, + Some(Target { llvm_config, .. }) => { + // If the user set llvm-config we assume Rust is not patched, + // but first check to see if it was configured by llvm-from-ci. + (self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none() + } None => true, } } @@ -1013,7 +1014,9 @@ impl Build { /// Returns the number of parallel jobs that have been configured for this /// build. fn jobs(&self) -> u32 { - self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32) + self.config.jobs.unwrap_or_else(|| { + std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32 + }) } fn debuginfo_map_to(&self, which: GitRepo) -> Option { @@ -1636,14 +1639,12 @@ fn chmod(_path: &Path, _perms: u32) {} /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) /// If the test is running and code is an error code, it will cause a panic. fn detail_exit(code: i32) -> ! { - // Successful exit - if code == 0 { - std::process::exit(0); - } - if cfg!(test) { + // if in test and code is an error code, panic with status code provided + if cfg!(test) && code != 0 { panic!("status code: {}", code); } else { - std::panic::resume_unwind(Box::new(code)); + //otherwise,exit with provided status code + std::process::exit(code); } } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 5a1f2e704..9a08a7be0 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -66,16 +66,21 @@ TESTS_IN_2 := \ src/test/ui \ src/tools/linkchecker +## MSVC native builders + +# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows ci-subset-1: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %) + $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %) ci-subset-2: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2) + $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2) + +## MingW native builders TESTS_IN_MINGW_2 := \ src/test/ui ci-mingw-subset-1: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) + $(Q)$(CFG_SRC_DIR)/x test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) ci-mingw-subset-2: $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 4d548dbb6..fc3bfaf1b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -114,23 +114,20 @@ pub fn prebuilt_llvm_config( Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() }) } -pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { - let config = &builder.config; - if !config.llvm_from_ci { - return; - } +/// This retrieves the LLVM sha we *want* to use, according to git history. +pub(crate) fn detect_llvm_sha(config: &crate::config::Config) -> String { let mut rev_list = config.git(); rev_list.args(&[ PathBuf::from("rev-list"), - format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(), + format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), "-n1".into(), "--first-parent".into(), "HEAD".into(), "--".into(), - builder.src.join("src/llvm-project"), - builder.src.join("src/bootstrap/download-ci-llvm-stamp"), + config.src.join("src/llvm-project"), + config.src.join("src/bootstrap/download-ci-llvm-stamp"), // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` - builder.src.join("src/version"), + config.src.join("src/version"), ]); let llvm_sha = output(&mut rev_list); let llvm_sha = llvm_sha.trim(); @@ -143,8 +140,82 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { panic!(); } + llvm_sha.to_owned() +} + +/// Returns whether the CI-found LLVM is currently usable. +/// +/// This checks both the build triple platform to confirm we're usable at all, +/// and then verifies if the current HEAD matches the detected LLVM SHA head, +/// in which case LLVM is indicated as not available. +pub(crate) fn is_ci_llvm_available(config: &crate::config::Config, asserts: bool) -> bool { + // This is currently all tier 1 targets and tier 2 targets with host tools + // (since others may not have CI artifacts) + // https://doc.rust-lang.org/rustc/platform-support.html#tier-1 + let supported_platforms = [ + // tier 1 + "aarch64-unknown-linux-gnu", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + // tier 2 with host tools + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", + "aarch64-unknown-linux-musl", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "mips-unknown-linux-gnu", + "mips64-unknown-linux-gnuabi64", + "mips64el-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "riscv64gc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-unknown-freebsd", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", + ]; + if !supported_platforms.contains(&&*config.build.triple) { + return false; + } + + let triple = &*config.build.triple; + if (triple == "aarch64-unknown-linux-gnu" || triple.contains("i686")) && asserts { + // No alt builder for aarch64-unknown-linux-gnu today. + return false; + } + + if crate::util::CiEnv::is_ci() { + let llvm_sha = detect_llvm_sha(config); + let head_sha = output(config.git().arg("rev-parse").arg("HEAD")); + let head_sha = head_sha.trim(); + if llvm_sha == head_sha { + eprintln!( + "Detected LLVM as non-available: running in CI and modified LLVM in this change" + ); + return false; + } + } + + true +} + +pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { + let config = &builder.config; + if !config.llvm_from_ci { + return; + } let llvm_root = config.ci_llvm_root(); let llvm_stamp = llvm_root.join(".llvm-stamp"); + let llvm_sha = detect_llvm_sha(&config); let key = format!("{}{}", llvm_sha, config.llvm_assertions); if program_out_of_date(&llvm_stamp, &key) && !config.dry_run { download_ci_llvm(builder, &llvm_sha); @@ -189,8 +260,8 @@ fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) { } else { &builder.config.stage0_metadata.config.artifacts_server }; - let channel = builder.config.artifact_channel(llvm_sha); - let filename = format!("rust-dev-{}-{}.tar.xz", channel, builder.build.build.triple); + let version = builder.config.artifact_version_part(llvm_sha); + let filename = format!("rust-dev-{}-{}.tar.xz", version, builder.build.build.triple); let tarball = rustc_cache.join(&filename); if !tarball.exists() { let help_on_error = "error: failed to download llvm from ci @@ -325,6 +396,9 @@ impl Step for Llvm { cfg.define("LLVM_PROFDATA_FILE", &path); } + // Disable zstd to avoid a dependency on libzstd.so. + cfg.define("LLVM_ENABLE_ZSTD", "OFF"); + if target != "aarch64-apple-darwin" && !target.contains("windows") { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { @@ -358,12 +432,13 @@ impl Step for Llvm { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } - if target.starts_with("riscv") && !target.contains("freebsd") { + if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd") + { // RISC-V GCC erroneously requires linking against // `libatomic` when using 1-byte and 2-byte C++ // atomics but the LLVM build system check cannot // detect this. Therefore it is set manually here. - // FreeBSD uses Clang as its system compiler and + // Some BSD uses Clang as its system compiler and // provides no libatomic in its base system so does // not want this. ldflags.exe.push(" -latomic"); @@ -512,11 +587,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 12 { + if major >= 13 { return; } } - panic!("\n\nbad LLVM version: {}, need >=12.0\n\n", version) + panic!("\n\nbad LLVM version: {}, need >=13.0\n\n", version) } fn configure_cmake( @@ -563,7 +638,7 @@ fn configure_cmake( if target.contains("darwin") { // Make sure that CMake does not build universal binaries on macOS. - // Explicitly specifiy the one single target architecture. + // Explicitly specify the one single target architecture. if target.starts_with("aarch64") { // macOS uses a different name for building arm64 cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64"); diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 25abe7a72..511872903 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -103,3 +103,25 @@ impl Step for BumpStage0 { builder.run(&mut cmd); } } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct ReplaceVersionPlaceholder; + +impl Step for ReplaceVersionPlaceholder { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/replace-version-placeholder") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(ReplaceVersionPlaceholder); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder); + cmd.arg(&builder.src); + builder.run(&mut cmd); + } +} diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index a5a39a5a3..eb7da1bda 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -11,7 +11,7 @@ use std::{ io::{self, Write}, }; -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Profile { Compiler, Codegen, diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 7b0c029c1..e30067a5c 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -50,11 +50,7 @@ impl OverlayKind { OverlayKind::RustDemangler => { &["src/tools/rust-demangler/README.md", "LICENSE-APACHE", "LICENSE-MIT"] } - OverlayKind::RLS => &[ - "src/tools/rls/README.md", - "src/tools/rls/LICENSE-APACHE", - "src/tools/rls/LICENSE-MIT", - ], + OverlayKind::RLS => &["src/tools/rls/README.md", "LICENSE-APACHE", "LICENSE-MIT"], OverlayKind::RustAnalyzer => &[ "src/tools/rust-analyzer/README.md", "src/tools/rust-analyzer/LICENSE-APACHE", @@ -78,7 +74,7 @@ impl OverlayKind { OverlayKind::Rustfmt => { builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) } - OverlayKind::RLS => builder.rls_info.version(builder, &builder.release_num("rls")), + OverlayKind::RLS => builder.release(&builder.release_num("rls")), OverlayKind::RustAnalyzer => builder .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c0fa8c9ac..dd41f8453 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -299,57 +299,6 @@ impl Step for Cargo { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rls { - stage: u32, - host: TargetSelection, -} - -impl Step for Rls { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rls") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rls { stage: run.builder.top_stage, host: run.target }); - } - - /// Runs `cargo test` for the rls. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - let build_result = - builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() }); - if build_result.is_none() { - eprintln!("failed to test rls: could not build"); - return; - } - - let mut cargo = tool::prepare_tool_cargo( - builder, - compiler, - Mode::ToolRustc, - host, - "test", - "src/tools/rls", - SourceType::Submodule, - &[], - ); - - cargo.add_rustc_lib_path(builder, compiler); - cargo.arg("--").args(builder.config.cmd.test_args()); - - if try_run(builder, &mut cargo.into()) { - builder.save_toolstate("rls", ToolState::TestPass); - } - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct RustAnalyzer { stage: u32, @@ -628,6 +577,10 @@ impl Step for Miri { cargo.env("MIRI_HOST_SYSROOT", sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", miri); + // propagate --bless + if builder.config.cmd.bless() { + cargo.env("MIRI_BLESS", "Gesundheit"); + } cargo.arg("--").args(builder.config.cmd.test_args()); @@ -901,7 +854,10 @@ fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option .output() .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) .unwrap_or(String::new()); - lines.lines().find_map(|l| l.split(":browser-ui-test@").skip(1).next()).map(|v| v.to_owned()) + lines + .lines() + .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) + .map(|v| v.to_owned()) } fn get_browser_ui_test_version(npm: &Path) -> Option { @@ -920,6 +876,11 @@ fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { one used in the CI (`{}`)", installed_version, v ); + eprintln!( + "You can install this version using `npm update browser-ui-test` or by using \ + `npm install browser-ui-test@{}`", + v, + ); } } Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), @@ -1381,6 +1342,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the let json_compiler = compiler.with_stage(0); cmd.arg("--jsondocck-path") .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target })); + cmd.arg("--jsondoclint-path") + .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); } if mode == "run-make" { @@ -1487,6 +1450,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--run-clang-based-tests-with").arg(clang_exe); } + for exclude in &builder.config.exclude { + cmd.arg("--skip"); + cmd.arg(&exclude.path); + } + // Get paths from cmd args let paths = match &builder.config.cmd { Subcommand::Test { ref paths, .. } => &paths[..], @@ -1501,7 +1469,15 @@ note: if you're sure you want to do this, please open an issue as to why. In the test_args.append(&mut builder.config.cmd.test_args()); - cmd.args(&test_args); + // On Windows, replace forward slashes in test-args by backslashes + // so the correct filters are passed to libtest + if cfg!(windows) { + let test_args_win: Vec = + test_args.iter().map(|s| s.replace("/", "\\")).collect(); + cmd.args(&test_args_win); + } else { + cmd.args(&test_args); + } if builder.is_verbose() { cmd.arg("--verbose"); @@ -2508,6 +2484,43 @@ impl Step for TierCheck { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct ReplacePlaceholderTest; + +impl Step for ReplacePlaceholderTest { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + /// Ensure the version placeholder replacement tool builds + fn run(self, builder: &Builder<'_>) { + builder.info("build check for version replacement placeholder"); + + // Test the version placeholder replacement tool itself. + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(0, bootstrap_host); + let cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + bootstrap_host, + "test", + "src/tools/replace-version-placeholder", + SourceType::InTree, + &[], + ); + try_run(builder, &mut cargo.into()); + } + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/replace-version-placeholder") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self); + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct LintDocs { pub compiler: Compiler, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 06fa5039f..7d4ed24b6 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -376,8 +376,10 @@ bootstrap_tool!( ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; JsonDocCk, "src/tools/jsondocck", "jsondocck"; + JsonDocLint, "src/tools/jsondoclint", "jsondoclint"; HtmlChecker, "src/tools/html-checker", "html-checker"; BumpStage0, "src/tools/bump-stage0", "bump-stage0"; + ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] @@ -778,12 +780,10 @@ impl Step for RustAnalyzerProcMacroSrv { macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident, - $toolstate:ident, $path:expr, $tool_name:expr, stable = $stable:expr, $(in_tree = $in_tree:expr,)? - $(submodule = $submodule:literal,)? $(tool_std = $tool_std:literal,)? $extra_deps:block;)+) => { $( @@ -828,7 +828,6 @@ macro_rules! tool_extended { #[allow(unused_mut)] fn run(mut $sel, $builder: &Builder<'_>) -> Option { $extra_deps - $( $builder.update_submodule(&Path::new("src").join("tools").join($submodule)); )? $builder.ensure(ToolBuild { compiler: $sel.compiler, target: $sel.target, @@ -854,24 +853,17 @@ macro_rules! tool_extended { // Note: Most submodule updates for tools are handled by bootstrap.py, since they're needed just to // invoke Cargo to build bootstrap. See the comment there for more details. tool_extended!((self, builder), - Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", stable=true, in_tree=true, {}; - CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, in_tree=true, {}; - Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, in_tree=true, {}; - Miri, miri, "src/tools/miri", "miri", stable=false, {}; - CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, {}; - Rls, rls, "src/tools/rls", "rls", stable=true, { - builder.ensure(Clippy { - compiler: self.compiler, - target: self.target, - extra_features: Vec::new(), - }); - self.extra_features.push("clippy".to_owned()); - }; + Cargofmt, "src/tools/rustfmt", "cargo-fmt", stable=true, in_tree=true, {}; + CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true, in_tree=true, {}; + Clippy, "src/tools/clippy", "clippy-driver", stable=true, in_tree=true, {}; + Miri, "src/tools/miri", "miri", stable=false, {}; + CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, {}; + Rls, "src/tools/rls", "rls", stable=true, {}; // FIXME: tool_std is not quite right, we shouldn't allow nightly features. // But `builder.cargo` doesn't know how to handle ToolBootstrap in stages other than 0, // and this is close enough for now. - RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; - Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; + RustDemangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; + Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; ); impl<'a> Builder<'a> { diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 2cfeae7dc..f3a6759ab 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -69,7 +69,6 @@ static STABLE_TOOLS: &[(&str, &str)] = &[ ("reference", "src/doc/reference"), ("rust-by-example", "src/doc/rust-by-example"), ("edition-guide", "src/doc/edition-guide"), - ("rls", "src/tools/rls"), ]; // These tools are permitted to not build on the beta/stable channels. diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 1895e2901..0ebabbd5c 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -197,9 +197,11 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { ptr::null_mut(), ); - let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]; - let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut u16; + #[repr(C, align(8))] + struct Align8(T); + let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]); + let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; + let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16; let mut i = 0; // FIXME: this conversion is very hacky let v = br"\??\"; @@ -219,7 +221,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { let res = DeviceIoControl( h as *mut _, FSCTL_SET_REPARSE_POINT, - data.as_ptr() as *mut _, + db.cast(), (*db).ReparseDataLength + 8, ptr::null_mut(), 0, @@ -258,6 +260,10 @@ impl CiEnv { } } + pub fn is_ci() -> bool { + Self::current() != CiEnv::None + } + /// If in a CI environment, forces the command to run with colors. pub fn force_coloring_in_ci(self, cmd: &mut Command) { if self != CiEnv::None { diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index 43cdbbe92..7a875c960 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive COPY scripts/android-base-apt-get.sh /scripts/ RUN sh /scripts/android-base-apt-get.sh @@ -13,7 +14,7 @@ RUN dpkg --add-architecture i386 && \ libgl1-mesa-glx \ libpulse0 \ libstdc++6:i386 \ - openjdk-9-jre-headless \ + openjdk-8-jre-headless \ tzdata \ wget \ python3 @@ -36,8 +37,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh - COPY scripts/android-start-emulator.sh /scripts/ ENTRYPOINT ["/scripts/android-start-emulator.sh"] diff --git a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile index e2dbc7cfd..69f88e495 100644 --- a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile @@ -78,6 +78,8 @@ RUN curl -O https://ci-mirrors.rust-lang.org/rustc/vexpress-v2p-ca15-tc1.dtb COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +COPY static/gitconfig /etc/gitconfig + ENV RUST_CONFIGURE_ARGS --qemu-armhf-rootfs=/tmp/rootfs ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target arm-unknown-linux-gnueabihf diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 2f0496d7d..2328db4ab 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 COPY scripts/android-base-apt-get.sh /scripts/ RUN sh /scripts/android-base-apt-get.sh @@ -38,6 +38,3 @@ ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh - -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile index c98fc7dcf..b0d65428e 100644 --- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -36,7 +36,8 @@ RUN /scripts/cmake.sh ENV RUST_CONFIGURE_ARGS \ --musl-root-i586=/musl-i586 \ --musl-root-i686=/musl-i686 \ - --disable-docs + --disable-docs \ + --set llvm.allow-old-toolchain # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile index b0f06569a..948fa40dd 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -26,5 +26,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile index 245c28e1f..fd15dbd22 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -25,5 +25,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile index 03998c888..376bdfb4a 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -26,5 +26,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips64el-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile index 586172706..70c8b2a96 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -25,5 +25,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mipsel-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 6f9980dbc..126c292b3 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -32,10 +32,16 @@ RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main' ENV \ AR_x86_64_fuchsia=x86_64-fuchsia-ar \ CC_x86_64_fuchsia=x86_64-fuchsia-clang \ + CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \ + CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \ AR_aarch64_fuchsia=aarch64-fuchsia-ar \ CC_aarch64_fuchsia=aarch64-fuchsia-clang \ + CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \ + CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \ AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ @@ -89,14 +95,14 @@ RUN sh /scripts/sccache.sh ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \ --C link-arg=--sysroot=/usr/local/x86_64-fuchsia \ --C link-arg=-L/usr/local/x86_64-fuchsia/lib \ --C link-arg=-L/usr/local/lib/x86_64-fuchsia/lib +-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \ +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \ --C link-arg=--sysroot=/usr/local/aarch64-fuchsia \ --C link-arg=-L/usr/local/aarch64-fuchsia/lib \ --C link-arg=-L/usr/local/lib/aarch64-fuchsia/lib +-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \ +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \ +-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib ENV TARGETS=x86_64-fuchsia ENV TARGETS=$TARGETS,aarch64-fuchsia diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh index 73acdf5be..80db92577 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh @@ -3,52 +3,58 @@ set -ex source shared.sh -ZIRCON=e9a26dbc70d631029f8ee9763103910b7e3a2fe1 - -mkdir -p zircon -pushd zircon > /dev/null - -# Download sources -git init -git remote add origin https://github.com/rust-lang-nursery/mirror-google-fuchsia-zircon -git fetch --depth=1 origin $ZIRCON -git reset --hard FETCH_HEAD - -# Download toolchain -./scripts/download-toolchain -chmod -R a+rx prebuilt/downloads/clang+llvm-x86_64-linux -cp -a prebuilt/downloads/clang+llvm-x86_64-linux/. /usr/local - -build() { - local arch="$1" - - case "${arch}" in - x86_64) tgt="zircon-pc-x86-64" ;; - aarch64) tgt="zircon-qemu-arm64" ;; - esac - - hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt - dst=/usr/local/${arch}-fuchsia - mkdir -p $dst - cp -a build-${tgt}/sysroot/include $dst/ - cp -a build-${tgt}/sysroot/lib $dst/ +FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64 +FUCHSIA_SDK_ID=4xjxrGUrDbQ6_zJwj6cDN1IbWsWV5aCQXC_zO_Hu0XkC +FUCHSIA_SDK_SHA256=e318f1ac652b0db43aff32708fa70337521b5ac595e5a0905c2ff33bf1eed179 +FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk +CLANG_DOWNLOAD_URL=\ +https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64 +CLANG_DOWNLOAD_ID=vU0vNjSihOV4Q6taQYCpy03JXGiCyVwxen3rFMNMIgsC +CLANG_DOWNLOAD_SHA256=bd4d2f3634a284e57843ab5a4180a9cb4dc95c6882c95c317a7deb14c34c220b + +install_clang() { + mkdir -p clang_download + pushd clang_download > /dev/null + + # Download clang+llvm + curl -LO "${CLANG_DOWNLOAD_URL}/+/${CLANG_DOWNLOAD_ID}" + echo "$(echo ${CLANG_DOWNLOAD_SHA256}) ${CLANG_DOWNLOAD_ID}" | sha256sum --check --status + unzip -qq ${CLANG_DOWNLOAD_ID} -d clang-linux-amd64 + + # Other dists currently depend on our Clang... moving into /usr/local for other + # dist usage instead of a Fuchsia /usr/local directory + chmod -R 777 clang-linux-amd64/. + cp -a clang-linux-amd64/. /usr/local + + # CFLAGS and CXXFLAGS env variables in main Dockerfile handle sysroot linking + for arch in x86_64 aarch64; do + for tool in clang clang++; do + ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-fuchsia-${tool} + done + ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar + done + + popd > /dev/null + rm -rf clang_download } -# Build sysroot -for arch in x86_64 aarch64; do - build ${arch} -done - -popd > /dev/null -rm -rf zircon - -for arch in x86_64 aarch64; do - for tool in clang clang++; do - cat >/usr/local/bin/${arch}-fuchsia-${tool} < /dev/null + + # Download Fuchsia SDK (with Zircon libs) + curl -LO "${FUCHSIA_SDK_URL}/+/${FUCHSIA_SDK_ID}" + echo "$(echo ${FUCHSIA_SDK_SHA256}) ${FUCHSIA_SDK_ID}" | sha256sum --check --status + unzip -qq ${FUCHSIA_SDK_ID} -d core-linux-amd64 + + # Moving SDK into Docker's user-space + mkdir -p ${FUCHSIA_SDK_USR_DIR} + chmod -R 777 core-linux-amd64/. + cp -r core-linux-amd64/* ${FUCHSIA_SDK_USR_DIR} + + popd > /dev/null + rm -rf zircon +} + +hide_output install_clang +hide_output install_zircon_libs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 1025f5bce..fa780e1e4 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -LLVM=llvmorg-14.0.5 +LLVM=llvmorg-15.0.0 mkdir llvm-project cd llvm-project diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile index 92bdc9811..fed4be4c3 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile @@ -21,5 +21,6 @@ ENV \ ENV HOSTS=x86_64-unknown-netbsd -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index 0182ebb8b..dd74726f8 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ @@ -20,9 +21,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh - RUN mkdir -p /config RUN echo "[rust]" > /config/nopt-std-config.toml RUN echo "optimize = false" >> /config/nopt-std-config.toml diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index feaab819b..0c36cfd66 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ @@ -20,9 +21,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh - ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu # Exclude some tests that are unlikely to be platform specific, to speed up # this slow job. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 9ee84f420..52a777615 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -1,4 +1,7 @@ FROM ubuntu:18.04 +# FIXME: when bumping the version, remove the Python 3.6-specific changes in +# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove +# this comment. RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ @@ -8,6 +11,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python3 \ + python3-pip \ + python3-pkg-resources \ git \ cmake \ sudo \ @@ -27,6 +32,9 @@ RUN npm install eslint@8.6.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/ +RUN pip3 install --no-deps --require-hashes -r /tmp/reuse-requirements.txt + COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ @@ -37,9 +45,11 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 2 src/tools/tidy && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ - python3 ../x.py doc --stage 0 library/test && \ + # Build both public and internal documentation. + RUSTDOCFLAGS="--document-private-items" python3 ../x.py doc --stage 0 library/test && \ /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ + reuse lint && \ # Runs checks to ensure that there are no ES5 issues in our JS code. es-check es6 ../src/librustdoc/html/static/js/*.js && \ eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in new file mode 100644 index 000000000..4964f40aa --- /dev/null +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in @@ -0,0 +1,22 @@ +# This is the template for reuse-requirements.txt. +# +# The pip-tools project is used to generate the file again. To install it, the +# recommended way is to: +# +# - Install pipx from https://github.com/pypa/pipx +# - Run `pipx install pip-tools` +# +# Once pip-tools is installed, run this command to regenerate the .txt file: +# +# pip-compile --allow-unsafe --generate-hashes reuse-requirements.in +# + +reuse + +# Some packages dropped support for Python 3.6, which is the version used in +# this builder (due to Ubuntu 18.04). This should be removed once we bump the +# Ubuntu version of the builder. +jinja2 < 3.1 +markupsafe < 2.1 +requests < 2.28 +setuptools < 59.7 diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt new file mode 100644 index 000000000..10a5f7387 --- /dev/null +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt @@ -0,0 +1,145 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --allow-unsafe --generate-hashes reuse-requirements.in +# +binaryornot==0.4.4 \ + --hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \ + --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4 + # via reuse +boolean-py==3.8 \ + --hash=sha256:cc24e20f985d60cd4a3a5a1c0956dd12611159d32a75081dabd0c9ab981acaa4 \ + --hash=sha256:d75da0fd0354425fa64f6bbc6cec6ae1485d0eec3447b73187ff8cbf9b572e26 + # via + # license-expression + # reuse +certifi==2022.6.15 \ + --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ + --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 + # via requests +chardet==5.0.0 \ + --hash=sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa \ + --hash=sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557 + # via + # binaryornot + # python-debian +charset-normalizer==2.0.12 \ + --hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \ + --hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df + # via requests +idna==3.3 \ + --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ + --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d + # via requests +jinja2==3.0.3 \ + --hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \ + --hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7 + # via + # -r reuse-requirements.in + # reuse +license-expression==21.6.14 \ + --hash=sha256:324246eed8e138b4139fefdc0e9dc4161d5075e3929e56983966d37298dca30e \ + --hash=sha256:9de87a427c9a449eee7913472fb9ed03b63036295547369fdbf95f76a8b924b2 + # via + # -r reuse-requirements.in + # reuse +markupsafe==2.0.1 \ + --hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \ + --hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \ + --hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \ + --hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \ + --hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \ + --hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \ + --hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \ + --hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \ + --hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \ + --hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \ + --hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \ + --hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \ + --hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \ + --hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \ + --hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \ + --hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \ + --hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \ + --hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \ + --hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \ + --hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \ + --hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \ + --hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \ + --hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \ + --hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \ + --hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \ + --hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \ + --hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \ + --hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \ + --hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \ + --hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \ + --hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \ + --hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \ + --hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \ + --hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \ + --hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \ + --hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \ + --hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \ + --hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \ + --hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \ + --hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \ + --hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \ + --hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \ + --hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \ + --hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \ + --hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \ + --hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \ + --hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \ + --hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \ + --hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \ + --hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \ + --hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \ + --hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \ + --hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \ + --hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \ + --hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \ + --hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \ + --hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \ + --hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \ + --hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \ + --hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \ + --hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \ + --hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \ + --hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \ + --hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \ + --hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \ + --hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \ + --hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \ + --hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \ + --hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872 + # via + # -r reuse-requirements.in + # jinja2 +python-debian==0.1.44 \ + --hash=sha256:11bd6f01c46da57982bdd66dd595e2d240feb32a85de3fd37c452102fd0337ab \ + --hash=sha256:65592fe3b64f6c6c93d94e2d2599db5e0c22831d3bcff07cb7b96d3840b1333e + # via reuse +requests==2.26.0 \ + --hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24 \ + --hash=sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7 + # via + # -r reuse-requirements.in + # reuse +reuse==1.0.0 \ + --hash=sha256:db3022be2d87f69c8f508b928023de3026f454ce17d01e22f770f7147ac1e8d4 \ + --hash=sha256:e2605e796311c424465d741ea2a1e1ad03bbb90b921d74750119c331ca5af46e + # via -r reuse-requirements.in +urllib3==1.26.10 \ + --hash=sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec \ + --hash=sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6 + # via requests + +# The following packages are considered to be unsafe in a requirements file: +setuptools==59.6.0 \ + --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \ + --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e + # via + # -r reuse-requirements.in + # reuse diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 4d554a285..b75e2f085 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -30,6 +30,10 @@ WORKDIR / COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# We are disabling CI LLVM since this builder needs to build LLD, which is +# currently unsupported when downloading pre-built LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 + ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --set build.nodejs=/node-v15.14.0-linux-x64/bin/node \ diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile index 878c4e341..9e37c2822 100644 --- a/src/ci/docker/host-x86_64/wasm32/Dockerfile +++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile @@ -48,6 +48,8 @@ ENV TARGETS=wasm32-unknown-emscripten # Use -O1 optimizations in the link step to reduce time spent optimizing. ENV EMCC_CFLAGS=-O1 +COPY static/gitconfig /etc/gitconfig + # Emscripten installation is user-specific ENV NO_CHANGE_USER=1 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index ee3cd092f..d55d5b56a 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ @@ -23,8 +24,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh - ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu ENV RUST_CHECK_TARGET check-aux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 13d440423..739045248 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -31,6 +31,9 @@ RUN sh /scripts/sccache.sh ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 +# llvm.use-linker conflicts with downloading CI LLVM +ENV NO_DOWNLOAD_CI_LLVM 1 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 09d9cda02..80a004501 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ @@ -19,8 +20,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh +# We are disabling CI LLVM since distcheck is an offline build. +ENV NO_DOWNLOAD_CI_LLVM 1 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false ENV SCRIPT python3 ../x.py --stage 2 test distcheck diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12-stage1/Dockerfile deleted file mode 100644 index c2f3a16d2..000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12-stage1/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -FROM ubuntu:20.04 - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python2.7 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-12-tools \ - llvm-12-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-12 \ - --enable-llvm-link-shared \ - --set rust.thin-lto-import-instr-limit=10 - -ENV SCRIPT python2.7 ../x.py --stage 1 test --exclude src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - python2.7 ../x.py --stage 1 test src/test/mir-opt \ - --host='' --target=i686-unknown-linux-gnu \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile deleted file mode 100644 index df1fbc29c..000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM ubuntu:20.04 - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python2.7 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-12-tools \ - llvm-12-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-12 \ - --enable-llvm-link-shared \ - --set rust.thin-lto-import-instr-limit=10 - -ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \ - # Run the `mir-opt` tests again but this time for a 32-bit target. - # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have - # both 32-bit and 64-bit outputs updated by the PR author, before - # the PR is approved and tested for merging. - # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, - # despite having different output on 32-bit vs 64-bit targets. - python2.7 ../x.py --stage 2 test src/test/mir-opt \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run the UI test suite again, but in `--pass=check` mode - # - # This is intended to make sure that both `--pass=check` continues to - # work. - # - python2.7 ../x.py --stage 2 test src/test/ui --pass=check \ - --host='' --target=i686-unknown-linux-gnu && \ - # Run tidy at the very end, after all the other tests. - python2.7 ../x.py --stage 2 test src/tools/tidy diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile new file mode 100644 index 000000000..23f2215c2 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile @@ -0,0 +1,48 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-13-tools \ + llvm-13-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-13 \ + --enable-llvm-link-shared \ + --set rust.thin-lto-import-instr-limit=10 + +ENV SCRIPT python2.7 ../x.py --stage 1 test --exclude src/tools/tidy && \ + # Run the `mir-opt` tests again but this time for a 32-bit target. + # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have + # both 32-bit and 64-bit outputs updated by the PR author, before + # the PR is approved and tested for merging. + # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, + # despite having different output on 32-bit vs 64-bit targets. + python2.7 ../x.py --stage 1 test src/test/mir-opt \ + --host='' --target=i686-unknown-linux-gnu diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile new file mode 100644 index 000000000..8f6831bc5 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile @@ -0,0 +1,69 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive + +# NOTE: intentionally installs both python2 and python3 so we can test support for both. +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python3.9 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-13-tools \ + llvm-13-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs + +# Install powershell so we can test x.ps1 on Linux +RUN apt-get update && \ + apt-get install -y apt-transport-https software-properties-common && \ + curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + apt-get update && \ + apt-get install -y powershell + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-13 \ + --enable-llvm-link-shared \ + --set rust.thin-lto-import-instr-limit=10 + +# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. +ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \ + # Run the `mir-opt` tests again but this time for a 32-bit target. + # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have + # both 32-bit and 64-bit outputs updated by the PR author, before + # the PR is approved and tested for merging. + # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, + # despite having different output on 32-bit vs 64-bit targets. + ../x --stage 2 test src/test/mir-opt \ + --host='' --target=i686-unknown-linux-gnu && \ + # Run the UI test suite again, but in `--pass=check` mode + # + # This is intended to make sure that both `--pass=check` continues to + # work. + # + ../x.ps1 --stage 2 test src/test/ui --pass=check \ + --host='' --target=i686-unknown-linux-gnu && \ + # Run tidy at the very end, after all the other tests. + python2.7 ../x.py --stage 2 test src/tools/tidy diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 2358091a6..4350ca205 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -1,5 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ @@ -27,6 +28,7 @@ RUN apt-get install -y \ libdbus-1-3 \ libexpat1 \ libfontconfig1 \ + libgbm1 \ libgcc1 \ libgconf-2-4 \ libgdk-pixbuf2.0-0 \ @@ -59,13 +61,10 @@ RUN apt-get install -y \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY scripts/cmake.sh /scripts/ -RUN /scripts/cmake.sh - COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/ -RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ -ENV NODE_FOLDER=/node-v14.4.0-linux-x64/bin +RUN curl -sL https://nodejs.org/dist/v14.20.0/node-v14.20.0-linux-x64.tar.xz | tar -xJ +ENV NODE_FOLDER=/node-v14.20.0-linux-x64/bin ENV PATH="$NODE_FOLDER:${PATH}" COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ @@ -85,4 +84,5 @@ ENV RUST_CONFIGURE_ARGS \ --save-toolstates=/tmp/toolstate/toolstates.json ENV SCRIPT /tmp/checktools.sh ../x.py && \ - NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2 + NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2 \ + --test-args "'--no-sandbox --jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index bae256fd5..2774f8587 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.9.7 \ No newline at end of file +0.10.0 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 412efe5c4..0fb8f41a7 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -14,7 +14,6 @@ python3 "$X_PY" test --stage 2 --no-fail-fast \ src/doc/rust-by-example \ src/doc/embedded-book \ src/doc/edition-guide \ - src/tools/rls \ src/tools/miri \ set -e diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 93b4f435d..69d4916e5 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -213,7 +213,16 @@ else args="$args --volume $HOME/.cargo:/cargo" args="$args --volume $HOME/rustsrc:$HOME/rustsrc" args="$args --volume /tmp/toolstate:/tmp/toolstate" - args="$args --env LOCAL_USER_ID=`id -u`" + + id=$(id -u) + if [[ "$id" != 0 && "$(docker -v)" =~ ^podman ]]; then + # Rootless podman creates a separate user namespace, where an inner + # LOCAL_USER_ID will map to a different subuid range on the host. + # The "keep-id" mode maps the current UID directly into the container. + args="$args --env NO_CHANGE_USER=1 --userns=keep-id" + else + args="$args --env LOCAL_USER_ID=$id" + fi fi if [ "$dev" = "1" ] diff --git a/src/ci/docker/scripts/android-base-apt-get.sh b/src/ci/docker/scripts/android-base-apt-get.sh index f1761f806..22e2e243e 100644 --- a/src/ci/docker/scripts/android-base-apt-get.sh +++ b/src/ci/docker/scripts/android-base-apt-get.sh @@ -10,6 +10,7 @@ apt-get install -y --no-install-recommends \ g++ \ git \ libssl-dev \ + libncurses5 \ make \ ninja-build \ pkg-config \ diff --git a/src/ci/docker/static/gitconfig b/src/ci/docker/static/gitconfig new file mode 100644 index 000000000..6bad35f01 --- /dev/null +++ b/src/ci/docker/static/gitconfig @@ -0,0 +1,2 @@ +[safe] +directory = * diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 3ad4e3f97..6e4b0b0c2 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -284,7 +284,7 @@ jobs: - name: mingw-check <<: *job-linux-xl - - name: x86_64-gnu-llvm-12 + - name: x86_64-gnu-llvm-13 <<: *job-linux-xl - name: x86_64-gnu-tools @@ -431,12 +431,12 @@ jobs: - name: x86_64-gnu-distcheck <<: *job-linux-xl - - name: x86_64-gnu-llvm-12 + - name: x86_64-gnu-llvm-13 env: RUST_BACKTRACE: 1 <<: *job-linux-xl - - name: x86_64-gnu-llvm-12-stage1 + - name: x86_64-gnu-llvm-13-stage1 env: RUST_BACKTRACE: 1 <<: *job-linux-xl @@ -596,29 +596,51 @@ jobs: - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --set llvm.allow-old-toolchain SCRIPT: make ci-mingw-subset-1 + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 <<: *job-windows-xl - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --set llvm.allow-old-toolchain SCRIPT: make ci-mingw-subset-2 + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 <<: *job-windows-xl - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + --set llvm.allow-old-toolchain + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 <<: *job-windows-xl - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + --set llvm.allow-old-toolchain + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 <<: *job-windows-xl @@ -654,8 +676,7 @@ jobs: --enable-full-tools --enable-profiler SCRIPT: python x.py dist - # RLS does not build for aarch64-pc-windows-msvc. See rust-lang/rls#1693 - DIST_REQUIRE_ALL_TOOLS: 0 + DIST_REQUIRE_ALL_TOOLS: 1 # Hack around this SDK version, because it doesn't work with clang. # See https://github.com/rust-lang/rust/issues/88796 WINDOWS_SDK_20348_HACK: 1 @@ -663,7 +684,14 @@ jobs: - name: dist-i686-mingw env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --enable-full-tools + --enable-profiler + --set llvm.allow-old-toolchain + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 @@ -672,7 +700,14 @@ jobs: - name: dist-x86_64-mingw env: SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-full-tools + --enable-profiler + --set llvm.allow-old-toolchain + # We are intentionally allowing an old toolchain on this builder (and that's + # incompatible with LLVM downloads today). + NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl diff --git a/src/ci/run.sh b/src/ci/run.sh index 6545475d9..9a247fb60 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -11,6 +11,16 @@ if [ "$NO_CHANGE_USER" = "" ]; then useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user export HOME=/home/user unset LOCAL_USER_ID + + # Ensure that runners are able to execute git commands in the worktree, + # overriding the typical git protections. In our docker container we're running + # as root, while the user owning the checkout is not root. + # This is only necessary when we change the user, otherwise we should + # already be running with the right user. + # + # For NO_CHANGE_USER done in the small number of Dockerfiles affected. + echo -e '[safe]\n\tdirectory = *' > /home/user/gitconfig + exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user fi fi @@ -102,6 +112,18 @@ else fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" + + # We enable this for non-dist builders, since those aren't trying to produce + # fresh binaries. We currently don't entirely support distributing a fresh + # copy of the compiler (including llvm tools, etc.) if we haven't actually + # built LLVM, since not everything necessary is copied into the + # local-usage-only LLVM artifacts. If that changes, this could maybe be made + # true for all builds. In practice it's probably a good idea to keep building + # LLVM continuously on at least some builders to ensure it works, though. + # (And PGO is its own can of worms). + if [ "$NO_DOWNLOAD_CI_LLVM" = "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.download-ci-llvm=if-available" + fi fi if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]; then diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index 0bc8a0389..02b72625d 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -61,6 +61,10 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then 7z x -oclang-rust/ "LLVM-${LLVM_VERSION}-win64.exe" ciCommandSetEnv RUST_CONFIGURE_ARGS \ "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe" + + # Disable downloading CI LLVM on this builder; + # setting up clang-cl just above conflicts with the default if-available option. + ciCommandSetEnv NO_DOWNLOAD_CI_LLVM 1 fi if isWindows; then diff --git a/src/doc/book/2018-edition/book.toml b/src/doc/book/2018-edition/book.toml index 9c71e2a91..03b59090b 100644 --- a/src/doc/book/2018-edition/book.toml +++ b/src/doc/book/2018-edition/book.toml @@ -3,5 +3,5 @@ title = "The Rust Programming Language" author = "Steve Klabnik and Carol Nichols, with Contributions from the Rust Community" [output.html] -additional-css = ["ferris.css", "src/theme/2018-edition.css"] +additional-css = ["ferris.css"] additional-js = ["ferris.js"] diff --git a/src/doc/book/2018-edition/src/theme/2018-edition.css b/src/doc/book/2018-edition/src/theme/2018-edition.css deleted file mode 100644 index b1dcf9364..000000000 --- a/src/doc/book/2018-edition/src/theme/2018-edition.css +++ /dev/null @@ -1,9 +0,0 @@ -span.caption { - font-size: .8em; - font-weight: 600; -} - -span.caption code { - font-size: 0.875em; - font-weight: 400; -} diff --git a/src/doc/book/2018-edition/src/theme/index.hbs b/src/doc/book/2018-edition/src/theme/index.hbs deleted file mode 100644 index f3f1b52fa..000000000 --- a/src/doc/book/2018-edition/src/theme/index.hbs +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - Outdated link: {{ title }} - - - - - - - - - - - - - - - {{#each additional_css}} - - {{/each}} - - -

- - diff --git a/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs b/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs index 55e8fef8f..28c0dea26 100644 --- a/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs +++ b/src/doc/book/listings/ch20-web-server/listing-20-24/src/lib.rs @@ -70,7 +70,9 @@ struct Worker { impl Worker { fn new(id: usize, receiver: Arc>>) -> Worker { let thread = thread::spawn(move || loop { - match receiver.lock().unwrap().recv() { + let message = receiver.lock().unwrap().recv(); + + match message { Ok(job) => { println!("Worker {id} got a job; executing."); diff --git a/src/doc/book/src/ch01-03-hello-cargo.md b/src/doc/book/src/ch01-03-hello-cargo.md index 135eacd2f..9979e76dd 100644 --- a/src/doc/book/src/ch01-03-hello-cargo.md +++ b/src/doc/book/src/ch01-03-hello-cargo.md @@ -66,6 +66,8 @@ name = "hello_cargo" version = "0.1.0" edition = "2021" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + [dependencies] ``` diff --git a/src/doc/book/src/ch06-02-match.md b/src/doc/book/src/ch06-02-match.md index a24936829..2dfe6c34b 100644 --- a/src/doc/book/src/ch06-02-match.md +++ b/src/doc/book/src/ch06-02-match.md @@ -17,7 +17,7 @@ the value falls into the associated code block to be used during execution. Speaking of coins, let’s use them as an example using `match`! We can write a function that takes an unknown United States coin and, in a similar way as the -counting machine, determines which coin it is and return its value in cents, as +counting machine, determines which coin it is and returns its value in cents, as shown here in Listing 6-3. ```rust diff --git a/src/doc/book/src/ch09-02-recoverable-errors-with-result.md b/src/doc/book/src/ch09-02-recoverable-errors-with-result.md index 61931f08d..347ef9aa7 100644 --- a/src/doc/book/src/ch09-02-recoverable-errors-with-result.md +++ b/src/doc/book/src/ch09-02-recoverable-errors-with-result.md @@ -524,7 +524,7 @@ returns integers from executables to be compatible with this convention. The `main` function may return any types that implement [the `std::process::Termination` trait][termination], which contains -a function `report` that returns an `ExitCode` Consult the standard library +a function `report` that returns an `ExitCode`. Consult the standard library documentation for more information on implementing the `Termination` trait for your own types. diff --git a/src/doc/book/src/ch20-02-multithreaded.md b/src/doc/book/src/ch20-02-multithreaded.md index bd1dc25ab..5a4a50ac0 100644 --- a/src/doc/book/src/ch20-02-multithreaded.md +++ b/src/doc/book/src/ch20-02-multithreaded.md @@ -387,7 +387,7 @@ this data structure *Worker*, which is a common term in pooling implementations. The Worker picks up code that needs to be run and runs the code in the Worker’s thread. Think of people working in the kitchen at a restaurant: the workers wait until orders come in from customers, and then -they’re responsible for taking those orders and filling them. +they’re responsible for taking those orders and fulfilling them. Instead of storing a vector of `JoinHandle<()>` instances in the thread pool, we’ll store instances of the `Worker` struct. Each `Worker` will store a single diff --git a/src/doc/book/src/title-page.md b/src/doc/book/src/title-page.md index 47226dc84..ed55a6839 100644 --- a/src/doc/book/src/title-page.md +++ b/src/doc/book/src/title-page.md @@ -20,3 +20,7 @@ Press][nsprust]. [editions]: appendix-05-editions.html [nsprust]: https://nostarch.com/rust [translations]: appendix-06-translation.html + +> **🚨 Want a more interactive learning experience? Try out a different version +> of the Rust Book, featuring: quizzes, highlighting, visualizations, and +> more**: diff --git a/src/doc/edition-guide/README.md b/src/doc/edition-guide/README.md index 559498257..3f3994381 100644 --- a/src/doc/edition-guide/README.md +++ b/src/doc/edition-guide/README.md @@ -8,8 +8,8 @@ online](https://doc.rust-lang.org/nightly/edition-guide/). ## License -The Edition Guide is dual licensed under `MIT`/`Apache2`, just like Rust itself. -See the `LICENSE-*` files in this repository for more details. +The Rust Edition Guide is dual licensed under `MIT`/`Apache2`, just like Rust +itself. See the `LICENSE-*` files in this repository for more details. ## Building locally diff --git a/src/doc/edition-guide/book.toml b/src/doc/edition-guide/book.toml index 8d8b26322..7841b647d 100644 --- a/src/doc/edition-guide/book.toml +++ b/src/doc/edition-guide/book.toml @@ -2,7 +2,7 @@ authors = ["The Rust Project Developers"] multilingual = false src = "src" -title = "The Edition Guide" +title = "The Rust Edition Guide" [output.html] git-repository-url = "https://github.com/rust-lang/edition-guide" diff --git a/src/doc/edition-guide/src/SUMMARY.md b/src/doc/edition-guide/src/SUMMARY.md index dac77913b..9ac69923f 100644 --- a/src/doc/edition-guide/src/SUMMARY.md +++ b/src/doc/edition-guide/src/SUMMARY.md @@ -1,4 +1,4 @@ -# The Edition Guide +# The Rust Edition Guide [Introduction](introduction.md) diff --git a/src/doc/edition-guide/src/editions/creating-a-new-project.md b/src/doc/edition-guide/src/editions/creating-a-new-project.md index 319d6996c..8ec71d67e 100644 --- a/src/doc/edition-guide/src/editions/creating-a-new-project.md +++ b/src/doc/edition-guide/src/editions/creating-a-new-project.md @@ -1,12 +1,12 @@ # Creating a new project -When you create a new project with Cargo, it will automatically add -configuration for the latest edition: +A new project created with Cargo is configured to use the latest edition by +default: ```console -> cargo new foo +$ cargo new foo Created binary (application) `foo` project -> cat foo/Cargo.toml +$ cat foo/Cargo.toml [package] name = "foo" version = "0.1.0" @@ -15,11 +15,41 @@ edition = "2021" [dependencies] ``` -That `edition = "2021"` setting will configure your package to use Rust 2021. -No more configuration needed! +That `edition = "2021"` setting configures your package to be built using the +Rust 2021 edition. No further configuration needed! -If you'd prefer to use an older edition, you can change the value in that -key, for example: +You can use the `--edition ` option of `cargo new` to create the project +using some specific edition. For example, creating a new project to use the +Rust 2018 edition could be done like this: + +```console +$ cargo new --edition 2018 foo + Created binary (application) `foo` project +$ cat foo/Cargo.toml +[package] +name = "foo" +version = "0.1.0" +edition = "2018" + +[dependencies] +``` + +Don't worry about accidentally using an invalid year for the edition; the +`cargo new` invocation will not accept an invalid edition year value: + +```console +$ cargo new --edition 2019 foo +error: "2019" isn't a valid value for '--edition ' + [possible values: 2015, 2018, 2021] + + Did you mean "2018"? + +For more information try --help +``` + +You can change the value of the `edition` key by simply editing the +`Cargo.toml` file. For example, to cause your package to be built using the +Rust 2015 edition, you would set the key as in the following example: ```toml [package] @@ -29,5 +59,3 @@ edition = "2015" [dependencies] ``` - -This will build your package in Rust 2015. diff --git a/src/doc/edition-guide/src/editions/index.md b/src/doc/edition-guide/src/editions/index.md index e12285c49..b5480e809 100644 --- a/src/doc/edition-guide/src/editions/index.md +++ b/src/doc/edition-guide/src/editions/index.md @@ -1,6 +1,8 @@ # What are Editions? -The release of Rust 1.0 established +The release of Rust 1.0 +([in May 2015](https://blog.rust-lang.org/2015/05/15/Rust-1.0.html)) +established ["stability without stagnation"](https://blog.rust-lang.org/2014/10/30/Stability.html) as a core Rust deliverable. Ever since the 1.0 release, @@ -51,11 +53,11 @@ there might be some corner cases where manual changes are still required. The tooling tries hard to avoid changes to semantics that could affect the correctness or performance of the code. -In addition to tooling, we also maintain this Edition Migration Guide that covers +In addition to tooling, we also maintain this Rust Edition Guide that covers the changes that are part of an edition. This guide describes each change and gives pointers to where you can learn more about it. It also covers any corner cases or details you should be aware of. -This guide serves both as an overview of the edition +This guide serves as an overview of editions, +as a migration guide for specific editions, and as a quick troubleshooting reference if you encounter problems with the automated tooling. - diff --git a/src/doc/edition-guide/src/introduction.md b/src/doc/edition-guide/src/introduction.md index c23508b2f..a36a620a8 100644 --- a/src/doc/edition-guide/src/introduction.md +++ b/src/doc/edition-guide/src/introduction.md @@ -1,6 +1,6 @@ # Introduction -Welcome to the Rust Edition Guide! "Editions" are Rust's way of introducing +Welcome to The Rust Edition Guide! "Editions" are Rust's way of introducing changes into the language that would not otherwise be backwards compatible. diff --git a/src/doc/index.md b/src/doc/index.md index b77790e33..744c7f709 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -101,7 +101,7 @@ accomplishing various tasks. Many of Rust's errors come with error codes, and you can request extended diagnostics from the compiler on those errors. You can also [read them -here](error-index.html), if you prefer to read them that way. +here](error_codes/index.html), if you prefer to read them that way. # Master Rust diff --git a/src/doc/nomicon/src/lifetime-mismatch.md b/src/doc/nomicon/src/lifetime-mismatch.md index 0494d492a..1da2d285c 100644 --- a/src/doc/nomicon/src/lifetime-mismatch.md +++ b/src/doc/nomicon/src/lifetime-mismatch.md @@ -76,7 +76,7 @@ care about, but the lifetime system is too coarse-grained to handle that. The following code fails to compile, because Rust sees that a variable, `map`, is borrowed twice, and can not infer that the first borrow stops to be needed before the second one occurs. This is caused by Rust conservatively falling back -to using a whole scope for the first borow. This will eventually get fixed. +to using a whole scope for the first borrow. This will eventually get fixed. ```rust,compile_fail # use std::collections::HashMap; diff --git a/src/doc/nomicon/src/lifetimes.md b/src/doc/nomicon/src/lifetimes.md index ef86b7b53..f55ea8c2a 100644 --- a/src/doc/nomicon/src/lifetimes.md +++ b/src/doc/nomicon/src/lifetimes.md @@ -55,7 +55,7 @@ likely desugar to the following: let y: &'b i32 = &'b x; 'c: { // ditto on 'c - let z: &'c &'b i32 = &'c y; + let z: &'c &'b i32 = &'c y; // "a reference to a reference to an i32" (with lifetimes annotated) } } } diff --git a/src/doc/nomicon/src/other-reprs.md b/src/doc/nomicon/src/other-reprs.md index 93da7297e..228b22bda 100644 --- a/src/doc/nomicon/src/other-reprs.md +++ b/src/doc/nomicon/src/other-reprs.md @@ -56,24 +56,26 @@ compiled as normal.) ## repr(transparent) -This can only be used on structs with a single non-zero-sized field (there may -be additional zero-sized fields). The effect is that the layout and ABI of the -whole struct is guaranteed to be the same as that one field. +`#[repr(transparent)]` can only be used on a struct or single-variant enum that has a single non-zero-sized field (there may be additional zero-sized fields). +The effect is that the layout and ABI of the whole struct/enum is guaranteed to be the same as that one field. + +> NOTE: There's a `transparent_unions` nightly feature to apply `repr(transparent)` to unions, +> but it hasn't been stabilized due to design concerns. See the [tracking issue][issue-60405] for more details. The goal is to make it possible to transmute between the single field and the -struct. An example of that is [`UnsafeCell`], which can be transmuted into +struct/enum. An example of that is [`UnsafeCell`], which can be transmuted into the type it wraps ([`UnsafeCell`] also uses the unstable [no_niche][no-niche-pull], so its ABI is not actually guaranteed to be the same when nested in other types). -Also, passing the struct through FFI where the inner field type is expected on -the other side is guaranteed to work. In particular, this is necessary for `struct -Foo(f32)` to always have the same ABI as `f32`. +Also, passing the struct/enum through FFI where the inner field type is expected on +the other side is guaranteed to work. In particular, this is necessary for +`struct Foo(f32)` or `enum Foo { Bar(f32) }` to always have the same ABI as `f32`. This repr is only considered part of the public ABI of a type if either the single field is `pub`, or if its layout is documented in prose. Otherwise, the layout should not be relied upon by other crates. -More details are in the [RFC][rfc-transparent]. +More details are in the [RFC 1758][rfc-transparent] and the [RFC 2645][rfc-transparent-unions-enums]. ## repr(u*), repr(i*) @@ -153,8 +155,10 @@ This is a modifier on `repr(C)` and `repr(Rust)`. It is incompatible with [unsafe code guidelines]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html [drop flags]: drop-flags.html [ub loads]: https://github.com/rust-lang/rust/issues/27060 +[issue-60405]: https://github.com/rust-lang/rust/issues/60405 [`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html [rfc-transparent]: https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md +[rfc-transparent-unions-enums]: https://rust-lang.github.io/rfcs/2645-transparent-unions.html [really-tagged]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md [rust-bindgen]: https://rust-lang.github.io/rust-bindgen/ [cbindgen]: https://github.com/eqrion/cbindgen diff --git a/src/doc/reference/book.toml b/src/doc/reference/book.toml index 2bc218fe4..19b9afc79 100644 --- a/src/doc/reference/book.toml +++ b/src/doc/reference/book.toml @@ -6,6 +6,7 @@ author = "The Rust Project Developers" [output.html] additional-css = ["theme/reference.css"] git-repository-url = "https://github.com/rust-lang/reference/" +edit-url-template = "https://github.com/rust-lang/reference/edit/master/{path}" [output.html.redirect] "/expressions/enum-variant-expr.html" = "struct-expr.html" diff --git a/src/doc/reference/src/attributes/testing.md b/src/doc/reference/src/attributes/testing.md index 63df999ad..2c3b29286 100644 --- a/src/doc/reference/src/attributes/testing.md +++ b/src/doc/reference/src/attributes/testing.md @@ -12,9 +12,8 @@ functions are only compiled when in test mode. Test functions must be free, monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: * `()` -* `Result<(), E> where E: Debug` +* `Result where T: Termination, E: Debug` * `!` - diff --git a/src/doc/reference/src/attributes/type_system.md b/src/doc/reference/src/attributes/type_system.md index 729069d26..71b0243a6 100644 --- a/src/doc/reference/src/attributes/type_system.md +++ b/src/doc/reference/src/attributes/type_system.md @@ -127,6 +127,14 @@ match message { } ``` +It's also not allowed to cast non-exhaustive types from foreign crates. +```rust, ignore +use othercrate::NonExhaustiveEnum; + +// Cannot cast a non-exhaustive enum outside of its defining crate. +let _ = NonExhaustiveEnum::default() as u8; +``` + Non-exhaustive types are always considered inhabited in downstream crates. [_MetaWord_]: ../attributes.md#meta-item-attribute-syntax diff --git a/src/doc/reference/src/crates-and-source-files.md b/src/doc/reference/src/crates-and-source-files.md index 6922b0ee3..8d54c3f6b 100644 --- a/src/doc/reference/src/crates-and-source-files.md +++ b/src/doc/reference/src/crates-and-source-files.md @@ -123,10 +123,9 @@ fn main() -> impl std::process::Termination { > > * `()` > * [`!`] +> * [`Infallible`] > * [`ExitCode`] -> * `Result<(), E> where E: Debug` -> * `Result where E: Debug` - +> * `Result where T: Termination, E: Debug` @@ -165,6 +164,7 @@ or `_` (U+005F) characters. [_shebang_]: https://en.wikipedia.org/wiki/Shebang_(Unix) [_utf8 byte order mark_]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 [`ExitCode`]: ../std/process/struct.ExitCode.html +[`Infallible`]: ../std/convert/enum.Infallible.html [`Termination`]: ../std/process/trait.Termination.html [attribute]: attributes.md [attributes]: attributes.md diff --git a/src/doc/rust-by-example/book.toml b/src/doc/rust-by-example/book.toml index 19db456b6..61fb4057f 100644 --- a/src/doc/rust-by-example/book.toml +++ b/src/doc/rust-by-example/book.toml @@ -6,6 +6,7 @@ author = "The Rust Community" [output.html.playpen] editable = true editor = "ace" +line-numbers = true [output.html.fold] enable = true diff --git a/src/doc/rust-by-example/src/SUMMARY.md b/src/doc/rust-by-example/src/SUMMARY.md index 223a5d8dd..9d7001690 100644 --- a/src/doc/rust-by-example/src/SUMMARY.md +++ b/src/doc/rust-by-example/src/SUMMARY.md @@ -219,4 +219,4 @@ - [Meta](meta.md) - [Documentation](meta/doc.md) - - [Playpen](meta/playpen.md) + - [Playground](meta/playground.md) diff --git a/src/doc/rust-by-example/src/error/option_unwrap/defaults.md b/src/doc/rust-by-example/src/error/option_unwrap/defaults.md index c998ad9ad..eb515aee6 100644 --- a/src/doc/rust-by-example/src/error/option_unwrap/defaults.md +++ b/src/doc/rust-by-example/src/error/option_unwrap/defaults.md @@ -8,7 +8,7 @@ The is more than one way to unpack an `Option` and fall back on a default if it `or()`is chainable and eagerly evaluates its argument, as is shown in the following example. Note that because `or`'s arguments are evaluated eagerly, the variable passed to `or` is moved. -``` +```rust,editable #[derive(Debug)] enum Fruit { Apple, Orange, Banana, Kiwi, Lemon } @@ -33,7 +33,7 @@ fn main() { Another alternative is to use `or_else`, which is also chainable, and evaluates lazily, as is shown in the following example: -``` +```rust,editable #[derive(Debug)] enum Fruit { Apple, Orange, Banana, Kiwi, Lemon } @@ -58,11 +58,11 @@ fn main() { } ``` -## `get_or_insert()` evaluates eagerly, modifies empty value im place +## `get_or_insert()` evaluates eagerly, modifies empty value in place To make sure that an `Option` contains a value, we can use `get_or_insert` to modify it in place with a fallback value, as is shown in the following example. Note that `get_or_insert` eagerly evaluaes its parameter, so variable `apple` is moved: -``` +```rust,editable #[derive(Debug)] enum Fruit { Apple, Orange, Banana, Kiwi, Lemon } @@ -79,10 +79,10 @@ fn main() { } ``` -## `get_or_insert_with()` evaluates lazily, modifies empty value im place +## `get_or_insert_with()` evaluates lazily, modifies empty value in place Instead of explicitly providing a value to fall back on, we can pass a closure to `get_or_insert_with`, as follows: -``` +```rust,editable #[derive(Debug)] enum Fruit { Apple, Orange, Banana, Kiwi, Lemon } diff --git a/src/doc/rust-by-example/src/flow_control.md b/src/doc/rust-by-example/src/flow_control.md index c8a2f9ed8..79ef7e1f6 100644 --- a/src/doc/rust-by-example/src/flow_control.md +++ b/src/doc/rust-by-example/src/flow_control.md @@ -1,4 +1,4 @@ # Flow of Control -An essential part of any programming languages are ways to modify control flow: +An integral part of any programming language are ways to modify control flow: `if`/`else`, `for`, and others. Let's talk about them in Rust. diff --git a/src/doc/rust-by-example/src/hello/print.md b/src/doc/rust-by-example/src/hello/print.md index 34dc9f0dd..c28dd9125 100644 --- a/src/doc/rust-by-example/src/hello/print.md +++ b/src/doc/rust-by-example/src/hello/print.md @@ -31,18 +31,20 @@ fn main() { // Different formatting can be invoked by specifying the format character after a // `:`. - println!("Base 10 repr: {}", 69420); - println!("Base 2 (binary) repr: {:b}", 69420); - println!("Base 8 (octal) repr: {:o}", 69420); - println!("Base 16 (hexadecimal) repr: {:x}", 69420); - println!("Base 16 (hexadecimal) repr: {:X}", 69420); - - // You can right-align text with a specified width. This will output - // " 1". 4 white spaces and a "1", for a total width of 5. + println!("Base 10: {}", 69420); //69420 + println!("Base 2 (binary): {:b}", 69420); //10000111100101100 + println!("Base 8 (octal): {:o}", 69420); //207454 + println!("Base 16 (hexadecimal): {:x}", 69420); //10f2c + println!("Base 16 (hexadecimal): {:X}", 69420); //10F2C + + + // You can right-justify text with a specified width. This will + // output " 1". (Four white spaces and a "1", for a total width of 5.) println!("{number:>5}", number=1); - // You can pad numbers with extra zeroes. This will output "00001". - println!("{number:0>5}", number=1); + // You can pad numbers with extra zeroes, + //and left-adjust by flipping the sign. This will output "10000". + println!("{number:0<5}", number=1); // You can use named arguments in the format specifier by appending a `$` println!("{number:0>width$}", number=1, width=5); diff --git a/src/doc/rust-by-example/src/meta.md b/src/doc/rust-by-example/src/meta.md index 367c7e121..8fcea1df0 100644 --- a/src/doc/rust-by-example/src/meta.md +++ b/src/doc/rust-by-example/src/meta.md @@ -6,7 +6,7 @@ everyone. These topics include: - [Documentation][doc]: Generate library documentation for users via the included `rustdoc`. -- [Playpen][playpen]: Integrate the Rust Playpen (also known as the Rust Playground) in your documentation. +- [Playground][playground]: Integrate the Rust Playground in your documentation. [doc]: meta/doc.md -[playpen]: meta/playpen.md +[playground]: meta/playground.md diff --git a/src/doc/rust-by-example/src/meta/doc.md b/src/doc/rust-by-example/src/meta/doc.md index 63e0b4101..e9e51186f 100644 --- a/src/doc/rust-by-example/src/meta/doc.md +++ b/src/doc/rust-by-example/src/meta/doc.md @@ -44,7 +44,7 @@ impl Person { /// Gives a friendly hello! /// - /// Says "Hello, [name]" to the `Person` it is called on. + /// Says "Hello, [name](Person::name)" to the `Person` it is called on. pub fn hello(& self) { println!("Hello, {}!", self.name); } diff --git a/src/doc/rust-by-example/src/meta/playground.md b/src/doc/rust-by-example/src/meta/playground.md new file mode 100644 index 000000000..7fcfad1a7 --- /dev/null +++ b/src/doc/rust-by-example/src/meta/playground.md @@ -0,0 +1,46 @@ +# Playground + +The [Rust Playground](https://play.rust-lang.org/) is a way to experiment with Rust code through a web interface. + +## Using it with `mdbook` + +In [`mdbook`][mdbook], you can make code examples playable and editable. + +```rust,editable +fn main() { + println!("Hello World!"); +} +``` + +This allows the reader to both run your code sample, but also modify and tweak it. The key here is the adding the word `editable` to your codefence block separated by a comma. + +````markdown +```rust,editable +//...place your code here +``` +```` + +Additionally, you can add `ignore` if you want `mdbook` to skip your code when it builds and tests. + +````markdown +```rust,editable,ignore +//...place your code here +``` +```` + +## Using it with docs + +You may have noticed in some of the [official Rust docs][official-rust-docs] a button that says "Run", which opens the code sample up in a new tab in Rust Playground. This feature is enabled if you use the #[doc] attribute called [`html_playground_url`][html-playground-url]. + +### See also: + +- [The Rust Playground][rust-playground] +- [rust-playground][rust-playground] +- [The rustdoc Book][rustdoc-book] + +[rust-playground]: https://play.rust-lang.org/ +[rust-playground]: https://github.com/integer32llc/rust-playground/ +[mdbook]: https://github.com/rust-lang/mdBook +[official-rust-docs]: https://doc.rust-lang.org/core/ +[rustdoc-book]: https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html +[html-playground-url]: https://doc.rust-lang.org/rustdoc/the-doc-attribute.html#html_playground_url diff --git a/src/doc/rust-by-example/src/meta/playpen.md b/src/doc/rust-by-example/src/meta/playpen.md deleted file mode 100644 index a125f139d..000000000 --- a/src/doc/rust-by-example/src/meta/playpen.md +++ /dev/null @@ -1,46 +0,0 @@ -# Playpen - -The [Rust Playpen](https://github.com/rust-lang/rust-playpen) is a way to experiment with Rust code through a web interface. This project is now commonly referred to as [Rust Playground](https://play.rust-lang.org/). - -## Using it with `mdbook` - -In [`mdbook`][mdbook], you can make code examples playable and editable. - -```rust,editable -fn main() { - println!("Hello World!"); -} -``` - -This allows the reader to both run your code sample, but also modify and tweak it. The key here is the adding the word `editable` to your codefence block separated by a comma. - -````markdown -```rust,editable -//...place your code here -``` -```` - -Additionally, you can add `ignore` if you want `mdbook` to skip your code when it builds and tests. - -````markdown -```rust,editable,ignore -//...place your code here -``` -```` - -## Using it with docs - -You may have noticed in some of the [official Rust docs][official-rust-docs] a button that says "Run", which opens the code sample up in a new tab in Rust Playground. This feature is enabled if you use the #[doc] attribute called [`html_playground_url`][html-playground-url]. - -### See also: - -- [The Rust Playground][rust-playground] -- [The next-gen playpen][next-gen-playpen] -- [The rustdoc Book][rustdoc-book] - -[rust-playground]: https://play.rust-lang.org/ -[next-gen-playpen]: https://github.com/integer32llc/rust-playground/ -[mdbook]: https://github.com/rust-lang/mdBook -[official-rust-docs]: https://doc.rust-lang.org/core/ -[rustdoc-book]: https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html -[html-playground-url]: https://doc.rust-lang.org/rustdoc/the-doc-attribute.html#html_playground_url diff --git a/src/doc/rust-by-example/src/std_misc/threads/testcase_mapreduce.md b/src/doc/rust-by-example/src/std_misc/threads/testcase_mapreduce.md index 28075164f..ee25b1661 100644 --- a/src/doc/rust-by-example/src/std_misc/threads/testcase_mapreduce.md +++ b/src/doc/rust-by-example/src/std_misc/threads/testcase_mapreduce.md @@ -17,9 +17,11 @@ its tiny block of digits, and subsequently we will sum the intermediate sums pro thread. Note that, although we're passing references across thread boundaries, Rust understands that we're -only passing read-only references, and that thus no unsafety or data races can occur. Because -we're `move`-ing the data segments into the thread, Rust will also ensure the data is kept alive -until the threads exit, so no dangling pointers occur. +only passing read-only references, and that thus no unsafety or data races can occur. Also because +the references we're passing have `'static` lifetimes, Rust understands that our data won't be +destroyed while these threads are still running. (When you need to share non-`static` data between +threads, you can use a smart pointer like `Arc` to keep the data alive and avoid non-`static` +lifetimes.) ```rust,editable use std::thread; diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml index 51dc8ecb0..c86ec5638 100644 --- a/src/doc/rustc-dev-guide/book.toml +++ b/src/doc/rustc-dev-guide/book.toml @@ -15,7 +15,7 @@ command = "mdbook-mermaid" [output.html] git-repository-url = "https://github.com/rust-lang/rustc-dev-guide" -edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/tree/master/{path}?mode=edit" +edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/edit/master/{path}" additional-js = ["mermaid.min.js", "mermaid-init.js"] [output.html.fold] diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index bbea2bf38..70fce8b1c 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -3,9 +3,11 @@ use std::{ convert::TryInto as _, env, fmt, fs, path::{Path, PathBuf}, + process, + str::FromStr, }; -use chrono::{Datelike as _, TimeZone as _, Utc}; +use chrono::{Datelike as _, Month, TimeZone as _, Utc}; use glob::glob; use regex::Regex; @@ -38,12 +40,18 @@ impl fmt::Display for Date { fn make_date_regex() -> Regex { Regex::new( r"(?x) # insignificant whitespace mode - ", + ( + ) + | + (\s+ + (?P[[:alpha:]]+)\s+ + (?P\d{4})\b + ) + ", ) .unwrap() } @@ -52,15 +60,22 @@ fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)> let mut line = 1; let mut end_of_last_cap = 0; date_regex - .captures_iter(&text) - .map(|cap| { - ( - cap.get(0).unwrap().range(), - Date { - year: cap["y"].parse().unwrap(), - month: cap["m"].parse().unwrap(), - }, - ) + .captures_iter(text) + .filter_map(|cap| { + if let (Some(month), Some(year), None, None) | (None, None, Some(month), Some(year)) = ( + cap.name("m1"), + cap.name("y1"), + cap.name("m2"), + cap.name("y2"), + ) { + let year = year.as_str().parse().expect("year"); + let month = Month::from_str(month.as_str()) + .expect("month") + .number_from_month(); + Some((cap.get(0).expect("all").range(), Date { year, month })) + } else { + None + } }) .map(|(byte_range, date)| { line += text[end_of_last_cap..byte_range.end] @@ -110,9 +125,12 @@ fn filter_dates( } fn main() { - let root_dir = env::args() - .nth(1) - .expect("expect root Markdown directory as CLI argument"); + let mut args = env::args(); + if args.len() == 1 { + eprintln!("error: expected root Markdown directory as CLI argument"); + process::exit(1); + } + let root_dir = args.nth(1).unwrap(); let root_dir_path = Path::new(&root_dir); let glob_pat = format!("{}/**/*.md", root_dir); let today_chrono = Utc::today(); @@ -136,7 +154,7 @@ fn main() { up-to-date. Each date should be updated (in the Markdown file where it appears) to \ use the current month ({current_month}), or removed if the docs it annotates are not \ expected to fall out of date quickly.", - current_month = current_month + current_month = today_chrono.format("%B %Y"), ); println!(); println!( @@ -153,7 +171,7 @@ fn main() { for (path, dates) in dates_by_file { println!( "- [ ] {}", - path.strip_prefix(&root_dir_path).unwrap().display() + path.strip_prefix(&root_dir_path).unwrap_or(&path).display(), ); for (line, date) in dates { println!(" - [ ] line {}: {}", line, date); @@ -182,61 +200,153 @@ mod tests { #[test] fn test_date_regex() { - let regex = make_date_regex(); - assert!(regex.is_match("foo bar")); + let regex = &make_date_regex(); + assert!(regex.is_match("")); + assert!(regex.is_match("")); + assert!(regex.is_match("")); + assert!(regex.is_match("")); + assert!(regex.is_match(" jan 2021")); + assert!(regex.is_match(" january 2021")); + assert!(regex.is_match(" Jan 2021")); + assert!(regex.is_match(" January 2021")); + + assert!(regex.is_match(" jan 2021 ")); + assert!(regex.is_match(" jan 2021.")); } #[test] - fn test_date_regex_capitalized() { - let regex = make_date_regex(); - assert!(regex.is_match("foo bar")); + fn test_date_regex_fail() { + let regexes = &make_date_regex(); + assert!(!regexes.is_match("")); + assert!(!regexes.is_match("")); + assert!(!regexes.is_match("")); + assert!(!regexes.is_match(" jan 221")); + assert!(!regexes.is_match(" jan 20222")); + assert!(!regexes.is_match(" 01 2021")); } #[test] fn test_collect_dates_from_file() { - let text = "Test1\n\nTest2\nFoo\nTest3\nTest4\nFooBar\n\nTest5\nTest6\nTest7\n\nTest8 + let text = r" +Test1 + +Test2 +Foo +Test3 +Test4 +FooBar + +Test5 +Test6 +Test7 + +Test8 +Test1 + jan 2021 +Test2 +Foo february 2021 +Test3 +Test4 +Foo mar 2021 Bar + apr 2021 +Test5 +Test6 +Test7 + may 2021 +Test8 + june 2021. "; assert_eq!( collect_dates_from_file(&make_date_regex(), text), vec![ ( - 2, + 3, + Date { + year: 2021, + month: 1, + } + ), + ( + 6, + Date { + year: 2021, + month: 2, + } + ), + ( + 9, + Date { + year: 2021, + month: 3, + } + ), + ( + 11, + Date { + year: 2021, + month: 4, + } + ), + ( + 17, + Date { + year: 2021, + month: 5, + } + ), + ( + 20, Date { year: 2021, month: 1, } ), ( - 4, + 23, Date { year: 2021, month: 2, } ), ( - 7, + 26, Date { year: 2021, month: 3, } ), ( - 8, + 28, Date { year: 2021, month: 4, } ), ( - 14, + 34, Date { year: 2021, month: 5, } ), - ] + ( + 38, + Date { + year: 2021, + month: 6, + } + ), + ], ); } } diff --git a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md index 271e6a16f..ea50cd754 100644 --- a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md +++ b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md @@ -2,15 +2,12 @@ -As of October 2021, `rustc_codegen_ssa` provides an +As of Aug 2022, `rustc_codegen_ssa` provides an abstract interface for all backends to implement, to allow other codegen backends (e.g. [Cranelift]). [Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/HEAD/cranelift -> The following is a copy/paste of a README from the rust-lang/rust repo. -> Please submit a PR if it needs updating. - # Refactoring of `rustc_codegen_llvm` by Denis Merigoux, October 23rd 2018 diff --git a/src/doc/rustc-dev-guide/src/backend/codegen.md b/src/doc/rustc-dev-guide/src/backend/codegen.md index 1a6c2fa76..5feea5202 100644 --- a/src/doc/rustc-dev-guide/src/backend/codegen.md +++ b/src/doc/rustc-dev-guide/src/backend/codegen.md @@ -1,13 +1,16 @@ # Code generation -Code generation or "codegen" is the part of the compiler that actually -generates an executable binary. Usually, rustc uses LLVM for code generation; -there is also support for [Cranelift]. The key is that rustc doesn't implement -codegen itself. It's worth noting, though, that in the Rust source code, many -parts of the backend have `codegen` in their names (there are no hard -boundaries). - -[Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/HEAD/cranelift +Code generation (or "codegen") is the part of the compiler +that actually generates an executable binary. +Usually, rustc uses LLVM for code generation, +bu there is also support for [Cranelift] and [GCC]. +The key is that rustc doesn't implement codegen itself. +It's worth noting, though, that in the Rust source code, +many parts of the backend have `codegen` in their names +(there are no hard boundaries). + +[Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/main/cranelift +[GCC]: https://github.com/rust-lang/rustc_codegen_gcc > NOTE: If you are looking for hints on how to debug code generation bugs, > please see [this section of the debugging chapter][debugging]. diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 0de0767b6..81ebbbb40 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -43,7 +43,7 @@ the branch we're already using. The steps for this are: 1. Make sure the bugfix is in upstream LLVM. 2. Identify the branch that rustc is currently using. The `src/llvm-project` submodule is always pinned to a branch of the - [rust-lang/llvm-project](https://github.com/rust-lang/llvm-project) repository. + [rust-lang/llvm-project repository]. 3. Fork the rust-lang/llvm-project repository 4. Check out the appropriate branch (typically named `rustc/a.b-yyyy-mm-dd`) 5. Cherry-pick the upstream commit onto the branch @@ -66,8 +66,8 @@ Example PRs look like: ## Feature updates -> Note that this information is as of the time of this writing (October 2021). The process for updating LLVM changes with +> Note that this information is as of the time of this writing, October 2021. The process for updating LLVM changes with practically all LLVM updates, so this may be out of date! Unlike bugfixes, updating to pick up a new feature of LLVM typically requires a @@ -146,9 +146,6 @@ easiest to land [`llvm-wrapper`] compatibility as a PR before actually updating interested in trying out the new LLVM can benefit from work you've done to update the C++ bindings. -[rust-lang/llvm-project repository]: https://github.com/rust-lang/llvm-project -[`llvm-wrapper`]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_llvm/llvm-wrapper - ### Caveats and gotchas Ideally the above instructions are pretty smooth, but here's some caveats to @@ -161,8 +158,6 @@ keep in mind while going through them: * Creating branches is a privileged operation on GitHub, so you'll need someone with write access to create the branches for you most likely. -[wg-llvm]: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm - ## New LLVM Release Updates Updating to a new release of LLVM is very similar to the "feature updates" @@ -172,7 +167,7 @@ section above is generally around branch naming. The sequence of events typically looks like: 1. LLVM announces that its latest release version has branched. This will show - up as a branch in https://github.com/llvm/llvm-project typically named + up as a branch in the [llvm/llvm-project repository] typically named `release/$N.x` where `$N` is the version of LLVM that's being released. 2. We then follow the "feature updates" section above to create a new branch of @@ -192,3 +187,8 @@ typically looks like: to create a new branch in the rust-lang/llvm-project repository, this time with a new date. The commit history should look much cleaner as just a few Rust-specific commits stacked on top of stock LLVM's release branch. + +[rust-lang/llvm-project repository]: https://github.com/rust-lang/llvm-project +[llvm/llvm-project repository]: https://github.com/llvm/llvm-project +[`llvm-wrapper`]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_llvm/llvm-wrapper +[wg-llvm]: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md index c7c107e1e..e236e0124 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md @@ -94,7 +94,7 @@ member constraints come in. ## Choices are always lifetime parameters At present, the "choice" regions from a member constraint are always lifetime -parameters from the current function. As of October 2021, +parameters from the current function. As of October 2021, this falls out from the placement of impl Trait, though in the future it may not be the case. We take some advantage of this fact, as it simplifies the current code. In particular, we don't have to consider a case like `'0 member of ['1, diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping.md b/src/doc/rustc-dev-guide/src/building/bootstrapping.md index fd54de20c..939c47f1b 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping.md @@ -18,7 +18,34 @@ rustc, then uses it to compile the new compiler. ## Stages of bootstrapping -Compiling `rustc` is done in stages. +Compiling `rustc` is done in stages. Here's a diagram, adapted from Joshua Nelson's +[talk on bootstrapping][rustconf22-talk] at RustConf 2022, with detailed explanations below. + +The `A`, `B`, `C`, and `D` show the ordering of the stages of bootstrapping. +Blue nodes are downloaded, +yellow nodes are built with the +stage0 compiler, and +green nodes are built with the +stage1 compiler. + +[rustconf22-talk]: https://rustconf.com/schedule#bootstrapping-the-once-and-future-compiler + +```mermaid +graph TD + s0c["stage0 compiler (1.63)"]:::downloaded -->|A| s0l("stage0 std (1.64)"):::with-s0c; + s0c & s0l --- stepb[ ]:::empty; + stepb -->|B| s0ca["stage0 compiler artifacts (1.64)"]:::with-s0c; + s0ca -->|copy| s1c["stage1 compiler (1.64)"]:::with-s0c; + s1c -->|C| s1l("stage1 std (1.64)"):::with-s1c; + s1c & s1l --- stepd[ ]:::empty; + stepd -->|D| s1ca["stage1 compiler artifacts (1.64)"]:::with-s1c; + s1ca -->|copy| s2c["stage2 compiler"]:::with-s1c; + + classDef empty width:0px,height:0px; + classDef downloaded fill: lightblue; + classDef with-s0c fill: yellow; + classDef with-s1c fill: lightgreen; +``` ### Stage 0 diff --git a/src/doc/rustc-dev-guide/src/building/prerequisites.md b/src/doc/rustc-dev-guide/src/building/prerequisites.md index a5ab23d91..0783e82ee 100644 --- a/src/doc/rustc-dev-guide/src/building/prerequisites.md +++ b/src/doc/rustc-dev-guide/src/building/prerequisites.md @@ -12,7 +12,8 @@ Before building the compiler, you need the following things installed: If building LLVM from source (the default), you'll need additional tools: -* `g++` 5.1 or later, `clang++` 3.5 or later, or MSVC 2017 or later. +* `g++`, `clang++`, or MSVC with versions listed on + [LLVM's documentation](https://releases.llvm.org/13.0.0/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library) * `ninja`, or GNU `make` 3.81 or later (ninja is recommended, especially on Windows) * `cmake` 3.13.4 or later diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 1c2229335..3e077977d 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -22,7 +22,7 @@ You can also install the hook as a step of running `./x.py setup`! a file. By default, `rust-analyzer` runs the `cargo check` and `rustfmt` commands, but you can override these commands to use more adapted versions of these tools when hacking on `rustc`. For example, for Visual Studio Code, -you can write: +you can write: ```JSON { diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 8f46e896e..35458b55c 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -16,9 +16,36 @@ set `debug = true` in your config.toml. Setting `debug = true` turns on many different debug options (e.g., `debug-assertions`, `debug-logging`, etc.) which can be individually tweaked if you want to, but many people -simply set `debug = true`. Check out the comments in config.toml.example for more info. +simply set `debug = true`. -You will need to rebuild the compiler once you've changed any configuration options. +If you want to use GDB to debug rustc, please set `config.toml` with options: + +```toml +[rust] +debug = true +debuginfo-level = 2 +``` + +> NOTE: +> This will use a lot of disk space +> (upwards of 35GB), +> and will take a lot more compile time. +> With `debuginfo-level = 1` (the default when `debug = true`), +> you will be able to track the execution path, +> but will lose the symbol information for debugging. + +The default configuration will enable `symbol-mangling-version` v0. +This requires at least GDB v10.2, +otherwise you need to disable new symbol-mangling-version in `config.toml`. + +```toml +[rust] +new-symbol-mangling = false +``` + +> See the comments in `config.toml.example` for more info. + +You will need to rebuild the compiler after changing any configuration option. ## `-Z` flags diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 45f8c9033..e59bb0a77 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -437,17 +437,35 @@ Just a few things to keep in mind: the project. - The date the comment was added, e.g. instead of writing _"Currently, ..."_ - or _"As of now, ..."_, consider writing - _"As of January 2021, ..."_. - Try to format the date as ` ` to ease search. + or _"As of now, ..."_, + consider adding the date, in one of the following formats: + - Jan 2021 + - January 2021 + - jan 2021 + - january 2021 - - Additionally, include a machine-readable comment of the form `` (if the current month is April 2022). We have an automated - tool that uses these (in `ci/date-check`). + There is a CI action (in `~/.github/workflows/date-check.yml`) + that generates a monthly issue with any of these that are over 6 months old. - So, for the month of April 2022, the comment would look like: `As of April 2022`. Make sure to put the comment *between* `as of` - and `April 2022`; see [PR #1066][rdg#1066] for the rationale. + For the action to pick the date, + add a special annotation before specifying the date: + + ```md + Jul 2022 + ``` + + Example: + + ```md + As of Jul 2022, the foo did the bar. + ``` + + For cases where the date should not be part of the visible rendered output, + use the following instead: + + ```md + + ``` - A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide further explanation for the change process or a way to verify that the information is not @@ -459,7 +477,6 @@ Just a few things to keep in mind: [rdg]: https://rustc-dev-guide.rust-lang.org/ [rdgrepo]: https://github.com/rust-lang/rustc-dev-guide -[rdg#1066]: https://github.com/rust-lang/rustc-dev-guide/pull/1066 ## Issue Triage diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 15d125377..0d5f17b99 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -14,14 +14,14 @@ special config, so this may result in different style from normal [`rustfmt`]. Therefore, formatting this repository using `cargo fmt` is not recommended. Instead, formatting should be done using `./x.py fmt`. It's a good habit to run -`./x.py fmt` before every commit, as this reduces conflicts later. +`./x.py fmt` before every commit, as this reduces conflicts later. Formatting is checked by the `tidy` script. It runs automatically when you do `./x.py test` and can be run in isolation with `./x.py fmt --check`. If you want to use format-on-save in your editor, the pinned version of `rustfmt` is built under `build//stage0/bin/rustfmt`. You'll have to -pass the `--edition=2021` argument yourself when calling +pass the `--edition=2021` argument yourself when calling `rustfmt` directly. [fmt]: https://github.com/rust-dev-tools/fmt-rfcs diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 8c8fd0c38..f012c5bb5 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -1,20 +1,20 @@ # crates.io Dependencies The Rust compiler supports building with some dependencies from `crates.io`. -For example, `log` and `env_logger` come from `crates.io`. +Examples are `log` and `env_logger`. -In general, you should avoid adding dependencies to the compiler for several -reasons: +In general, +you should avoid adding dependencies to the compiler for several reasons: -- The dependency may not be high quality or well-maintained, whereas we want - the compiler to be high-quality. +- The dependency may not be of high quality or well-maintained. - The dependency may not be using a compatible license. - The dependency may have transitive dependencies that have one of the above problems. -As of February 2022, there is no official policy for vetting -new dependencies to the compiler. Generally, new dependencies are not added -to the compiler unless there is a good reason to do so. +As of Aug 2022, +there is no official policy for vetting new dependencies to the compiler. +Decisions are made on a case-by-case basis, +during code review. ## Permitted dependencies diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md index b6b6e0fa9..dcaba533e 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md @@ -1,4 +1,5 @@ # Diagnostic Items + While writing lints it's common to check for specific types, traits and functions. This raises the question on how to check for these. Types can be checked by their complete type path. However, this requires hard coding paths @@ -7,7 +8,8 @@ rustc has introduced diagnostic items that are used to identify types via [`Symbol`]s. ## Finding diagnostic items -Diagnostic items are added to items inside `rustc`/`std`/`core` with the + +Diagnostic items are added to items inside `rustc`/`std`/`core`/`alloc` with the `rustc_diagnostic_item` attribute. The item for a specific type can be found by opening the source code in the documentation and looking for this attribute. Note that it's often added with the `cfg_attr` attribute to avoid compilation @@ -19,12 +21,15 @@ errors during tests. A definition often looks like this: struct Penguin; ``` -Diagnostic items are usually only added to traits, types and standalone -functions. If the goal is to check for an associated type or method, please use -the diagnostic item of the item and reference [*How To Use Diagnostic -Items*](#how-to-use-diagnostic-items). +Diagnostic items are usually only added to traits, +types, +and standalone functions. +If the goal is to check for an associated type or method, +please use the diagnostic item of the item and reference +[*Using Diagnostic Items*](#using-diagnostic-items). ## Adding diagnostic items + A new diagnostic item can be added with these two steps: 1. Find the target item inside the Rust repo. Now add the diagnostic item as a @@ -43,45 +48,55 @@ A new diagnostic item can be added with these two steps: For the naming conventions of diagnostic items, please refer to [*Naming Conventions*](#naming-conventions). -2. As of February 2022, diagnostic items in code are - accessed via symbols in [`rustc_span::symbol::sym`]. To add your newly - created diagnostic item simply open the module file and add the name (In - this case `Cat`) at the correct point in the list. +2. + Diagnostic items in code are accessed via symbols in + [`rustc_span::symbol::sym`]. + To add your newly-created diagnostic item, + simply open the module file, + and add the name (In this case `Cat`) at the correct point in the list. -Now you can create a pull request with your changes. :tada: (Note that when -using diagnostic items in other projects like Clippy, it might take some time -until the repos get synchronized.) +Now you can create a pull request with your changes. :tada: + +> NOTE: +> When using diagnostic items in other projects like Clippy, +> it might take some time until the repos get synchronized. ## Naming conventions -Diagnostic items don't have a set in stone naming convention yet. These are -some guidelines that should be used for the future, but might differ from -existing names: - -* Types, traits and enums are named using UpperCamelCase (Examples: `Iterator`, -* `HashMap`, ...) -* For type names that are used multiple times like `Writer` it's good to choose - a more precise name, maybe by adding the module to it. (Example: `IoWriter`) -* Associated items should not get their own diagnostic items, but instead be - accessed indirectly by the diagnostic item of the type they're originating - from. + +Diagnostic items don't have a naming convention yet. +Following are some guidelines that should be used in future, +but might differ from existing names: + +* Types, traits, and enums are named using UpperCamelCase + (Examples: `Iterator` and `HashMap`) +* For type names that are used multiple times, + like `Writer`, + it's good to choose a more precise name, + maybe by adding the module to it + (Example: `IoWriter`) +* Associated items should not get their own diagnostic items, + but instead be accessed indirectly by the diagnostic item + of the type they're originating from. * Freestanding functions like `std::mem::swap()` should be named using - `snake_case` with one important (export) module as a prefix (Example: - `mem_swap`, `cmp_max`) + `snake_case` with one important (export) module as a prefix + (Examples: `mem_swap` and `cmp_max`) * Modules should usually not have a diagnostic item attached to them. - Diagnostic items were added to avoid the usage of paths, using them on - modules would therefore most likely to be counterproductive. + Diagnostic items were added to avoid the usage of paths, + and using them on modules would therefore most likely be counterproductive. ## Using diagnostic items + In rustc, diagnostic items are looked up via [`Symbol`]s from inside the [`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s using [`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`] using [`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to a [`DefId`], the method will return a `Option`. This can be `None` if either the symbol isn't a diagnostic item or the type is not registered, for -instance when compiling with `#[no_std]`. All following examples are based on -[`DefId`]s and their usage. +instance when compiling with `#[no_std]`. +All the following examples are based on [`DefId`]s and their usage. ### Example: Checking for a type + ```rust use rustc_span::symbol::sym; @@ -96,6 +111,7 @@ fn example_1(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { ``` ### Example: Checking for a trait implementation + ```rust /// This example checks if a given [`DefId`] from a method is part of a trait /// implementation defined by a diagnostic item. @@ -112,6 +128,7 @@ fn is_diag_trait_item( ``` ### Associated Types + Associated types of diagnostic items can be accessed indirectly by first getting the [`DefId`] of the trait and then calling [`TyCtxt::associated_items()`]. This returns an [`AssocItems`] object which can @@ -119,13 +136,15 @@ be used for further checks. Checkout [`clippy_utils::ty::get_iterator_item_ty()`] for an example usage of this. ### Usage in Clippy + Clippy tries to use diagnostic items where possible and has developed some wrapper and utility functions. Please also refer to its documentation when using diagnostic items in Clippy. (See [*Common tools for writing lints*][clippy-Common-tools-for-writing-lints].) ## Related issues -This lists some related issues. These are probably only interesting to people + +These are probably only interesting to people who really want to take a deep dive into the topic :) * [rust#60966]: The Rust PR that introduced diagnostic items diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index f28350e03..f456474c7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -17,45 +17,43 @@ shown below: ```rust,ignore #[derive(SessionDiagnostic)] -#[error(typeck::field_already_declared, code = "E0124")] +#[diag(typeck::field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] #[label] pub span: Span, - #[label = "previous-decl-label"] + #[label(typeck::previous_decl_label)] pub prev_span: Span, } ``` `SessionDiagnostic` can only be applied to structs. Every `SessionDiagnostic` -has to have one attribute applied to the struct itself: either `#[error(..)]` -for defining errors, or `#[warning(..)]` for defining warnings. +has to have one attribute, `#[diag(...)]`, applied to the struct itself. If an error has an error code (e.g. "E0624"), then that can be specified using the `code` sub-attribute. Specifying a `code` isn't mandatory, but if you are porting a diagnostic that uses `DiagnosticBuilder` to use `SessionDiagnostic` then you should keep the code if there was one. -Both `#[error(..)]` and `#[warning(..)]` must provide a slug as the first -positional argument (a path to an item in `rustc_errors::fluent::*`). A slug -uniquely identifies the diagnostic and is also how the compiler knows what -error message to emit (in the default locale of the compiler, or in the locale -requested by the user). See [translation documentation](./translation.md) to -learn more about how translatable error messages are written and how slug -items are generated. +`#[diag(..)]` must provide a slug as the first positional argument (a path to an +item in `rustc_errors::fluent::*`). A slug uniquely identifies the diagnostic +and is also how the compiler knows what error message to emit (in the default +locale of the compiler, or in the locale requested by the user). See +[translation documentation](./translation.md) to learn more about how +translatable error messages are written and how slug items are generated. In our example, the Fluent message for the "field already declared" diagnostic looks like this: ```fluent -typeck-field-already-declared = +typeck_field_already_declared = field `{$field_name}` is already declared .label = field already declared - .previous-decl-label = `{$field_name}` first declared here + .previous_decl_label = `{$field_name}` first declared here ``` -`typeck-field-already-declared` is the slug from our example and is followed +`typeck_field_already_declared` is the slug from our example and is followed by the diagnostic message. Every field of the `SessionDiagnostic` which does not have an annotation is @@ -75,10 +73,10 @@ type `Span`. Applying any of these attributes will create the corresponding subdiagnostic with that `Span`. These attributes will look for their diagnostic message in a Fluent attribute attached to the primary Fluent message. In our example, `#[label]` will look for -`typeck-field-already-declared.label` (which has the message "field already +`typeck_field_already_declared.label` (which has the message "field already declared"). If there is more than one subdiagnostic of the same type, then these attributes can also take a value that is the attribute name to look for -(e.g. `previous-decl-label` in our example). +(e.g. `previous_decl_label` in our example). Other types have special behavior when used in a `SessionDiagnostic` derive: @@ -95,38 +93,35 @@ represent optional `#[note]`/`#[help]` subdiagnostics. Suggestions can be emitted using one of four field attributes: -- `#[suggestion(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_hidden(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_short(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_verbose(message = "...", code = "...", applicability = "...")]` +- `#[suggestion(slug, code = "...", applicability = "...")]` +- `#[suggestion_hidden(slug, code = "...", applicability = "...")]` +- `#[suggestion_short(slug, code = "...", applicability = "...")]` +- `#[suggestion_verbose(slug, code = "...", applicability = "...")]` Suggestions must be applied on either a `Span` field or a `(Span, -MachineApplicability)` field. Similarly to other field attributes, `message` -specifies the Fluent attribute with the message and defaults to `.suggestion`. -`code` specifies the code that should be suggested as a replacement and is a -format string (e.g. `{field_name}` would be replaced by the value of the -`field_name` field of the struct), not a Fluent identifier. `applicability` can -be used to specify the applicability in the attribute, it cannot be used when -the field's type contains an `Applicability`. +MachineApplicability)` field. Similarly to other field attributes, the slug +specifies the Fluent attribute with the message and defaults to the equivalent +of `.suggestion`. `code` specifies the code that should be suggested as a +replacement and is a format string (e.g. `{field_name}` would be replaced by +the value of the `field_name` field of the struct), not a Fluent identifier. +`applicability` can be used to specify the applicability in the attribute, it +cannot be used when the field's type contains an `Applicability`. In the end, the `SessionDiagnostic` derive will generate an implementation of `SessionDiagnostic` that looks like the following: ```rust,ignore -impl SessionDiagnostic for FieldAlreadyDeclared { +impl SessionDiagnostic<'_> for FieldAlreadyDeclared { fn into_diagnostic(self, sess: &'_ rustc_session::Session) -> DiagnosticBuilder<'_> { - let mut diag = sess.struct_err_with_code( - rustc_errors::DiagnosticMessage::fluent("typeck-field-already-declared"), - rustc_errors::DiagnosticId::Error("E0124") - ); + let mut diag = sess.struct_err(rustc_errors::fluent::typeck::field_already_declared); diag.set_span(self.span); diag.span_label( self.span, - rustc_errors::DiagnosticMessage::fluent_attr("typeck-field-already-declared", "label") + rustc_errors::fluent::typeck::label ); diag.span_label( self.prev_span, - rustc_errors::DiagnosticMessage::fluent_attr("typeck-field-already-declared", "previous-decl-label") + rustc_errors::fluent::typeck::previous_decl_label ); diag } @@ -146,12 +141,13 @@ tcx.sess.emit_err(FieldAlreadyDeclared { ``` ### Reference -`#[derive(SessionDiagnostic)]` supports the following attributes: +`#[derive(SessionDiagnostic)]` and `#[derive(LintDiagnostic)]` support the +following attributes: -- `#[error(slug, code = "...")]` or `#[warning(slug, code = "...")]` +- `#[diag(slug, code = "...")]` - _Applied to struct._ - _Mandatory_ - - Defines the struct to be representing an error or a warning. + - Defines the text and error code to be associated with the diagnostic. - Slug (_Mandatory_) - Uniquely identifies the diagnostic and corresponds to its Fluent message, mandatory. @@ -164,34 +160,48 @@ tcx.sess.emit_err(FieldAlreadyDeclared { - See [translation documentation](./translation.md). - `code = "..."` (_Optional_) - Specifies the error code. -- `#[note]` or `#[note = "..."]` (_Optional_) +- `#[note]` or `#[note(slug)]` (_Optional_) - _Applied to struct or `Span`/`()` fields._ - Adds a note subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the note's message - - Defaults to `note`. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.note`. - If applied to a `Span` field, creates a spanned note. -- `#[help]` or `#[help = "..."]` (_Optional_) +- `#[help]` or `#[help(slug)]` (_Optional_) - _Applied to struct or `Span`/`()` fields._ - Adds a help subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the help's message. - - Defaults to `help`. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.help`. - If applied to a `Span` field, creates a spanned help. -- `#[label]` or `#[label = "..."]` (_Optional_) +- `#[label]` or `#[label(slug)]` (_Optional_) - _Applied to `Span` fields._ - Adds a label subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the label's message. - - Defaults to `label`. -- `#[suggestion{,_hidden,_short,_verbose}(message = "...", code = "...", applicability = "...")]` + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.label`. +- `#[warn_]` or `#[warn_(slug)]` (_Optional_) + - _Applied to `Span` fields._ + - Adds a warning subdiagnostic. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.warn`. +- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` (_Optional_) - _Applied to `(Span, MachineApplicability)` or `Span` fields._ - Adds a suggestion subdiagnostic. - - `message = "..."` (_Mandatory_) - - Value is the Fluent attribute (relative to the Fluent message specified - by `slug`) for the suggestion's message. - - Defaults to `suggestion`. + - Slug (_Mandatory_) + - A path to an item in `rustc_errors::fluent`. Always in a module starting + with a Fluent resource name (which is typically the name of the crate + that the diagnostic is from), e.g. + `rustc_errors::fluent::typeck::field_already_declared` + (`rustc_errors::fluent` is implicit in the attribute, so just + `typeck::field_already_declared`). Fluent attributes for all messages + exist as top-level items in that module (so `typeck_message.attr` is just + `typeck::attr`). + - See [translation documentation](./translation.md). + - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or + - `.suggestion` in Fluent). - `code = "..."` (_Mandatory_) - Value is a format string indicating the code to be suggested as a replacement. @@ -203,7 +213,7 @@ tcx.sess.emit_err(FieldAlreadyDeclared { `#[derive(SessionSubdiagnostic)]`)._ - Adds the subdiagnostic represented by the subdiagnostic struct. - `#[primary_span]` (_Optional_) - - _Applied to `Span` fields._ + - _Applied to `Span` fields on `SessionSubdiagnostic`s. Not used for `LintDiagnostic`s._ - Indicates the primary span of the diagnostic. - `#[skip_arg]` (_Optional_) - _Applied to any field._ @@ -258,9 +268,9 @@ In our example, the Fluent message for the "expected return type" label looks like this: ```fluent -typeck-expected-default-return-type = expected `()` because of default return type +typeck_expected_default_return_type = expected `()` because of default return type -typeck-expected-return-type = expected `{$expected}` because of return type +typeck_expected_return_type = expected `{$expected}` because of return type ``` Using the `#[primary_span]` attribute on a field (with type `Span`) will denote @@ -276,16 +286,17 @@ Like `SessionDiagnostic`, `SessionSubdiagnostic` supports `Option` and Suggestions can be emitted using one of four attributes on the type/variant: -- `#[suggestion(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_hidden(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_short(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_verbose(message = "...", code = "...", applicability = "...")]` +- `#[suggestion(..., code = "...", applicability = "...")]` +- `#[suggestion_hidden(..., code = "...", applicability = "...")]` +- `#[suggestion_short(..., code = "...", applicability = "...")]` +- `#[suggestion_verbose(..., code = "...", applicability = "...")]` Suggestions require `#[primary_span]` be set on a field and can have the following sub-attributes: -- `message` specifies the Fluent attribute with the message and defaults to - `.suggestion`. +- The first positional argument specifies the path to a item in + `rustc_errors::fluent` corresponding to the Fluent attribute with the message + and defaults to the equivalent of `.suggestion`. - `code` specifies the code that should be suggested as a replacement and is a format string (e.g. `{field_name}` would be replaced by the value of the `field_name` field of the struct), not a Fluent identifier. @@ -304,11 +315,11 @@ impl<'tcx> AddToDiagnostic for ExpectedReturnTypeLabel<'tcx> { use rustc_errors::{Applicability, IntoDiagnosticArg}; match self { ExpectedReturnTypeLabel::Unit { span } => { - diag.span_label(span, DiagnosticMessage::fluent("typeck-expected-default-return-type")) + diag.span_label(span, rustc_errors::fluent::typeck::expected_default_return_type) } ExpectedReturnTypeLabel::Other { span, expected } => { diag.set_arg("expected", expected); - diag.span_label(span, DiagnosticMessage::fluent("typeck-expected-return-type")) + diag.span_label(span, rustc_errors::fluent::typeck::expected_return_type) } } @@ -338,14 +349,22 @@ diagnostic struct. (`rustc_errors::fluent` is implicit in the attribute, so just `typeck::field_already_declared`). - See [translation documentation](./translation.md). -- `#[suggestion{,_hidden,_short,_verbose}(message = "...", code = "...", applicability = "...")]` +- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._ - _Mandatory_ - Defines the type to be representing a suggestion. - - `message = "..."` (_Mandatory_) - - Value is the Fluent attribute (relative to the Fluent message specified - by `slug`) for the suggestion's message. - - Defaults to `suggestion`. + - Slug (_Mandatory_) + - A path to an item in `rustc_errors::fluent`. Always in a module starting + with a Fluent resource name (which is typically the name of the crate + that the diagnostic is from), e.g. + `rustc_errors::fluent::typeck::field_already_declared` + (`rustc_errors::fluent` is implicit in the attribute, so just + `typeck::field_already_declared`). Fluent attributes for all messages + exist as top-level items in that module (so `typeck_message.attr` is just + `typeck::attr`). + - See [translation documentation](./translation.md). + - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or + - `.suggestion` in Fluent). - `code = "..."` (_Mandatory_) - Value is a format string indicating the code to be suggested as a replacement. diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md index 39007f8d1..33d9646f6 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md @@ -1,4 +1,5 @@ # Lints + This page documents some of the machinery around lint registration and how we run lints in the compiler. @@ -8,6 +9,7 @@ everything rotates. It's not available during the early parts of compilation lints, which can only happen after plugin registration. ## Lints vs. lint passes + There are two parts to the linting mechanism within the compiler: lints and lint passes. Unfortunately, a lot of the documentation we have refers to both of these as just "lints." @@ -15,11 +17,18 @@ of these as just "lints." First, we have the lint declarations themselves: this is where the name and default lint level and other metadata come from. These are normally defined by way of the [`declare_lint!`] macro, which boils down to a static with type -`&rustc_session::lint::Lint`. +[`&rustc_lint_defs::Lint`]. + +First, we have the lint declarations themselves, +and this is where the name and default lint level and other metadata come from. +These are normally defined by way of the [`declare_lint!`] macro, +which boils down to a static with type [`&rustc_lint_defs::Lint`] +(although this may change in the future, +as the macro is somewhat unwieldy to add new fields to, +like all macros). -As of February 2022, we lint against direct declarations -without the use of the macro today (although this may change in the future, as -the macro is somewhat unwieldy to add new fields to, like all macros). +As of Aug 2022, +we lint against direct declarations without the use of the macro. Lint declarations don't carry any "state" - they are merely global identifiers and descriptions of lints. We assert at runtime that they are not registered @@ -34,8 +43,10 @@ lints are emitted as part of other work (e.g., type checking, etc.). ## Registration ### High-level overview -In [`rustc_interface::register_plugins`] the [`LintStore`] is created and all -lints are registered. + +In [`rustc_interface::register_plugins`], +the [`LintStore`] is created, +and all lints are registered. There are four 'sources' of lints: @@ -61,6 +72,7 @@ then invoke the lint pass methods. The lint pass methods take `&mut self` so they can keep track of state internally. #### Internal lints + These are lints used just by the compiler or plugins like `clippy`. They can be found in `rustc_lint::internal`. @@ -73,16 +85,20 @@ function which is called when constructing a new lint store inside [`rustc_lint::new_lint_store`]. ### Builtin Lints -These are primarily described in two places: `rustc_session::lint::builtin` and -`rustc_lint::builtin`. Often the first provides the definitions for the lints -themselves, and the latter provides the lint pass definitions (and -implementations), but this is not always true. -The builtin lint registration happens in the [`rustc_lint::register_builtins`] -function. Just like with internal lints, this happens inside of -[`rustc_lint::new_lint_store`]. +These are primarily described in two places, +`rustc_lint_defs::builtin` and `rustc_lint::builtin`. +Often the first provides the definitions for the lints themselves, +and the latter provides the lint pass definitions (and implementations), +but this is not always true. + +The builtin lint registration happens in +the [`rustc_lint::register_builtins`] function. +Just like with internal lints, +this happens inside of [`rustc_lint::new_lint_store`]. #### Plugin lints + This is one of the primary use cases remaining for plugins/drivers. Plugins are given access to the mutable `LintStore` during registration (which happens inside of [`rustc_interface::register_plugins`]) and they can call any @@ -94,6 +110,7 @@ diagnostics and help text; otherwise plugin lints are mostly just as first class as rustc builtin lints. #### Driver lints + These are the lints provided by drivers via the `rustc_interface::Config` [`register_lints`] field, which is a callback. Drivers should, if finding it already set, call the function currently set within the callback they add. The @@ -102,6 +119,7 @@ best way for drivers to get access to this is by overriding the structure. ## Compiler lint passes are combined into one pass + Within the compiler, for performance reasons, we usually do not register dozens of lint passes. Instead, we have a single lint pass of each variety (e.g., `BuiltinCombinedModuleLateLintPass`) which will internally call all of the @@ -121,3 +139,4 @@ approach, it is beneficial to do so for performance reasons. [`declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint.html [`declare_tool_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_tool_lint.html [`register_lints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html#structfield.register_lints +[`&rustc_lint_defs::Lint`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/struct.Lint.html diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index 5c078ffb3..5bb37fbc2 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -32,23 +32,23 @@ Diagnostic messages are defined in Fluent resources. A combined set of Fluent resources for a given locale (e.g. `en-US`) is known as Fluent bundle. ```fluent -typeck-address-of-temporary-taken = cannot take address of a temporary +typeck_address_of_temporary_taken = cannot take address of a temporary ``` -In the above example, `typeck-address-of-temporary-taken` is the identifier for +In the above example, `typeck_address_of_temporary_taken` is the identifier for a Fluent message and corresponds to the diagnostic message in English. Other Fluent resources can be written which would correspond to a message in another language. Each diagnostic therefore has at least one Fluent message. ```fluent -typeck-address-of-temporary-taken = cannot take address of a temporary +typeck_address_of_temporary_taken = cannot take address of a temporary .label = temporary value ``` By convention, diagnostic messages for subdiagnostics are specified as "attributes" on Fluent messages (additional related messages, denoted by the `.` syntax). In the above example, `label` is an attribute of -`typeck-address-of-temporary-taken` which corresponds to the message for the +`typeck_address_of_temporary_taken` which corresponds to the message for the label added to this diagnostic. Diagnostic messages often interpolate additional context into the message shown @@ -56,7 +56,7 @@ to the user, such as the name of a type or of a variable. Additional context to Fluent messages is provided as an "argument" to the diagnostic. ```fluent -typeck-struct-expr-non-exhaustive = +typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression ``` @@ -67,6 +67,13 @@ discussed in detail later). You can consult the [Fluent] documentation for other usage examples of Fluent and its syntax. +### Guideline for message naming +Usually, fluent uses `-` for separating words inside a message name. However, +`_` is accepted by fluent as well. As `_` fits Rust's use cases better, due to +the identifiers on the Rust side using `_` as well, inside rustc, `-` is not +allowed for separating words, and instead `_` is recommended. The only exception +is for leading `-`s, for message names like `-passes_see_issue`. + ### Guidelines for writing translatable messages For a message to be translatable into different languages, all of the information required by any language must be provided to the diagnostic as an @@ -106,10 +113,10 @@ fluent_messages! { For example, given the following Fluent... ```fluent -typeck-field-multiply-specified-in-initializer = +typeck_field_multiply_specified_in_initializer = field `{$ident}` specified more than once .label = used more than once - .label-previous-use = first use of `{$ident}` + .label_previous_use = first use of `{$ident}` ``` ...then the `fluent_messages` macro will generate: @@ -122,11 +129,11 @@ pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[ mod fluent_generated { mod typeck { pub const field_multiply_specified_in_initializer: DiagnosticMessage = - DiagnosticMessage::new("typeck-field-multiply-specified-in-initializer"); + DiagnosticMessage::new("typeck_field_multiply_specified_in_initializer"); pub const label: SubdiagnosticMessage = SubdiagnosticMessage::attr("label"); pub const label_previous_use: SubdiagnosticMessage = - SubdiagnosticMessage::attr("previous-use-label"); + SubdiagnosticMessage::attr("previous_use_label"); } } ``` @@ -217,7 +224,7 @@ returned by `Emitter::fluent_bundle`. This bundle is used preferentially when translating messages, the fallback bundle is only used if the primary bundle is missing a message or not provided. -As of June 2022, there are no locale bundles +As of June 2022, there are no locale bundles distributed with the compiler, but mechanisms are implemented for loading bundles. diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index f16c22d93..5899753ba 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -157,9 +157,12 @@ no changes added to commit (use "git add" and/or "git commit -a") These changes are not changes to files: they are changes to submodules (more on this [later](#git-submodules)). To get rid of those, run `git submodule update` (or run any `x.py` command, which will automatically update the submodules). -Note that there is (as of February 2022) a [bug][#77620] if you use -worktrees, submodules, and `x.py` in a commit hook. If you run into an error -like: +Note that, +as of Aug 2022, +there is a [bug][#77620] if you use worktrees, +submodules, and `x.py` in a commit hook. +If you run into an error like the following, +it's not anything you did wrong: ``` error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Cargo.toml` @@ -167,7 +170,8 @@ error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Car Caused by: No such file or directory (os error 2) ``` -it's not anything you did wrong. There is a workaround in [the issue][#77620-workaround]. + +There is a workaround in [the issue][#77620-workaround]. [#77620]: https://github.com/rust-lang/rust/issues/77620 [#77620-workaround]: https://github.com/rust-lang/rust/issues/77620#issuecomment-705228229 diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index ea4bdfca6..b186f4820 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -222,9 +222,10 @@ properly-configured variables in LLVM IR, according to very specific details of the [_LLVM Coverage Mapping Format_][coverage-mapping-format] (Version 6).[^llvm-and-covmap-versions] -[^llvm-and-covmap-versions]: The Rust compiler (as of -December 2021) supports _LLVM Coverage Mapping Format_ Version 5 or 6. Version 5 -was introduced in _LLVM 12_, which is (as of this writing) the minimum LLVM +[^llvm-and-covmap-versions]: The Rust compiler (as of December 2021) +supports _LLVM Coverage Mapping Format_ Version 5 or 6. Version 5 +was introduced in _LLVM 12_, +which is (as of this writing) the minimum LLVM version supported by the current version of Rust. Version 6 was introduced in _LLVM 13_, which is currently the default LLVM version for Rust. The Rust compiler will automatically use the most up-to-date coverage mapping format diff --git a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md index 2be072dd2..956f56828 100644 --- a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md +++ b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md @@ -14,9 +14,9 @@ This declares an opaque type named `Foo`, of which the only information is that it implements `Bar`. Therefore, any of `Bar`'s interface can be used on a `Foo`, but nothing else (regardless of whether it implements any other traits). -Since there needs to be a concrete background type, you can (as of January 2021) express that type by using the opaque type in a -"defining use site". +Since there needs to be a concrete background type, +you can (as of January 2021) express that type +by using the opaque type in a "defining use site". ```rust,ignore struct Struct; diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index de6c88e7e..c7da92542 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -292,7 +292,7 @@ Moreover, the compiler wasn't originally built to use a query system; the query system has been retrofitted into the compiler, so parts of it are not query-fied yet. Also, LLVM isn't our code, so that isn't querified either. The plan is to eventually query-fy all of the steps listed in the previous section, -but as of November 2021, only the steps between HIR and +but as of November 2021, only the steps between HIR and LLVM IR are query-fied. That is, lexing, parsing, name resolution, and macro expansion are done all at once for the whole program. diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md index 4aa13d781..e93f51dbb 100644 --- a/src/doc/rustc-dev-guide/src/parallel-rustc.md +++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md @@ -1,34 +1,116 @@ # Parallel Compilation -As of May 2022, The only stage of the compiler -that is already parallel is codegen. The nightly compiler implements query evaluation, -but there is still a lot of work to be done. The lack of parallelism at other stages -also represents an opportunity for improving compiler performance. One can try out the current -parallel compiler work by enabling it in the `config.toml`. +As of August 2022, the only stage of the compiler that +is already parallel is codegen. Some parts of the compiler already have +parallel implementations, such as query evaluation, type check and +monomorphization, but the general version of the compiler does not include +these parallelization functions. **To try out the current parallel compiler**, +one can install rustc from source code with `parallel-compiler = true` in +the `config.toml`. + +The lack of parallelism at other stages (for example, macro expansion) also +represents an opportunity for improving compiler performance. These next few sections describe where and how parallelism is currently used, and the current status of making parallel compilation the default in `rustc`. -The underlying thread-safe data-structures used in the parallel compiler -can be found in the `rustc_data_structures::sync` module. Some of these data structures -use the `parking_lot` crate as well. - ## Codegen -There are two underlying thread safe data structures used in code generation: - -- `Lrc` - - Which is an [`Arc`][Arc] if `parallel_compiler` is true, and a [`Rc`][Rc] - if it is not. -- `MetadataRef` -> [`OwningRef, [u8]>`][OwningRef] - - This data structure is specific to `rustc`. - During [monomorphization][monomorphization] the compiler splits up all the code to be generated into smaller chunks called _codegen units_. These are then generated by independent instances of LLVM running in parallel. At the end, the linker is run to combine all the codegen units together into one binary. This process occurs in the `rustc_codegen_ssa::base` module. +## Data Structures + +The underlying thread-safe data-structures used in the parallel compiler +can be found in the `rustc_data_structures::sync` module. These data structures +are implemented diferently depending on whether `parallel-compiler` is true. + +| data structure | parallel | non-parallel | +| -------------------------------- | --------------------------------------------------- | ------------ | +| Lrc | std::sync::Arc | std::rc::Rc | +| Weak | std::sync::Weak | std::rc::Weak | +| Atomic{Bool}/{Usize}/{U32}/{U64} | std::sync::atomic::Atomic{Bool}/{Usize}/{U32}/{U64} | (std::cell::Cell) | +| OnceCell | std::sync::OnceLock | std::cell::OnceCell | +| Lock\ | (parking_lot::Mutex\) | (std::cell::RefCell) | +| RwLock\ | (parking_lot::RwLock\) | (std::cell::RefCell) | +| MTRef<'a, T> | &'a T | &'a mut T | +| MTLock\ | (Lock\) | (T) | +| ReadGuard | parking_lot::RwLockReadGuard | std::cell::Ref | +| MappedReadGuard | parking_lot::MappedRwLockReadGuard | std::cell::Ref | +| WriteGuard | parking_lot::RwLockWriteGuard | std::cell::RefMut | +| MappedWriteGuard | parking_lot::MappedRwLockWriteGuard | std::cell::RefMut | +| LockGuard | parking_lot::MutexGuard | std::cell::RefMut | +| MappedLockGuard | parking_lot::MappedMutexGuard | std::cell::RefMut | +| MetadataRef | [`OwningRef, [u8]>`][OwningRef] | [`OwningRef, [u8]>`][OwningRef] | + +- These thread-safe data structures interspersed during compilation can + cause a lot of lock contention, which actually degrades performance as the + number of threads increases beyond 4. This inspires us to audit the use + of these data structures, leading to either refactoring to reduce use of + shared state, or persistent documentation covering invariants, atomicity, + and lock orderings. + +- On the other hand, we still need to figure out what other invariants + during compilation might not hold in parallel compilation. + +### WorkLocal + +`WorkLocal` is a special data structure implemented for parallel compiler. +It holds worker-locals values for each thread in a thread pool. You can only +access the worker local value through the Deref impl on the thread pool it +was constructed on. It will panic otherwise. + +`WorkLocal` is used to implement the `Arena` allocator in the parallel +environment, which is critical in parallel queries. Its implementation +is located in the `rustc-rayon-core::worker_local` module. However, in the +non-parallel compiler, it is implemented as `(OneThread)`, whose `T` +can be accessed directly through `Deref::deref`. + +## Parallel Iterator + +The parallel iterators provided by the [`rayon`] crate are easy ways +to implement parallelism. In the current implementation of the parallel +compiler we use a custom [fork][rustc-rayon] of [`rayon`] to run tasks in parallel. + +Some iterator functions are implemented to run loops in parallel +when `parallel-compiler` is true. + +| Function(Omit `Send` and `Sync`) | Introduction | Owning Module | +| ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------- | +| **par_iter**(t: T) -> T::Iter | generate a parallel iterator | rustc_data_structure::sync | +| **par_for_each_in**(t: T, for_each: impl Fn(T::Item)) | generate a parallel iterator and run `for_each` on each element | rustc_data_structure::sync | +| **Map::par_body_owners**(self, f: impl Fn(LocalDefId)) | run `f` on all hir owners in the crate | rustc_middle::hir::map | +| **Map::par_for_each_module**(self, f: impl Fn(LocalDefId)) | run `f` on all modules and sub modules in the crate | rustc_middle::hir::map | +| **ModuleItems::par_items**(&self, f: impl Fn(ItemId)) | run `f` on all items in the module | rustc_middle::hir | +| **ModuleItems::par_trait_items**(&self, f: impl Fn(TraitItemId)) | run `f` on all trait items in the module | rustc_middle::hir | +| **ModuleItems::par_impl_items**(&self, f: impl Fn(ImplItemId)) | run `f` on all impl items in the module | rustc_middle::hir | +| **ModuleItems::par_foreign_items**(&self, f: impl Fn(ForeignItemId)) | run `f` on all foreign items in the module | rustc_middle::hir | + +There are a lot of loops in the compiler which can possibly be +parallelized using these functions. As of August +2022, scenarios where the parallel iterator function has been used +are as follows: + +| caller | scenario | callee | +| ------------------------------------------------------- | ------------------------------------------------------------ | ------------------------ | +| rustc_metadata::rmeta::encoder::prefetch_mir | Prefetch queries which will be needed later by metadata encoding | par_iter | +| rustc_monomorphize::collector::collect_crate_mono_items | Collect monomorphized items reachable from non-generic items | par_for_each_in | +| rustc_interface::passes::analysis | Check the validity of the match statements | Map::par_body_owners | +| rustc_interface::passes::analysis | MIR borrow check | Map::par_body_owners | +| rustc_typeck::check::typeck_item_bodies | Type check | Map::par_body_owners | +| rustc_interface::passes::hir_id_validator::check_crate | Check the validity of hir | Map::par_for_each_module | +| rustc_interface::passes::analysis | Check the validity of loops body, attributes, naked functions, unstable abi, const bodys | Map::par_for_each_module | +| rustc_interface::passes::analysis | Liveness and intrinsic checking of MIR | Map::par_for_each_module | +| rustc_interface::passes::analysis | Deathness checking | Map::par_for_each_module | +| rustc_interface::passes::analysis | Privacy checking | Map::par_for_each_module | +| rustc_lint::late::check_crate | Run per-module lints | Map::par_for_each_module | +| rustc_typeck::check_crate | Well-formedness checking | Map::par_for_each_module | + +There are still many loops that have the potential to use parallel iterators. + ## Query System The query model has some properties that make it actually feasible to evaluate @@ -48,44 +130,22 @@ When a query `foo` is evaluated, the cache table for `foo` is locked. start evaluating. - If there *is* another query invocation for the same key in progress, we release the lock, and just block the thread until the other invocation has - computed the result we are waiting for. This cannot deadlock because, as - mentioned before, query invocations form a DAG. Some threads will always make - progress. + computed the result we are waiting for. **Cycle error detection** in the parallel + compiler requires more complex logic than in single-threaded mode. When + worker threads in parallel queries stop making progress due to interdependence, + the compiler uses an extra thread *(named deadlock handler)* to detect, remove and + report the cycle error. + +Parallel query still has a lot of work to do, most of which is related to +the previous `Data Structures` and `Parallel Iterators`. See [this tracking issue][tracking]. ## Rustdoc -As of May 2022, there are still a number of steps +As of May 2022, there are still a number of steps to complete before rustdoc rendering can be made parallel. More details on this issue can be found [here][parallel-rustdoc]. -## Current Status - -As of May 2022, work on explicitly parallelizing the -compiler has stalled. There is a lot of design and correctness work that needs -to be done. - -These are the basic ideas in the effort to make `rustc` parallel: - -- There are a lot of loops in the compiler that just iterate over all items in - a crate. These can possibly be parallelized. -- We can use (a custom fork of) [`rayon`] to run tasks in parallel. The custom - fork allows the execution of DAGs of tasks, not just trees. -- There are currently a lot of global data structures that need to be made - thread-safe. A key strategy here has been converting interior-mutable - data-structures (e.g. `Cell`) into their thread-safe siblings (e.g. `Mutex`). - -[`rayon`]: https://crates.io/crates/rayon - -As of May 2022, much of this effort is on hold due -to lack of manpower. We have a working prototype with promising performance -gains in many cases. However, there are two blockers: - -- It's not clear what invariants need to be upheld that might not hold in the - face of concurrency. An auditing effort was underway, but seems to have - stalled at some point. - -- There is a lot of lock contention, which actually degrades performance as the - number of threads increases beyond 4. +## Resources Here are some resources that can be used to learn more (note that some of them are a bit out of date): @@ -93,8 +153,9 @@ are a bit out of date): - [This IRLO thread by Zoxc, one of the pioneers of the effort][irlo0] - [This list of interior mutability in the compiler by nikomatsakis][imlist] - [This IRLO thread by alexchricton about performance][irlo1] -- [This tracking issue][tracking] +[`rayon`]: https://crates.io/crates/rayon +[rustc-rayon]: https://github.com/rust-lang/rustc-rayon [irlo0]: https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606 [imlist]: https://github.com/nikomatsakis/rustc-parallelization/blob/master/interior-mutability-list.md [irlo1]: https://internals.rust-lang.org/t/help-test-parallel-rustc/11503 diff --git a/src/doc/rustc-dev-guide/src/part-5-intro.md b/src/doc/rustc-dev-guide/src/part-5-intro.md index 4b7c25797..faa12f484 100644 --- a/src/doc/rustc-dev-guide/src/part-5-intro.md +++ b/src/doc/rustc-dev-guide/src/part-5-intro.md @@ -1,54 +1,57 @@ # From MIR to Binaries -All of the preceding chapters of this guide have one thing in common: we never -generated any executable machine code at all! With this chapter, all of that -changes. +All of the preceding chapters of this guide have one thing in common: +we never generated any executable machine code at all! +With this chapter, all of that changes. -So far, we've shown how the compiler can take raw source code in text format -and transform it into [MIR]. We have also shown how the compiler does various -analyses on the code to detect things like type or lifetime errors. Now, we -will finally take the MIR and produce some executable machine code. +So far, +we've shown how the compiler can take raw source code in text format +and transform it into [MIR]. +We have also shown how the compiler does various +analyses on the code to detect things like type or lifetime errors. +Now, we will finally take the MIR and produce some executable machine code. [MIR]: ./mir/index.md -> NOTE: This part of a compiler is often called the _backend_. The term is a bit -> overloaded because in the compiler source, it usually refers to the "codegen -> backend" (i.e. LLVM or Cranelift). Usually, when you see the word "backend" -> in this part, we are referring to the "codegen backend". +> NOTE: This part of a compiler is often called the _backend_. +> The term is a bit overloaded because in the compiler source, +> it usually refers to the "codegen backend" (i.e. LLVM, Cranelift, or GCC). +> Usually, when you see the word "backend" in this part, +> we are referring to the "codegen backend". So what do we need to do? -0. First, we need to collect the set of things to generate code for. In - particular, we need to find out which concrete types to substitute for - generic ones, since we need to generate code for the concrete types. - Generating code for the concrete types (i.e. emitting a copy of the code for - each concrete type) is called _monomorphization_, so the process of - collecting all the concrete types is called _monomorphization collection_. +0. First, we need to collect the set of things to generate code for. + In particular, + we need to find out which concrete types to substitute for generic ones, + since we need to generate code for the concrete types. + Generating code for the concrete types + (i.e. emitting a copy of the code for each concrete type) is called _monomorphization_, + so the process of collecting all the concrete types is called _monomorphization collection_. 1. Next, we need to actually lower the MIR to a codegen IR (usually LLVM IR) for each concrete type we collected. -2. Finally, we need to invoke LLVM or Cranelift, which runs a bunch of - optimization passes, generates executable code, and links together an - executable binary. +2. Finally, we need to invoke the codegen backend, + which runs a bunch of optimization passes, + generates executable code, + and links together an executable binary. [codegen1]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/fn.codegen_crate.html The code for codegen is actually a bit complex due to a few factors: -- Support for multiple codegen backends (LLVM and Cranelift). We try to share as much - backend code between them as possible, so a lot of it is generic over the - codegen implementation. This means that there are often a lot of layers of - abstraction. +- Support for multiple codegen backends (LLVM, Cranelift, and GCC). + We try to share as much backend code between them as possible, + so a lot of it is generic over the codegen implementation. + This means that there are often a lot of layers of abstraction. - Codegen happens asynchronously in another thread for performance. -- The actual codegen is done by a third-party library (either LLVM or Cranelift). +- The actual codegen is done by a third-party library (either of the 3 backends). -Generally, the [`rustc_codegen_ssa`][ssa] crate contains backend-agnostic code -(i.e. independent of LLVM or Cranelift), while the [`rustc_codegen_llvm`][llvm] -crate contains code specific to LLVM codegen. +Generally, the [`rustc_codegen_ssa`][ssa] crate contains backend-agnostic code, +while the [`rustc_codegen_llvm`][llvm] crate contains code specific to LLVM codegen. [ssa]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html [llvm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/index.html At a very high level, the entry point is -[`rustc_codegen_ssa::base::codegen_crate`][codegen1]. This function starts the -process discussed in the rest of this chapter. - +[`rustc_codegen_ssa::base::codegen_crate`][codegen1]. +This function starts the process discussed in the rest of this chapter. diff --git a/src/doc/rustc-dev-guide/src/profiling.md b/src/doc/rustc-dev-guide/src/profiling.md index ada497d88..e1666e237 100644 --- a/src/doc/rustc-dev-guide/src/profiling.md +++ b/src/doc/rustc-dev-guide/src/profiling.md @@ -108,6 +108,6 @@ The llvm-lines output is affected by several options. MIR optimizations have little impact. Compared to the default `RUSTFLAGS="-Z mir-opt-level=1"`, level 0 adds 0.3GB and level 2 removes 0.2GB. -As of July 2022, +As of July 2022, inlining happens in LLVM and GCC codegen backends, missing only in the Cranelift one. diff --git a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md index b84a5dac4..8a08f1e04 100644 --- a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md @@ -76,7 +76,7 @@ executed, no results are cached. But the context already provides access to "input" data, i.e. pieces of immutable data that were computed before the context was created and that queries can access to do their computations. -As of January 2021, this input data consists mainly of +As of January 2021, this input data consists mainly of the HIR map, upstream crate metadata, and the command-line options the compiler was invoked with; but in the future inputs will just consist of command-line options and a list of source files -- the HIR map will itself be provided by a diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 95e570dfc..3d60059bd 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -3,7 +3,7 @@ As described in [the high-level overview of the compiler][hl], the Rust compiler -is still (as of July 2021) transitioning from a +is still (as of July 2021) transitioning from a traditional "pass-based" setup to a "demand-driven" system. The compiler query system is the key to rustc's demand-driven organization. The idea is pretty simple. Instead of entirely independent passes diff --git a/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md b/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md index 327415e5a..5ce93c3df 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md @@ -7,7 +7,7 @@ To get diagnostics from the compiler, configure `rustc_interface::Config` to output diagnostic to a buffer, and run `TyCtxt.analysis`. The following was tested -with `nightly-2022-06-05` (See [here][example] +with `nightly-2022-06-05` (See [here][example] for the complete example): [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-getting-diagnostics.rs diff --git a/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md b/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md index d70264fe4..ce53f3861 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md @@ -5,7 +5,7 @@ ## Getting the type of an expression To get the type of an expression, use the `global_ctxt` to get a `TyCtxt`. -The following was tested with `nightly-2022-06-05` +The following was tested with `nightly-2022-06-05` (see [here][example] for the complete example): [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-interacting-with-the-ast.rs diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md index 91bb0c358..f21c8725c 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md @@ -66,7 +66,7 @@ these passes, please let us know!) [44136]: https://github.com/rust-lang/rust/issues/44136 -Here is the list of passes as of May 2022: +Here is the list of passes as of May 2022: - `calculate-doc-coverage` calculates information used for the `--show-coverage` flag. diff --git a/src/doc/rustc-dev-guide/src/salsa.md b/src/doc/rustc-dev-guide/src/salsa.md index afa01eda2..872308e78 100644 --- a/src/doc/rustc-dev-guide/src/salsa.md +++ b/src/doc/rustc-dev-guide/src/salsa.md @@ -9,7 +9,7 @@ want to watch [Salsa In More Depth](https://www.youtube.com/watch?v=i_IhACacPRY), also by Niko Matsakis. -> As of April 2022, although Salsa is inspired by +> As of April 2022, although Salsa is inspired by > (among other things) rustc's query system, it is not used directly in rustc. > It _is_ used in chalk and extensively in `rust-analyzer`, but there are no > medium or long-term concrete plans to integrate it into the compiler. diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md index 454cd0f27..0ac19293b 100644 --- a/src/doc/rustc-dev-guide/src/stabilization_guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md @@ -99,24 +99,6 @@ require steps beyond what this guide talks about. Note: Before we stabilize any feature, it's the rule that it should appear in the documentation. -### Determining the stabilization version - -The version in which the feature will be stabilized *must* match -the value of [the `src/version` file in `master`][src-version] when the PR is merged. - -It's worth checking [the version schedule on the Forge][forge-versions] to see whether -changes are coming soon. You'll usually use the version labelled "Nightly". -"Nightly" is two versions higher than the current stable release, -since what's currently in beta will be the next stable release, -and any changes you're making now will be in the one after that. - -No PR is merged instantly, so you'll want to be careful around release time. -The version bump happens [the Friday before][forge-release-process] the stable release, -not the same time as the release. So if you're opening a PR shortly before then, -be prepared to update the version, or consider just opening it for one version -higher than the current nightly, with a note saying not to merge until -after the upcoming version bump. - ### Updating the feature-gate listing There is a central listing of feature-gates in @@ -127,7 +109,7 @@ to stabilize, something like (this example is taken from ```rust,ignore // pub(restricted) visibilities (RFC 1422) -(active, pub_restricted, "1.9.0", Some(32409)), +(active, pub_restricted, "CURRENT_RUSTC_VERSION", Some(32409)), ``` The above line should be moved down to the area for "accepted" @@ -136,11 +118,13 @@ When it is done, it should look like: ```rust,ignore // pub(restricted) visibilities (RFC 1422) -(accepted, pub_restricted, "1.31.0", Some(32409)), +(accepted, pub_restricted, "CURRENT_RUSTC_VERSION", Some(32409)), // note that we changed this ``` -(The version here is the one discussed in the previous section.) +(Even though you will encounter version numbers in the file of past changes, +you should not put the rustc version you expect your stabilization to happen in, +but instead `CURRENT_RUSTC_VERSION`) ### Removing existing uses of the feature-gate diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md index 09a66cdc9..1b8247005 100644 --- a/src/doc/rustc-dev-guide/src/test-implementation.md +++ b/src/doc/rustc-dev-guide/src/test-implementation.md @@ -155,5 +155,4 @@ $ rustc my_mod.rs -Z unpretty=hir [TestDesc]: https://doc.rust-lang.org/test/struct.TestDesc.html [Symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html [Ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html -[eRFC]: https://github.com/rust-lang/rfcs/blob/master/text/2318-custom-test-frameworks.md [rustc_ast]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_ast diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 5c3dcf54b..70cef2ad3 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -452,7 +452,7 @@ fn main() { ## Revisions -Certain classes of tests support "revisions" (as of July 2022, +Certain classes of tests support "revisions" (as of July 2022, this includes UI, assembly, codegen, debuginfo, incremental, and rustdoc UI tests, though incremental tests are somewhat different). Revisions allow a single test file to be used for multiple tests. diff --git a/src/doc/rustc-dev-guide/src/the-parser.md b/src/doc/rustc-dev-guide/src/the-parser.md index ff43220c1..0d37704e8 100644 --- a/src/doc/rustc-dev-guide/src/the-parser.md +++ b/src/doc/rustc-dev-guide/src/the-parser.md @@ -1,6 +1,6 @@ # Lexing and Parsing -As of January 2021, the lexer and parser are undergoing +As of January 2021, the lexer and parser are undergoing refactoring to allow extracting them into libraries. The very first thing the compiler does is take the program (in Unicode @@ -35,9 +35,10 @@ The main entrypoint to the parser is via the various `parse_*` functions and oth the token stream, and then execute the parser to get a `Crate` (the root AST node). -To minimise the amount of copying that is done, both the `StringReader` and -`Parser` have lifetimes which bind them to the parent `ParseSess`. This contains -all the information needed while parsing, as well as the `SourceMap` itself. +To minimize the amount of copying that is done, +both [`StringReader`] and [`Parser`] have lifetimes which bind them to the parent `ParseSess`. +This contains all the information needed while parsing, +as well as the [`SourceMap`] itself. Note that while parsing, we may encounter macro definitions or invocations. We set these aside to be expanded (see [this chapter](./macro-expansion.md)). @@ -52,9 +53,9 @@ Code for lexical analysis is split between two crates: constituting tokens. Although it is popular to implement lexers as generated finite state machines, the lexer in `rustc_lexer` is hand-written. -- [`StringReader`] from [`rustc_ast`][rustc_ast] integrates `rustc_lexer` with `rustc` - specific data structures. Specifically, it adds `Span` information to tokens - returned by `rustc_lexer` and interns identifiers. +- [`StringReader`] integrates `rustc_lexer` with data structures specific to `rustc`. + Specifically, + it adds `Span` information to tokens returned by `rustc_lexer` and interns identifiers. [rustc_ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/index.html [rustc_errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html @@ -64,7 +65,7 @@ Code for lexical analysis is split between two crates: [rustc_parse]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [parser_lib]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [parser]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html -[`Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/parse/parser/struct.Parser.html +[`Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html [`StringReader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html [visit module]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/index.html [sourcefile]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.SourceFile.html diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 4f8e6512c..2a811be3d 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -4,7 +4,7 @@ The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for "High-Level Abstract IR", is another IR used by rustc that is generated after -[type checking]. It is (as of April 2022) only used for +[type checking]. It is (as of April 2022) only used for [MIR construction] and [exhaustiveness checking]. There is also [an experimental unsafety checker][thir-unsafeck] that operates on the THIR as a replacement for the current MIR unsafety checker, and can be used instead of the MIR unsafety checker by passing @@ -47,9 +47,19 @@ which is useful to keep peak memory in check. Having a THIR representation of all bodies of a crate in memory at the same time would be very heavy. You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag -to `rustc`. Here is how a function with just the statement `let x = 1 + 2;` gets represented in -THIR: +to `rustc`. + +To demonstrate, let's use the following example: + ```rust +fn main() { + let x = 1 + 2; +} +``` + +Here is how that gets represented in THIR (as of Aug 2022): + +```rust,no_run Thir { // no match arms arms: [], @@ -57,57 +67,73 @@ Thir { // expression 0, a literal with a value of 1 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:14 (#0), kind: Literal { - literal: Const { - ty: i32, - val: Value(Scalar(0x00000001)), + lit: Spanned { + node: Int( + 1, + Unsuffixed, + ), + span: oneplustwo.rs:2:13: 2:14 (#0), }, - user_ty: None, - const_id: None, + neg: false, }, }, // expression 1, scope surronding literal 1 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:14 (#0), kind: Scope { - region_scope: Node(1), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 1, - }), // reference to expression 0 above + region_scope: Node(3), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 3, + }, + ), value: e0, }, }, // expression 2, literal 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:17: 2:18 (#0), kind: Literal { - literal: Const { - ty: i32, - val: Value(Scalar(0x00000002)), + lit: Spanned { + node: Int( + 2, + Unsuffixed, + ), + span: oneplustwo.rs:2:17: 2:18 (#0), }, - user_ty: None, - const_id: None, + neg: false, }, }, // expression 3, scope surrounding literal 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:17: 2:18 (#0), kind: Scope { - region_scope: Node(2), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 2, - }), + region_scope: Node(4), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 4, + }, + ), // reference to expression 2 above value: e2, }, @@ -115,7 +141,9 @@ Thir { // expression 4, represents 1 + 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:18 (#0), kind: Binary { op: Add, @@ -127,30 +155,38 @@ Thir { // expression 5, scope surronding expression 4 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:18 (#0), kind: Scope { - region_scope: Node(3), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 3, - }), + region_scope: Node(5), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 5, + }, + ), value: e4, }, }, // expression 6, block around statement Expr { ty: (), - temp_lifetime: Some(Node(8)), + temp_lifetime: Some( + Node(9), + ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Block { body: Block { targeted_by_break: false, - region_scope: Node(7), + region_scope: Node(8), opt_destruction_scope: None, span: oneplustwo.rs:1:11: 3:2 (#0), // reference to statement 0 below - stmts: [ s0 ], + stmts: [ + s0, + ], expr: None, safety_mode: Safe, }, @@ -160,25 +196,29 @@ Thir { Expr { ty: (), temp_lifetime: Some( - Node(8), + Node(9), ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Node(8), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 8, - }), + region_scope: Node(9), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 9, + }, + ), value: e6, }, }, // destruction scope around expression 7 Expr { ty: (), - temp_lifetime: Some(Node(8)), + temp_lifetime: Some( + Node(9), + ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Destruction(8), + region_scope: Destruction(9), lint_level: Inherited, value: e7, }, @@ -188,8 +228,8 @@ Thir { // let statement Stmt { kind: Let { - remainder_scope: Remainder { block: 7, first_statement_index: 0}, - init_scope: Node(6), + remainder_scope: Remainder { block: 8, first_statement_index: 0}, + init_scope: Node(1), pattern: Pat { ty: i32, span: oneplustwo.rs:2:9: 2:10 (#0), @@ -197,22 +237,31 @@ Thir { mutability: Not, name: "x", mode: ByValue, - var: HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 5, - }, + var: LocalVarId( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 7, + }, + ), ty: i32, subpattern: None, is_primary: true, }, }, - initializer: Some(e5), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 4, - }), + initializer: Some( + e5, + ), + else_block: None, + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 6, + }, + ), }, - opt_destruction_scope: Some(Destruction(6)), + opt_destruction_scope: Some( + Destruction(1), + ), }, ], } diff --git a/src/doc/rustc-dev-guide/src/traits/chalk.md b/src/doc/rustc-dev-guide/src/traits/chalk.md index d4045c460..78deb3675 100644 --- a/src/doc/rustc-dev-guide/src/traits/chalk.md +++ b/src/doc/rustc-dev-guide/src/traits/chalk.md @@ -1,7 +1,7 @@ # Chalk-based trait solving -[Chalk][chalk] is an experimental trait solver for Rust that is (as of May 2022) under development by the [Types team]. +[Chalk][chalk] is an experimental trait solver for Rust that is +(as of May 2022) under development by the [Types team]. Its goal is to enable a lot of trait system features and bug fixes that are hard to implement (e.g. GATs or specialization). If you would like to help in hacking on the new solver, drop by on the rust-lang Zulip in the [`#t-types`] diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md index c22ee6de6..195fe6050 100644 --- a/src/doc/rustc-dev-guide/src/traits/resolution.md +++ b/src/doc/rustc-dev-guide/src/traits/resolution.md @@ -120,7 +120,7 @@ the obligation contains unbound inference variables. The subroutines that decide whether a particular impl/where-clause/etc applies to a particular obligation are collectively referred to as the process of -_matching_. As of May 2022, this amounts to unifying +_matching_. As of May 2022, this amounts to unifying the `Self` types, but in the future we may also recursively consider some of the nested obligations, in the case of an impl. diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index 4be9211ee..10f1dd5ef 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -45,11 +45,9 @@ tcx.infer_ctxt().enter(|infcx| { }) ``` -Within the closure, `infcx` has the type `InferCtxt<'cx, 'tcx>` for some -fresh `'cx`, while `'tcx` is the same as outside the inference context. -(Again, see the [`ty` chapter][ty-ch] for more details on this setup.) - -[ty-ch]: ty.html +Within the closure, +`infcx` has the type `InferCtxt<'a, 'tcx>` for some fresh `'a`, +while `'tcx` is the same as outside the inference context. The `tcx.infer_ctxt` method actually returns a builder, which means there are some kinds of configuration you can do before the `infcx` is @@ -72,7 +70,7 @@ inference works, or perhaps this blog post on [Unification in the Chalk project]: http://smallcultfollowing.com/babysteps/blog/2017/03/25/unification-in-chalk-part-1/ All told, the inference context stores five kinds of inference variables -(as of June 2021): +(as of June 2021): - Type variables, which come in three varieties: - General type variables (the most common). These can be unified with any diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index d168af60c..d9d430c20 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -18,6 +18,8 @@ - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) + - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) + - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 0ae9e53af..38fd5c969 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -97,7 +97,17 @@ $ echo "{some: 'thing'}" | target/debug/examples/formatjson5 - } ``` -After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`: +After running this program, a new file named like `default_11699812450447639123_0_20944` should be in the current working directory. +A new, unique file name will be generated each time the program is run to avoid overwriting previous data. + +```shell +$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 - +... +$ ls default_*.profraw +default_11699812450447639123_0_20944.profraw +``` + +You can also set a specific file name or path for the generated `.profraw` files by using the environment variable `LLVM_PROFILE_FILE`: ```shell $ echo "{some: 'thing'}" \ @@ -115,6 +125,9 @@ If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing - `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`). - `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered. +In the first example above, the value `11699812450447639123_0` in the generated filename is the instrumented binary's signature, +which replaced the `%m` pattern and the value `20944` is the process ID of the binary being executed. + ## Installing LLVM coverage tools LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher, and processing the *raw* data may require exactly the LLVM version used by the compiler. (`llvm-cov --version` typically shows the tool's LLVM version number, and `rustc --verbose --version` shows the version of LLVM used by the Rust compiler.) @@ -181,11 +194,10 @@ A typical use case for coverage analysis is test coverage. Rust's source-based c The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate. -Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-C instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.) +Since `cargo test` both builds and runs the tests, we set the additional `RUSTFLAGS`, to add the `-C instrument-coverage` flag. ```shell $ RUSTFLAGS="-C instrument-coverage" \ - LLVM_PROFILE_FILE="json5format-%m.profraw" \ cargo test --tests ``` @@ -210,7 +222,7 @@ test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them: ```shell -$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata +$ llvm-profdata merge -sparse default_*.profraw -o json5format.profdata ``` Then run the `cov` tool, with the `profdata` file and all test binaries: @@ -230,6 +242,8 @@ $ llvm-cov show \ --Xdemangler=rustfilt | less -R ``` +> **Note**: If overriding the default `profraw` file name via the `LLVM_PROFILE_FILE` environment variable, it's highly recommended to use the `%m` and `%p` special pattern strings to generate unique file names in the case of more than a single test binary being executed. + > **Note**: The command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results.\_ ### Tips for listing the binaries automatically @@ -271,9 +285,8 @@ To include doc tests in the coverage results, drop the `--tests` flag, and apply ```bash $ RUSTFLAGS="-C instrument-coverage" \ RUSTDOCFLAGS="-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \ - LLVM_PROFILE_FILE="json5format-%m.profraw" \ cargo test -$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata +$ llvm-profdata merge -sparse default_*.profraw -o json5format.profdata ``` The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries @@ -302,8 +315,7 @@ $ llvm-cov report \ > version without doc tests, include: - The `cargo test ... --no-run` command is updated with the same environment variables - and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE` - is only used when _running_ the tests.) + and flags used to _build_ the tests, _including_ the doc tests. - The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out` binaries generated for doc tests (note, however, that some `rust_out` files may not be executable binaries). diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 9c644dd40..b1854b22a 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -30,7 +30,7 @@ Using `rustc` directly: # Compile the Rust staticlib rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs # Compile the C code with `-flto=thin` -clang -c -O2 -flto=thin -o main.o ./main.c +clang -c -O2 -flto=thin -o cmain.o ./cmain.c # Link everything, making sure that we use an appropriate linker clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o ``` @@ -41,7 +41,7 @@ Using `cargo`: # Compile the Rust staticlib RUSTFLAGS="-Clinker-plugin-lto" cargo build --release # Compile the C code with `-flto=thin` -clang -c -O2 -flto=thin -o main.o ./main.c +clang -c -O2 -flto=thin -o cmain.o ./cmain.c # Link everything, making sure that we use an appropriate linker clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o ``` diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 01489e9aa..3a6963ebc 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -213,7 +213,7 @@ target | std | host | notes [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore -`aarch64-unknown-uefi` | * | | ARM64 UEFI +[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | ARM64 UEFI `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) `aarch64-unknown-netbsd` | ✓ | ✓ | [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD @@ -223,6 +223,8 @@ target | std | host | notes `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers +[`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). +`armv4t-none-eabi` | * | | ARMv4T A32 `armv4t-unknown-linux-gnueabi` | ? | | `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD @@ -249,7 +251,7 @@ target | std | host | notes `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD -`i686-unknown-uefi` | * | | 32-bit UEFI +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 32-bit UEFI `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | @@ -276,6 +278,7 @@ target | std | host | notes `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | +[`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) `riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA) @@ -283,6 +286,7 @@ target | std | host | notes `riscv32imc-esp-espidf` | ✓ | | RISC-V ESP-IDF `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) +[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 @@ -304,7 +308,7 @@ target | std | host | notes `x86_64-unknown-l4re-uclibc` | ? | | `x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD -`x86_64-unknown-uefi` | * | | 64-bit UEFI +[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 64-bit UEFI `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | `x86_64-wrs-vxworks` | ? | | diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md new file mode 100644 index 000000000..507631cdc --- /dev/null +++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md @@ -0,0 +1,74 @@ +# armeb-unknown-linux-gnueabi +**Tier: 3** + +Target for cross-compiling Linux user-mode applications targetting the ARM BE8 architecture. + +## Overview +BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian ARM systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). + +## History +BE8 architecture is the default big-endian architecture for ARM since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). It's predecessor, used for ARMv4 and ARMv5 devices was [BE32](https://developer.arm.com/documentation/dui0474/j/linker-command-line-options/--be32). On ARMv6 architecture, endianness can be configured via [system registers](https://developer.arm.com/documentation/ddi0290/g/unaligned-and-mixed-endian-data-access-support/mixed-endian-access-support/interaction-between-the-bus-protocol-and-the-core-endianness). However, BE32 was withdrawn for [ARMv7](https://developer.arm.com/documentation/ddi0406/cb/Appendixes/Deprecated-and-Obsolete-Features/Obsolete-features/Support-for-BE-32-endianness-model) onwards. + +## Target Maintainers +* [@WorksButNotTested](https://github.com/WorksButNotTested) + +## Requirements +The target is cross-compiled. This target supports `std` in the normal way (indeed only nominal changes are required from the standard ARM configuration). + +## Target definition +The target definition can be seen [here](https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs). In particular, it should be noted that the `features` specify that this target is built for the ARMv8 core. Though this can likely be modified as required. + +## Building the target +Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. + +Therefore, you can build Rust with support for the target by adding it to the target list in config.toml, a sample configuration is shown below. It is expected that the user already have a working GNU compiler toolchain and update the paths accordingly. + +```toml +[llvm] +download-ci-llvm = false +skip-rebuild = true +optimize = true +ninja = true +targets = "ARM;X86" +clang = false + +[build] +target = ["x86_64-unknown-linux-gnu", "armeb-unknown-linux-gnueabi"] +docs = false +docs-minification = false +compiler-docs = false +[install] +prefix = "/home/user/x-tools/rust/" + +[rust] +debug-logging=true +backtrace = true +incremental = true + +[target.x86_64-unknown-linux-gnu] + +[dist] + +[target.armeb-unknown-linux-gnueabi] +cc = "/home/user/x-tools/armeb-unknown-linux-gnueabi/bin/armeb-unknown-linux-gnueabi-gcc" +cxx = "/home/user/x-tools/armeb-unknown-linux-gnueabi/bin/armeb-unknown-linux-gnueabi-g++" +ar = "/home/user/x-tools/armeb-unknown-linux-gnueabi/bin/armeb-unknown-linux-gnueabi-ar" +ranlib = "/home/user/x-tools/armeb-unknown-linux-gnueabi/bin/armeb-unknown-linux-gnueabi-ranlib" +linker = "/home/user/x-tools/armeb-unknown-linux-gnueabi/bin/armeb-unknown-linux-gnueabi-gcc" +llvm-config = "/home/user/x-tools/clang/bin/llvm-config" +llvm-filecheck = "/home/user/x-tools/clang/bin/FileCheck" +``` + +## Building Rust programs + +The following `.cargo/config` is needed inside any project directory to build for the BE8 target: + +```toml +[build] +target = "armeb-unknown-linux-gnueabi" + +[target.armeb-unknown-linux-gnueabi] +linker = "armeb-unknown-linux-gnueabi-gcc" +``` + +Note that it is expected that the user has a suitable linker from the GNU toolchain. diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md new file mode 100644 index 000000000..cf831e159 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -0,0 +1,70 @@ +# armv4t-none-eabi + +Tier 3 + +Bare-metal target for any cpu in the ARMv4T architecture family, supporting +ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code +generation. + +In particular this supports the Gameboy Advance (GBA), but there's nothing GBA +specific with this target, so any ARMv4T device should work fine. + +## Target Maintainers + +* [@Lokathor](https://github.com/lokathor) + +## Requirements + +The target is cross-compiled, and uses static linking. + +The linker that comes with rustc cannot link for this platform (the platform is +too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils +targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM +Developer Website][arm-dev], or possibly from your OS's package manager. + +[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain + +This target doesn't provide a linker script, you'll need to bring your own +according to the specific device you want to target. Pass +`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use +`your_script.ld` during linking. + +## Building Rust Programs + +Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. + +Just use the `build-std` nightly cargo feature to build the `core` library. You +can pass this as a command line argument to cargo, or your `.cargo/config.toml` +file might include the following lines: + +```toml +[unstable] +build-std = ["core"] +``` + +Most of `core` should work as expected, with the following notes: +* the target is "soft float", so `f32` and `f64` operations are emulated in + software. +* integer division is also emulated in software. +* the target is old enough that it doesn't have atomic instructions. + +Rust programs are output as ELF files. + +For running on hardware, you'll generally need to extract the "raw" program code +out of the ELF and into a file of its own. The `objcopy` program provided as +part of the GNU Binutils can do this: + +```shell +arm-none-eabi-objcopy --output-target binary [in_file] [out_file] +``` + +## Testing + +This is a cross-compiled target that you will need to emulate during testing. + +Because this is a device-agnostic target, and the exact emulator that you'll +need depends on the specific device you want to run your code on. + +For example, when programming for the Gameboy Advance, the +[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a +normal set of rust tests be run within the `mgba` emulator. diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 61bd1b425..1ff6003c1 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -5,14 +5,10 @@ [Fuchsia] is a modern open source operating system that's simple, secure, updatable, and performant. -[Fuchsia]: https://fuchsia.dev/ - ## Target maintainers The [Fuchsia team]: -[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json - - Tyler Mandry ([@tmandry](https://github.com/tmandry)) - Dan Johnson ([@computerdruid](https://github.com/computerdruid)) - David Koloski ([@djkoloski](https://github.com/djkoloski)) @@ -24,27 +20,174 @@ the members reported by the API. The API should be considered to be authoritative if this occurs. Instead of pinging individual members, use `@rustbot ping fuchsia` to contact the team on GitHub. +## Table of contents + +1. [Requirements](#requirements) +1. [Walkthrough structure](#walkthrough-structure) +1. [Compiling a Rust binary targeting Fuchsia](#compiling-a-rust-binary-targeting-fuchsia) + 1. [Targeting Fuchsia with rustup and cargo](#targeting-fuchsia-with-rustup-and-cargo) + 1. [Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source) +1. [Creating a Fuchsia package](#creating-a-fuchsia-package) + 1. [Creating a Fuchsia component](#creating-a-fuchsia-component) + 1. [Building a Fuchsia package](#building-a-fuchsia-package) +1. [Publishing a Fuchsia package](#publishing-a-fuchsia-package) + 1. [Creating a Fuchsia package repository](#creating-a-fuchsia-package-repository) + 1. [Publishing Fuchsia package to repository](#publishing-fuchsia-package-to-repository) +1. [Running a Fuchsia component on an emulator](#running-a-fuchsia-component-on-an-emulator) + 1. [Starting the Fuchsia emulator](#starting-the-fuchsia-emulator) + 1. [Watching emulator logs](#watching-emulator-logs) + 1. [Serving a Fuchsia package](#serving-a-fuchsia-package) + 1. [Running a Fuchsia component](#running-a-fuchsia-component) +1. [`.gitignore` extensions](#gitignore-extensions) +1. [Testing](#testing) + 1. [Running unit tests](#running-unit-tests) + 1. [Running the compiler test suite](#running-the-compiler-test-suite) +1. [Debugging](#debugging) + 1. [`zxdb`](#zxdb) + 1. [Attaching `zxdb`](#attaching-zxdb) + 1. [Using `zxdb`](#using-zxdb) + 1. [Displaying source code in `zxdb`](#displaying-source-code-in-zxdb) + ## Requirements -This target is cross-compiled from a host environment. Development may be done -from the [source tree] or using the Fuchsia SDK. +This target is cross-compiled from a host environment. You will need a recent +copy of the [Fuchsia SDK], which provides the tools, libraries, and binaries +required to build and link programs for Fuchsia. -[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build +Development may also be done from the [source tree]. -Fuchsia targets support std and follow the `sysv64` calling convention on +Fuchsia targets support `std` and follow the `sysv64` calling convention on x86_64. Fuchsia binaries use the ELF file format. -## Building the target +## Walkthrough structure + +This walkthrough will cover: + +1. Compiling a Rust binary targeting Fuchsia. +1. Building a Fuchsia package. +1. Publishing and running a Fuchsia package to a Fuchsia emulator. + +For the purposes of this walkthrough, we will only target `x86_64-fuchsia`. + +## Compiling a Rust binary targeting Fuchsia + +Today, there are two main ways to build a Rust binary targeting Fuchsia +using the Fuchsia SDK: +1. Allow [rustup] to handle the installation of Fuchsia targets for you. +1. Build a toolchain locally that can target Fuchsia. + +### Targeting Fuchsia with rustup and cargo + +The easiest way to build a Rust binary targeting Fuchsia is by allowing [rustup] +to handle the installation of Fuchsia targets for you. This can be done by issuing +the following commands: + +```sh +rustup target add x86_64-fuchsia +rustup target add aarch64-fuchsia +``` + +After installing our Fuchsia targets, we can now compile a Rust binary that targets +Fuchsia. + +To create our Rust project, we can issue a standard `cargo` command as follows: + +**From base working directory** +```sh +cargo new hello_fuchsia +``` + +The rest of this walkthrough will take place from `hello_fuchsia`, so we can +change into that directory now: + +```sh +cd hello_fuchsia +``` + +*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/` +directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.* + +We can edit our `src/main.rs` to include a test as follows: + +**`src/main.rs`** +```rust +fn main() { + println!("Hello Fuchsia!"); +} + +#[test] +fn it_works() { + assert_eq!(2 + 2, 4); +} +``` + +In addition to the standard workspace created, we will want to create a +`.cargo/config.toml` file to link necessary libraries +during compilation: + +**`.cargo/config.toml`** +```txt +[target.x86_64-fuchsia] + +rustflags = [ + "-Lnative=/arch/x64/lib", + "-Lnative=/arch/x64/sysroot/lib" +] +``` + +*Note: Make sure to fill out `` with the path to the downloaded [Fuchsia SDK].* + +These options configure the following: + +* `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from + the SDK +* `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot + libraries from the SDK + +In total, our new project will look like: + +**Current directory structure** +```txt +hello_fuchsia/ +┣┠src/ +┃ ┗┠main.rs +┣┠Cargo.toml +┗┠.cargo/ + ┗┠config.toml +``` + +Finally, we can build our rust binary as: + +```sh +cargo build --target x86_64-fuchsia +``` + +Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`, +targeting our desired Fuchsia target. + +**Current directory structure** +```txt +hello_fuchsia/ +┣┠src/ +┃ ┗┠main.rs +┣┠target/ +┃ ┗┠x86_64-fuchsia/ +┃ ┗┠debug/ +┃ ┗┠hello_fuchsia +┣┠Cargo.toml +┗┠.cargo/ + ┗┠config.toml +``` + +### Targeting Fuchsia with a compiler built from source + +An alternative to the first workflow is to target Fuchsia by using +`rustc` built from source. Before building Rust for Fuchsia, you'll need a clang toolchain that supports Fuchsia as well. A recent version (14+) of clang should be sufficient to compile Rust for Fuchsia. -You'll also need a recent copy of the [Fuchsia SDK], which provides the tools -and binaries required to build and link programs for Fuchsia. - -[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core - x86-64 and AArch64 Fuchsia targets can be enabled using the following configuration. @@ -53,12 +196,6 @@ In `config.toml`, add: ```toml [build] target = ["", "aarch64-fuchsia", "x86_64-fuchsia"] - -[target.x86_64-fuchsia] -llvm-libunwind = "in-tree" - -[target.aarch64-fuchsia] -llvm-libunwind = "in-tree" ``` Additionally, the following environment variables must be configured (for @@ -81,15 +218,21 @@ export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/ These can be run together in a shell environment by executing `(source config-env.sh && ./x.py install)`. -## Building Rust programs +Once `rustc` is installed, we can create a new working directory to work from, +`hello_fuchsia` along with `hello_fuchsia/src`: -After compiling Rust binaries, you'll need to build a component, package it, and -serve it to a Fuchsia device or emulator. All of this can be done using the -Fuchsia SDK. +```sh +mkdir hello_fuchsia +cd hello_fuchsia +mkdir src +``` + +*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/` +directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.* -As an example, we'll compile and run this simple program on a Fuchsia emulator: +There, we can create a new file named `src/hello_fuchsia.rs`: -**`hello_fuchsia.rs`** +**`src/hello_fuchsia.rs`** ```rust fn main() { println!("Hello Fuchsia!"); @@ -101,45 +244,113 @@ fn it_works() { } ``` -Create a new file named `hello_fuchsia.rs` and fill out its contents with that -code. +**Current directory structure** +```txt +hello_fuchsia/ +┗┠src/ + ┗┠hello_fuchsia.rs +``` + +Using your freshly installed `rustc`, you can compile a binary for Fuchsia using +the following options: + +* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia + platform of your choice +* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from + the SDK +* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot + libraries from the SDK -### Create a package +Putting it all together: +```sh +# Configure these for the Fuchsia target of your choice +TARGET_ARCH="" +ARCH="" + +rustc \ + --target ${TARGET_ARCH} \ + -Lnative=${SDK_PATH}/arch/${ARCH}/lib \ + -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \ + --out-dir bin src/hello_fuchsia.rs +``` + +**Current directory structure** +```txt +hello_fuchsia/ +┣┠src/ +┃ ┗┠hello_fuchsia.rs +┗┠bin/ + ┗┠hello_fuchsia +``` + +## Creating a Fuchsia package + +Before moving on, double check your directory structure: + +**Current directory structure** +```txt +hello_fuchsia/ +┣┠src/ (if using rustc) +┃ ┗┠hello_fuchsia.rs ... +┣┠bin/ ... +┃ ┗┠hello_fuchsia ... +┣┠src/ (if using cargo) +┃ ┗┠main.rs ... +┗┠target/ ... + ┗┠x86_64-fuchsia/ ... + ┗┠debug/ ... + ┗┠hello_fuchsia ... +``` + +With our Rust binary built, we can move to creating a Fuchsia package. On Fuchsia, a package is the unit of distribution for software. We'll need to create a new package directory where we will place files like our finished -binary and any data it may need. The working directory will have this layout: +binary and any data it may need. + +To start, make the `pkg`, and `pkg/meta` directories: + +```sh +mkdir pkg +mkdir pkg/meta +``` +**Current directory structure** ```txt -hello_fuchsia.rs -hello_fuchsia.cml -package -┣┠bin -┃ ┗┠hello_fuchsia -┣┠meta -┃ ┣┠package -┃ ┗┠hello_fuchsia.cm -┗┠hello_fuchsia.manifest +hello_fuchsia/ +┗┠pkg/ + ┗┠meta/ ``` -Make the `package`, `package/bin`, and `package/meta` directories and create the -following files inside: +Now, create the following files inside: -**`package/meta/package`** +**`pkg/meta/package`** ```json -{"name":"hello_fuchsia","version":0} +{ + "name": "hello_fuchsia", + "version": "0" +} ``` The `package` file describes our package's name and version number. Every package must contain one. -**`package/hello_fuchsia.manifest`** +**`pkg/hello_fuchsia.manifest` if using cargo** +```txt +bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia +lib/ld.so.1=/arch/x64/sysroot/dist/lib/ld.so.1 +lib/libfdio.so=/arch/x64/dist/libfdio.so +meta/package=pkg/meta/package +meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm +``` + +**`pkg/hello_fuchsia.manifest` if using rustc** ```txt -bin/hello_fuchsia=package/bin/hello_fuchsia +bin/hello_fuchsia=bin/hello_fuchsia lib/ld.so.1=/arch/x64/sysroot/dist/lib/ld.so.1 lib/libfdio.so=/arch/x64/dist/libfdio.so -meta/package=package/meta/package -meta/hello_fuchsia.cm=package/meta/hello_fuchsia.cm +meta/package=pkg/meta/package +meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm ``` *Note: Relative manifest paths are resolved starting from the working directory @@ -147,42 +358,26 @@ of `pm`. Make sure to fill out `` with the path to the downloaded SDK.* The `.manifest` file will be used to describe the contents of the package by -relating their location when installed to their location on the file system. You -can use this to make a package pull files from other places, but for this -example we'll just be placing everything in the `package` directory. - -### Compiling a binary - -Using your freshly compiled `rustc`, you can compile a binary for Fuchsia using -the following options: +relating their location when installed to their location on the file system. The +`bin/hello_fuchsia=` entry will be different depending on how your Rust binary +was built, so choose accordingly. -* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia - platform of your choice -* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from - the SDK -* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel - libraries from the SDK - -Putting it all together: - -```sh -# Configure these for the Fuchsia target of your choice -TARGET_ARCH="" -ARCH="" - -rustc --target ${TARGET_ARCH} -Lnative=${SDK_PATH}/arch/${ARCH}/lib -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib -o package/bin/hello_fuchsia hello_fuchsia.rs +**Current directory structure** +```txt +hello_fuchsia/ +┗┠pkg/ + ┣┠meta/ + ┃ ┗┠package + ┗┠hello_fuchsia.manifest ``` -### Bulding a component +### Creating a Fuchsia component -On Fuchsia, components require a component manifest written in Fuchia's markup +On Fuchsia, components require a component manifest written in Fuchsia's markup language called CML. The Fuchsia devsite contains an [overview of CML] and a [reference for the file format]. Here's a basic one that can run our single binary: -[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests -[reference for the file format]: https://fuchsia.dev/reference/cml - -**`hello_fuchsia.cml`** +**`pkg/hello_fuchsia.cml`** ```txt { include: [ "syslog/client.shard.cml" ], @@ -193,43 +388,154 @@ language called CML. The Fuchsia devsite contains an [overview of CML] and a } ``` +**Current directory structure** +```txt +hello_fuchsia/ +┗┠pkg/ + ┣┠meta/ + ┃ ┗┠package + ┣┠hello_fuchsia.manifest + ┗┠hello_fuchsia.cml +``` + Now we can compile that CML into a component manifest: ```sh -${SDK_PATH}/tools/${ARCH}/cmc compile hello_fuchsia.cml --includepath ${SDK_PATH}/pkg -o package/meta/hello_fuchsia.cm +${SDK_PATH}/tools/${ARCH}/cmc compile \ + pkg/hello_fuchsia.cml \ + --includepath ${SDK_PATH}/pkg \ + -o pkg/meta/hello_fuchsia.cm ``` -`--includepath` tells the compiler where to look for `include`s from our CML. -In our case, we're only using `syslog/client.shard.cml`. +*Note: `--includepath` tells the compiler where to look for `include`s from our CML. +In our case, we're only using `syslog/client.shard.cml`.* -### Building and publishing a package +**Current directory structure** +```txt +hello_fuchsia/ +┗┠pkg/ + ┣┠meta/ + ┃ ┣┠package + ┃ ┗┠hello_fuchsia.cm + ┣┠hello_fuchsia.manifest + ┗┠hello_fuchsia.cml +``` -Next, we'll build our package as defined by our manifest: +### Building a Fuchsia package + +Next, we'll build a package manifest as defined by our manifest: ```sh -${SDK_PATH}/tools/${ARCH}/pm -o hello_fuchsia -m package/hello_fuchsia.manifest build -output-package-manifest hello_fuchsia_manifest +${SDK_PATH}/tools/${ARCH}/pm \ + -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 | awk -F ' ' '{print $2}') \ + -o pkg/hello_fuchsia_manifest \ + -m pkg/hello_fuchsia.manifest \ + build \ + -output-package-manifest pkg/hello_fuchsia_package_manifest +``` + +This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can +publish directly to a repository. + +**Current directory structure** +```txt +hello_fuchsia/ +┗┠pkg/ + ┣┠meta/ + ┃ ┣┠package + ┃ ┗┠hello_fuchsia.cm + ┣┠hello_fuchsia_manifest/ + ┃ ┗┠... + ┣┠hello_fuchsia.manifest + ┣┠hello_fuchsia.cml + ┗┠hello_fuchsia_package_manifest ``` -This will produce `hello_fuchsia_manifest` which is a package manifest we can -publish directly to a repository. We can set up that repository with: +We are now ready to publish the package. + +## Publishing a Fuchsia package + +With our package and component manifests setup, +we can now publish our package. The first step will +be to create a Fuchsia package repository to publish +to. + +### Creating a Fuchsia package repository + +We can set up our repository with: ```sh -${SDK_PATH}/tools/${ARCH}/pm newrepo -repo repo +${SDK_PATH}/tools/${ARCH}/pm newrepo \ + -repo pkg/repo ``` -And then publish our new package to that repository with: +**Current directory structure** +```txt +hello_fuchsia/ +┗┠pkg/ + ┣┠meta/ + ┃ ┣┠package + ┃ ┗┠hello_fuchsia.cm + ┣┠hello_fuchsia_manifest/ + ┃ ┗┠... + ┣┠repo/ + ┃ ┗┠... + ┣┠hello_fuchsia.manifest + ┣┠hello_fuchsia.cml + ┗┠hello_fuchsia_package_manifest +``` + +## Publishing Fuchsia package to repository + +We can publish our new package to that repository with: ```sh -${SDK_PATH}/tools/${ARCH}/pm publish -repo repo -lp -f <(echo "hello_fuchsia_manifest") +${SDK_PATH}/tools/${ARCH}/pm publish \ + -repo pkg/repo \ + -lp -f <(echo "pkg/hello_fuchsia_package_manifest") ``` -Then we can add it to `ffx`'s package server as `hello-fuchsia` using: +Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using: ```sh -${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm repo -r hello-fuchsia +${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \ + pkg/repo \ + -r hello-fuchsia +``` + +## Running a Fuchsia component on an emulator + +At this point, we are ready to run our Fuchsia +component. For reference, our final directory +structure will look like: + +**Final directory structure** +```txt +hello_fuchsia/ +┣┠src/ (if using rustc) +┃ ┗┠hello_fuchsia.rs ... +┣┠bin/ ... +┃ ┗┠hello_fuchsia ... +┣┠src/ (if using cargo) +┃ ┗┠main.rs ... +┣┠target/ ... +┃ ┗┠x86_64-fuchsia/ ... +┃ ┗┠debug/ ... +┃ ┗┠hello_fuchsia ... +┗┠pkg/ + ┣┠meta/ + ┃ ┣┠package + ┃ ┗┠hello_fuchsia.cm + ┣┠hello_fuchsia_manifest/ + ┃ ┗┠... + ┣┠repo/ + ┃ ┗┠... + ┣┠hello_fuchsia.manifest + ┣┠hello_fuchsia.cml + ┗┠hello_fuchsia_package_manifest ``` -### Starting the emulator +### Starting the Fuchsia emulator Start a Fuchsia emulator in a new terminal using: @@ -238,39 +544,85 @@ ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH} ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless ``` -Then, once the emulator has been started: +### Watching emulator logs + +Once the emulator is running, open a separate terminal to watch the emulator logs: + +**In separate terminal** +```sh +${SDK_PATH}/tools/${ARCH}/ffx log \ + --since now +``` + +### Serving a Fuchsia package + +Now, start a package repository server to serve our +package to the emulator: ```sh -${SDK_PATH}/tools/${ARCH}/ffx target repository register +${SDK_PATH}/tools/${ARCH}/ffx repository server start ``` -And watch the logs from the emulator in a separate terminal: +Once the repository server is up and running, register it with the target Fuchsia system running in the emulator: ```sh -${SDK_PATH}/tools/${ARCH}/ffx log --since now +${SDK_PATH}/tools/${ARCH}/ffx target repository register \ + --repository hello-fuchsia ``` +### Running a Fuchsia component + Finally, run the component: ```sh -${SDK_PATH}/tools/${ARCH}/ffx component run fuchsia-pkg://hello-fuchsia/hello_fuchsia#meta/hello_fuchsia.cm +${SDK_PATH}/tools/${ARCH}/ffx component run \ + /core/ffx-laboratory:hello_fuchsia \ + fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm ``` On reruns of the component, the `--recreate` argument may also need to be passed. +```sh +${SDK_PATH}/tools/${ARCH}/ffx component run \ + --recreate \ + /core/ffx-laboratory:hello_fuchsia \ + fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm +``` + +## `.gitignore` extensions + +Optionally, we can create/extend our `.gitignore` file to ignore files and +directories that are not helpful to track: + +```txt +pkg/repo +pkg/meta/hello_fuchsia.cm +pkg/hello_fuchsia_manifest +pkg/hello_fuchsia_package_manifest +``` + ## Testing ### Running unit tests -Tests can be run in the same way as a regular binary, simply by passing `--test` -to the `rustc` invocation and then repackaging and rerunning. The test harness -will run the applicable unit tests. +Tests can be run in the same way as a regular binary. + +* If using `cargo`, you can simply pass `test --no-run` +to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example, +this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable +binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-)` +into `pkg/hello_fuchsia.manifest`. + +* If using the compiled `rustc`, you can simply pass `--test` +to the `rustc` invocation and then repackage and rerun the Fuchsia package. + +The test harness will run the applicable unit tests. Often when testing, you may want to pass additional command line arguments to your binary. Additional arguments can be set in the component manifest: -**`hello_fuchsia.cml`** +**`pkg/hello_fuchsia.cml`** ```txt { include: [ "syslog/client.shard.cml" ], @@ -285,11 +637,148 @@ your binary. Additional arguments can be set in the component manifest: This will pass the argument `it_works` to the binary, filtering the tests to only those tests that match the pattern. There are many more configuration options available in CML including environment variables. More documentation is -available on the [Fuchsia devsite](https://fuchsia.dev/reference/cml). +available on the [Fuchsia devsite]. ### Running the compiler test suite Running the Rust test suite on Fuchsia is [not currently supported], but work is underway to enable it. +## Debugging + +### `zxdb` + +Debugging components running on a Fuchsia emulator can be done using the +console-mode debugger: [zxdb]. We will demonstrate attaching necessary symbol +paths to debug our `hello-fuchsia` component. + +### Attaching `zxdb` + +In a separate terminal, issue the following command from our `hello_fuchsia` +directory to launch `zxdb`: + +**In separate terminal** +```sh +${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \ + --symbol-path target/x86_64-fuchsia/debug +``` + +* `--symbol-path` gets required symbol paths, which are +necessary for stepping through your program. + +The "[displaying source code in `zxdb`](#displaying-source-code-in-zxdb)" section describes how you can +display Rust and/or Fuchsia source code in your debugging session. + +### Using `zxdb` + +Once launched, you will be presented with the window: + +```sh +Connecting (use "disconnect" to cancel)... +Connected successfully. +👉 To get started, try "status" or "help". +[zxdb] +``` + +To attach to our program, we can run: + +```sh +[zxdb] attach hello_fuchsia +``` + +**Expected output** +```sh +Waiting for process matching "hello_fuchsia". +Type "filter" to see the current filters. +``` + +Next, we can create a breakpoint at main using "b main": + +```sh +[zxdb] b main +``` + +**Expected output** +```sh +Created Breakpoint 1 @ main +``` + +Finally, we can re-run the "hello_fuchsia" component from our original +terminal: + +```sh +${SDK_PATH}/tools/${ARCH}/ffx component run \ + --recreate \ + fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm +``` + +Once our component is running, our `zxdb` window will stop execution +in our main as desired: + +**Expected output** +```txt +Breakpoint 1 now matching 1 addrs for main +🛑 on bp 1 hello_fuchsia::main() • main.rs:2 + 1 fn main() { + ▶ 2 println!("Hello Fuchsia!"); + 3 } + 4 +[zxdb] +``` + +`zxdb` has similar commands to other debuggers like [gdb]. +To list the available commands, run "help" in the +`zxdb` window or visit [the zxdb documentation]. + +```sh +[zxdb] help +``` + +**Expected output** +```sh +Help! + + Type "help " for command-specific help. + +Other help topics (see "help ") +... +``` + +### Displaying source code in `zxdb` + +By default, the debugger will not be able to display +source code while debugging. For our user code, we displayed +source code by pointing our debugger to our debug binary via +the `--symbol-path` arg. To display library source code in +the debugger, you must provide paths to the source using +`--build-dir`. For example, to display the Rust and Fuchsia +source code: + +```sh +${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \ + --symbol-path target/x86_64-fuchsia/debug \ + --build-dir ${RUST_SRC_PATH}/rust \ + --build-dir ${FUCHSIA_SRC_PATH}/fuchsia/out/default +``` + + * `--build-dir` links against source code paths, which + are not strictly necessary for debugging, but is a nice-to-have + for displaying source code in `zxdb`. + + Linking to a Fuchsia checkout can help with debugging Fuchsia libraries, + such as [fdio]. + +[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json +[Fuchsia]: https://fuchsia.dev/ +[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build +[rustup]: https://rustup.rs/ +[cargo]: https://doc.rust-lang.org/cargo/ +[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core +[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests +[reference for the file format]: https://fuchsia.dev/reference/cml +[Fuchsia devsite]: https://fuchsia.dev/reference/cml [not currently supported]: https://fxbug.dev/105393 +[zxdb]: https://fuchsia.dev/fuchsia-src/development/debugger +[gdb]: https://www.sourceware.org/gdb/ +[the zxdb documentation]: https://fuchsia.dev/fuchsia-src/development/debugger +[fdio]: https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/fdio/ diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md index d325ba334..b18a125f3 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md @@ -87,7 +87,7 @@ Rust programs can be built for that target: rustc --target m68k-unknown-linux-gnu your-code.rs ``` -Very simple progams can be run using the `qemu-m68k-static` program: +Very simple programs can be run using the `qemu-m68k-static` program: ```text $ qemu-m68k-static your-code diff --git a/src/doc/rustc/src/platform-support/openbsd.md b/src/doc/rustc/src/platform-support/openbsd.md index b2ac776ea..4ce80157d 100644 --- a/src/doc/rustc/src/platform-support/openbsd.md +++ b/src/doc/rustc/src/platform-support/openbsd.md @@ -12,6 +12,8 @@ The target names follow this format: `$ARCH-unknown-openbsd`, where `$ARCH` spec |--------------------------------|-------------|------------------| | `aarch64-unknown-openbsd` | libc++ | [64-bit ARM systems](https://www.openbsd.org/arm64.html) | | `i686-unknown-openbsd` | libc++ | [Standard PC and clones based on the Intel i386 architecture and compatible processors](https://www.openbsd.org/i386.html) | +| `powerpc64-unknown-openbsd` | libc++ | [IBM POWER-based PowerNV systems](https://www.openbsd.org/powerpc64.html) | +| `riscv64gc-unknown-openbsd` | libc++ | [64-bit RISC-V systems](https://www.openbsd.org/riscv64.html) | | `sparc64-unknown-openbsd` | estdc++ | [Sun UltraSPARC and Fujitsu SPARC64 systems](https://www.openbsd.org/sparc64.html) | | `x86_64-unknown-openbsd` | libc++ | [AMD64-based systems](https://www.openbsd.org/amd64.html) | diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md index 721c234c6..fb0cea05d 100644 --- a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md +++ b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md @@ -25,7 +25,7 @@ Like with any other Windows target created binaries are in PE format. ## Building the target -For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. +For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring cross compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. Native bootstrapping builds require rather fragile hacks until host artifacts are available so I won't describe them here. ## Building Rust programs diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index 8f90d9c74..295dec0f0 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -133,7 +133,7 @@ There are 3 common ways to compile native C code for UEFI targets: - Use native Windows targets. This means compiling your C code for the Windows platform as if it was the UEFI platform. This works for static libraries, but needs adjustments when linking into an UEFI executable. You can, however, - link such static libraries seemlessly into rust code compiled for UEFI + link such static libraries seamlessly into rust code compiled for UEFI targets. Be wary of any includes that are not specifically suitable for UEFI targets (especially the C standard library includes are not always compatible). Freestanding compilations are recommended to avoid diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index 021b904de..6932e6a57 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -30,7 +30,7 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum memory size is now the full 64-bit address space instead of the 4GB as limited by the 32-bit address space for `wasm32-unknown-unknown`. -This target is not a stable target. The [memory64] WebAssembly proposal is stil +This target is not a stable target. The [memory64] WebAssembly proposal is still in-progress and not standardized. This means that there are not many engines which implement the `memory64` feature and if they do they're likely behind a flag, for example: diff --git a/src/doc/rustdoc/book.toml b/src/doc/rustdoc/book.toml index 45405a117..dfa685785 100644 --- a/src/doc/rustdoc/book.toml +++ b/src/doc/rustdoc/book.toml @@ -6,5 +6,9 @@ title = "The rustdoc book" git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc" [output.html.redirect] +"/what-to-include.html" = "write-documentation/what-to-include.html" "/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html" +"/linking-to-items-by-name.html" = "write-documentation/linking-to-items-by-name.html" "/documentation-tests.html" = "write-documentation/documentation-tests.html" +"/website-features.html" = "advanced-features.html#custom-search-engines" +"/passes.html" = "deprecated-features.html#passes" diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index bfa92e7d3..321992f7b 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -143,7 +143,7 @@ fn do_features() {} #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names() // and because no value checking was enable for "has_feathers" - // no warning is emited for the value "zapping" + // no warning is emitted for the value "zapping" fn do_zapping() {} #[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and diff --git a/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md index 977d25852..3890a12b7 100644 --- a/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md +++ b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md @@ -8,7 +8,7 @@ This flag will rewrite absolute paths under the current working directory, replacing the current working directory prefix with a specified value. The given value may be absolute or relative, or empty. This switch takes -precidence over `--remap-path-prefix` in case they would both match a given +precedence over `--remap-path-prefix` in case they would both match a given path. This flag helps to produce deterministic output, by removing the current working diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 7f7549aaf..b33405f18 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -9,17 +9,17 @@ The tracking issues for this feature are: This feature allows for use of one of following sanitizers: -* [AddressSanitizer][clang-asan] a fast memory error detector. -* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides +* [AddressSanitizer](#addresssanitizer) a fast memory error detector. +* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity (CFI) provides forward-edge control flow protection. -* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to +* [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to AddressSanitizer, but based on partial hardware assistance. -* [LeakSanitizer][clang-lsan] a run-time memory leak detector. -* [MemorySanitizer][clang-msan] a detector of uninitialized reads. -* [MemTagSanitizer][clang-memtag] fast memory error detector based on +* [LeakSanitizer](#leaksanitizer) a run-time memory leak detector. +* [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. +* [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on Armv8.5-A Memory Tagging Extension. -* [ShadowCallStack][clang-scs] provides backward-edge control flow protection. -* [ThreadSanitizer][clang-tsan] a fast data race detector. +* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection. +* [ThreadSanitizer](#threadsanitizer) a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, @@ -58,6 +58,8 @@ AddressSanitizer works with non-instrumented code although it will impede its ability to detect some bugs. It is not expected to produce false positive reports. +See the [Clang AddressSanitizer documentation][clang-asan] for more details. + ## Examples Stack buffer overflow: @@ -204,6 +206,8 @@ tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)). LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto). +See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. + ## Example ```text @@ -430,6 +434,8 @@ HWAddressSanitizer requires `tagged-globals` target feature to instrument globals. To enable this target feature compile with `-C target-feature=+tagged-globals` +See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details. + ## Example Heap buffer overflow: @@ -507,6 +513,8 @@ LeakSanitizer is supported on the following targets: * `x86_64-apple-darwin` * `x86_64-unknown-linux-gnu` +See the [Clang LeakSanitizer documentation][clang-lsan] for more details. + # MemorySanitizer MemorySanitizer is detector of uninitialized reads. @@ -521,6 +529,8 @@ MemorySanitizer requires all program code to be instrumented. C/C++ dependencies need to be recompiled using Clang with `-fsanitize=memory` option. Failing to achieve that will result in false positive reports. +See the [Clang MemorySanitizer documentation][clang-msan] for more details. + ## Example Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and @@ -569,7 +579,7 @@ MemTagSanitizer is supported on the following targets: MemTagSanitizer requires hardware support and the `mte` target feature. To enable this target feature compile with `-C target-feature="+mte"`. -More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html). +See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details. # ShadowCallStack @@ -581,7 +591,9 @@ ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and i * `aarch64-linux-android` -A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details. +A runtime must be provided by the application or operating system. + +See the [Clang ShadowCallStack documentation][clang-scs] for more details. # ThreadSanitizer @@ -604,6 +616,8 @@ can lead to false positive reports. ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`, nor synchronization performed using inline assembly code. +See the [Clang ThreadSanitizer documentation][clang-tsan] for more details. + ## Example ```rust @@ -673,6 +687,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT * [HWAddressSanitizer in Clang][clang-hwasan] * [LeakSanitizer in Clang][clang-lsan] * [MemorySanitizer in Clang][clang-msan] +* [MemTagSanitizer in LLVM][llvm-memtag] * [ThreadSanitizer in Clang][clang-tsan] [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html @@ -682,3 +697,4 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html +[llvm-memtag]: https://llvm.org/docs/MemTagSanitizer.html diff --git a/src/doc/unstable-book/src/language-features/raw-dylib.md b/src/doc/unstable-book/src/language-features/raw-dylib.md index 23fc5b305..5fd208ae7 100644 --- a/src/doc/unstable-book/src/language-features/raw-dylib.md +++ b/src/doc/unstable-book/src/language-features/raw-dylib.md @@ -26,9 +26,9 @@ fn main() { ## Limitations -Currently, this feature is only supported on `-windows-msvc` targets. Non-Windows platforms don't have import -libraries, and an incompatibility between LLVM and the BFD linker means that it is not currently supported on -`-windows-gnu` targets. +This feature is unstable for the `x86` architecture, and stable for all other architectures. -On the `i686-pc-windows-msvc` target, this feature supports only the `cdecl`, `stdcall`, `system`, and `fastcall` -calling conventions. +This feature is only supported on Windows. + +On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and +`vectorcall` calling conventions. diff --git a/src/doc/unstable-book/src/language-features/unix-sigpipe.md b/src/doc/unstable-book/src/language-features/unix-sigpipe.md new file mode 100644 index 000000000..aa39b6eb2 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/unix-sigpipe.md @@ -0,0 +1,54 @@ +# `unix_sigpipe` + +The tracking issue for this feature is: [#97889] + +[#97889]: https://github.com/rust-lang/rust/issues/97889 + +--- + +The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants: +* `#[unix_sigpipe = "inherit"]` +* `#[unix_sigpipe = "sig_dfl"]` +* `#[unix_sigpipe = "sig_ign"]` + +## `#[unix_sigpipe = "inherit"]` + +Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`. + +## `#[unix_sigpipe = "sig_dfl"]` + +Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output. + +### Example + +```rust,no_run +#![feature(unix_sigpipe)] +#[unix_sigpipe = "sig_dfl"] +fn main() { loop { println!("hello world"); } } +``` + +```bash +% ./main | head -n 1 +hello world +``` + +## `#[unix_sigpipe = "sig_ign"]` + +Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers. + +This is what libstd has done by default since 2014. Omitting `#[unix_sigpipe = "..."]` is the same as having `#[unix_sigpipe = "sig_ign"]`. + +### Example + +```rust,no_run +#![feature(unix_sigpipe)] +#[unix_sigpipe = "sig_ign"] +fn main() { loop { println!("hello world"); } } +``` + +```bash +% ./main | head -n 1 +hello world +thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +``` diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py deleted file mode 100644 index 343dd0387..000000000 --- a/src/etc/check_missing_items.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python - -# This test ensures that every ID in the produced json actually resolves to an item either in -# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in -# any way correct, for example an empty map would pass. - -# FIXME: Better error output - -import sys -import json - -crate = json.load(open(sys.argv[1], encoding="utf-8")) - - -def get_local_item(item_id): - if item_id in crate["index"]: - return crate["index"][item_id] - print("Missing local ID:", item_id) - sys.exit(1) - - -# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have -# to be in `paths` -def valid_id(item_id): - return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"] - - -def check_generics(generics): - for param in generics["params"]: - check_generic_param(param) - for where_predicate in generics["where_predicates"]: - if "bound_predicate" in where_predicate: - pred = where_predicate["bound_predicate"] - check_type(pred["type"]) - for bound in pred["bounds"]: - check_generic_bound(bound) - elif "region_predicate" in where_predicate: - pred = where_predicate["region_predicate"] - for bound in pred["bounds"]: - check_generic_bound(bound) - elif "eq_predicate" in where_predicate: - pred = where_predicate["eq_predicate"] - check_type(pred["rhs"]) - check_type(pred["lhs"]) - - -def check_generic_param(param): - if "type" in param["kind"]: - ty = param["kind"]["type"] - if ty["default"]: - check_type(ty["default"]) - elif "const" in param["kind"]: - check_type(param["kind"]["const"]) - - -def check_generic_bound(bound): - if "trait_bound" in bound: - for param in bound["trait_bound"]["generic_params"]: - check_generic_param(param) - check_type(bound["trait_bound"]["trait"]) - - -def check_decl(decl): - for (_name, ty) in decl["inputs"]: - check_type(ty) - if decl["output"]: - check_type(decl["output"]) - - -def check_type(ty): - if ty["kind"] == "resolved_path": - for bound in ty["inner"]["param_names"]: - check_generic_bound(bound) - args = ty["inner"]["args"] - if args: - if "angle_bracketed" in args: - for arg in args["angle_bracketed"]["args"]: - if "type" in arg: - check_type(arg["type"]) - elif "const" in arg: - check_type(arg["const"]["type"]) - for binding in args["angle_bracketed"]["bindings"]: - if "equality" in binding["binding"]: - term = binding["binding"]["equality"] - if "type" in term: check_type(term["type"]) - elif "const" in term: check_type(term["const"]) - elif "constraint" in binding["binding"]: - for bound in binding["binding"]["constraint"]: - check_generic_bound(bound) - elif "parenthesized" in args: - for ty in args["parenthesized"]["inputs"]: - check_type(ty) - if args["parenthesized"]["output"]: - check_type(args["parenthesized"]["output"]) - if not valid_id(ty["inner"]["id"]): - print("Type contained an invalid ID:", ty["inner"]["id"]) - sys.exit(1) - elif ty["kind"] == "tuple": - for ty in ty["inner"]: - check_type(ty) - elif ty["kind"] == "slice": - check_type(ty["inner"]) - elif ty["kind"] == "impl_trait": - for bound in ty["inner"]: - check_generic_bound(bound) - elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"): - check_type(ty["inner"]["type"]) - elif ty["kind"] == "function_pointer": - for param in ty["inner"]["generic_params"]: - check_generic_param(param) - check_decl(ty["inner"]["decl"]) - elif ty["kind"] == "qualified_path": - check_type(ty["inner"]["self_type"]) - check_type(ty["inner"]["trait"]) - - -work_list = set([crate["root"]]) -visited = work_list.copy() - -while work_list: - current = work_list.pop() - visited.add(current) - item = get_local_item(current) - # check intradoc links - for (_name, link) in item["links"].items(): - if not valid_id(link): - print("Intra-doc link contains invalid ID:", link) - - # check all fields that reference types such as generics as well as nested items - # (modules, structs, traits, and enums) - if item["kind"] == "module": - work_list |= set(item["inner"]["items"]) - visited - elif item["kind"] == "struct": - check_generics(item["inner"]["generics"]) - work_list |= ( - set(item["inner"]["fields"]) | set(item["inner"]["impls"]) - ) - visited - elif item["kind"] == "struct_field": - check_type(item["inner"]) - elif item["kind"] == "enum": - check_generics(item["inner"]["generics"]) - work_list |= ( - set(item["inner"]["variants"]) | set(item["inner"]["impls"]) - ) - visited - elif item["kind"] == "variant": - if item["inner"]["variant_kind"] == "tuple": - for ty in item["inner"]["variant_inner"]: - check_type(ty) - elif item["inner"]["variant_kind"] == "struct": - work_list |= set(item["inner"]["variant_inner"]) - visited - elif item["kind"] in ("function", "method"): - check_generics(item["inner"]["generics"]) - check_decl(item["inner"]["decl"]) - elif item["kind"] in ("static", "constant", "assoc_const"): - check_type(item["inner"]["type"]) - elif item["kind"] == "typedef": - check_type(item["inner"]["type"]) - check_generics(item["inner"]["generics"]) - elif item["kind"] == "opaque_ty": - check_generics(item["inner"]["generics"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - elif item["kind"] == "trait_alias": - check_generics(item["inner"]["params"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - elif item["kind"] == "trait": - check_generics(item["inner"]["generics"]) - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - work_list |= ( - set(item["inner"]["items"]) | set(item["inner"]["implementations"]) - ) - visited - elif item["kind"] == "impl": - check_generics(item["inner"]["generics"]) - if item["inner"]["trait"]: - check_type(item["inner"]["trait"]) - if item["inner"]["blanket_impl"]: - check_type(item["inner"]["blanket_impl"]) - check_type(item["inner"]["for"]) - for assoc_item in item["inner"]["items"]: - if not valid_id(assoc_item): - print("Impl block referenced a missing ID:", assoc_item) - sys.exit(1) - elif item["kind"] == "assoc_type": - for bound in item["inner"]["bounds"]: - check_generic_bound(bound) - if item["inner"]["default"]: - check_type(item["inner"]["default"]) diff --git a/src/etc/cpu-usage-over-time-plot.sh b/src/etc/cpu-usage-over-time-plot.sh index 1c3425591..2617378ba 100755 --- a/src/etc/cpu-usage-over-time-plot.sh +++ b/src/etc/cpu-usage-over-time-plot.sh @@ -15,7 +15,7 @@ # Improvements to this script are greatly appreciated! if [[ $# != 2 ]]; then - echo "expected 2 arguments, recieved $#" + echo "expected 2 arguments, received $#" echo "example usage: './src/etc/cpu-usage-over-time-plot.sh \ 7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c \ x86_64-gnu'" diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index 292e91b4d..8171cb4e9 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -89,4 +89,7 @@ def lookup(valobj): if rust_type == RustType.STD_REF_CELL: return StdRefCellProvider(valobj) + if rust_type == RustType.STD_NONZERO_NUMBER: + return StdNonZeroNumberProvider(valobj) + return None diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index 0a52b8c97..c351c3450 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -231,6 +231,17 @@ class StdRefCellProvider: yield "borrow", self.borrow +class StdNonZeroNumberProvider: + def __init__(self, valobj): + fields = valobj.type.fields() + assert len(fields) == 1 + field = list(fields)[0] + self.value = str(valobj[field.name]) + + def to_string(self): + return self.value + + # Yields children (in a provider's sense of the word) for a BTreeMap. def children_of_btree_map(map): # Yields each key/value pair in the node and in any child nodes. diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index d02ac9d9c..c97fb4b80 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -41,15 +41,15 @@ There are a number of supported commands: `PATH` is relative to the output directory. It can be given as `-` which repeats the most recently used `PATH`. -* `@has PATH PATTERN` and `@matches PATH PATTERN` checks for - the occurrence of the given pattern `PATTERN` in the specified file. +* `@hasraw PATH PATTERN` and `@matchesraw PATH PATTERN` checks + for the occurrence of the given pattern `PATTERN` in the specified file. Only one occurrence of the pattern is enough. - For `@has`, `PATTERN` is a whitespace-normalized (every consecutive + For `@hasraw`, `PATTERN` is a whitespace-normalized (every consecutive whitespace being replaced by one single space character) string. The entire file is also whitespace-normalized including newlines. - For `@matches`, `PATTERN` is a Python-supported regular expression. + For `@matchesraw`, `PATTERN` is a Python-supported regular expression. The file remains intact but the regexp is matched without the `MULTILINE` and `IGNORECASE` options. You can still use a prefix `(?m)` or `(?i)` to override them, and `\A` and `\Z` for definitely matching @@ -386,7 +386,7 @@ def check_tree_attr(tree, path, attr, pat, regexp): return ret -# Returns the number of occurences matching the regex (`regexp`) and the text (`pat`). +# Returns the number of occurrences matching the regex (`regexp`) and the text (`pat`). def check_tree_text(tree, path, pat, regexp, stop_at_first): path = normalize_xpath(path) match_count = 0 @@ -542,19 +542,23 @@ ERR_COUNT = 0 def check_command(c, cache): try: cerr = "" - if c.cmd == 'has' or c.cmd == 'matches': # string test - regexp = (c.cmd == 'matches') - if len(c.args) == 1 and not regexp: # @has = file existence + if c.cmd in ['has', 'hasraw', 'matches', 'matchesraw']: # string test + regexp = c.cmd.startswith('matches') + + # @has = file existence + if len(c.args) == 1 and not regexp and 'raw' not in c.cmd: try: cache.get_file(c.args[0]) ret = True except FailedCheck as err: cerr = str(err) ret = False - elif len(c.args) == 2: # @has/matches = string test + # @hasraw/matchesraw = string test + elif len(c.args) == 2 and 'raw' in c.cmd: cerr = "`PATTERN` did not match" ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp) - elif len(c.args) == 3: # @has/matches = XML tree test + # @has/matches = XML tree test + elif len(c.args) == 3 and 'raw' not in c.cmd: cerr = "`XPATH PATTERN` did not match" ret = get_nb_matching_elements(cache, c, regexp, True) != 0 else: diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index a182bc406..0aa0784e5 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -170,10 +170,6 @@ - - - - @@ -277,16 +273,6 @@ - - - - - - diff --git a/src/etc/installer/pkg/Distribution.xml b/src/etc/installer/pkg/Distribution.xml index 077ee1751..64f6bab9b 100644 --- a/src/etc/installer/pkg/Distribution.xml +++ b/src/etc/installer/pkg/Distribution.xml @@ -16,9 +16,6 @@ - - - @@ -64,24 +61,10 @@ > - - - - - - rustc.pkg cargo.pkg rust-docs.pkg rust-std.pkg - - rls.pkg - - rust-analysis.pkg uninstall.pkg diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands index 4a1204ccc..ed66ecf30 100644 --- a/src/etc/lldb_commands +++ b/src/etc/lldb_commands @@ -15,4 +15,5 @@ type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)C type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust type category enable Rust diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 3cee51982..bca9c2ae1 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -55,6 +55,9 @@ def summary_lookup(valobj, dict): if rust_type == RustType.STD_REF_CELL: return StdRefSummaryProvider(valobj, dict) + if rust_type == RustType.STD_NONZERO_NUMBER: + return StdNonZeroNumberSummaryProvider(valobj, dict) + return "" diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 35ac07f0d..8a9927e7d 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -739,3 +739,11 @@ class StdRefSyntheticProvider: def has_children(self): # type: () -> bool return True + + +def StdNonZeroNumberSummaryProvider(valobj, _dict): + # type: (SBValue, dict) -> str + objtype = valobj.GetType() + field = objtype.GetFieldAtIndex(0) + element = valobj.GetChildMemberWithName(field.name) + return element.GetValue() diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 558536fa6..277e57aaf 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -1,4 +1,4 @@ - + {(char*)data_ptr,[length]s8} @@ -150,76 +150,189 @@ - - - - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} + + + + + + + + - - - {tag(),en} - - variant0 - variant1 - variant2 - variant3 - variant4 - variant5 - variant6 - variant7 - variant8 - variant9 - variant10 - variant11 - variant12 - variant13 - variant14 - variant15 - - + + + + + + - - - {"$T2",sb} - - - {"$T2",sb} - - $T2 - - + + + + + + - - - - - {"$T4",sb}({dataful_variant}) - {discriminant,en} - - dataful_variant - - {"$T4",sb} - - - {discriminant,en} - + + + + + + + + + + + + + + + + + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 912418fa7..bf6c02b91 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -185,12 +185,4 @@

` (where P is one \ of the previous types except `Self`)"; -#[tracing::instrument(level = "debug", skip(wfcx))] +#[instrument(level = "debug", skip(wfcx))] fn check_method_receiver<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_sig: &hir::FnSig<'_>, @@ -1817,6 +1866,7 @@ fn report_bivariance( impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. + #[instrument(level = "debug", skip(self))] fn check_false_global_bounds(&mut self) { let tcx = self.ocx.infcx.tcx; let mut span = self.span; @@ -1924,40 +1974,6 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { } } -pub fn impl_implied_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: LocalDefId, - span: Span, -) -> FxHashSet> { - // We completely ignore any obligations caused by normalizing the types - // we assume to be well formed. Considering that the user of the implied - // bounds will also normalize them, we leave it to them to emit errors - // which should result in better causes and spans. - tcx.infer_ctxt().enter(|infcx| { - let cause = ObligationCause::misc(span, tcx.hir().local_def_id_to_hir_id(impl_def_id)); - match tcx.impl_trait_ref(impl_def_id) { - Some(trait_ref) => { - // Trait impl: take implied bounds from all types that - // appear in the trait reference. - match infcx.at(&cause, param_env).normalize(trait_ref) { - Ok(Normalized { value, obligations: _ }) => value.substs.types().collect(), - Err(NoSolution) => FxHashSet::default(), - } - } - - None => { - // Inherent impl: take implied bounds from the `self` type. - let self_ty = tcx.type_of(impl_def_id); - match infcx.at(&cause, param_env).normalize(self_ty) { - Ok(Normalized { value, obligations: _ }) => FxHashSet::from_iter([value]), - Err(NoSolution) => FxHashSet::default(), - } - } - } - }) -} - fn error_392( tcx: TyCtxt<'_>, span: Span, diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index f549807c3..9ecf34e9a 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -3,7 +3,6 @@ // substitutions. use crate::check::FnCtxt; - use hir::def_id::LocalDefId; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; @@ -16,6 +15,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::TypeckResults; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -192,6 +192,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + // (ouz-a 1005988): Normally `[T] : std::ops::Index` should be normalized + // into [T] but currently `Where` clause stops the normalization process for it, + // here we compare types of expr and base in a code without `Where` clause they would be equal + // if they are not we don't modify the expr, hence we bypass the ICE + fn is_builtin_index( + &mut self, + typeck_results: &TypeckResults<'tcx>, + e: &hir::Expr<'_>, + base_ty: Ty<'tcx>, + index_ty: Ty<'tcx>, + ) -> bool { + if let Some(elem_ty) = base_ty.builtin_index() { + let Some(exp_ty) = typeck_results.expr_ty_opt(e) else {return false;}; + let resolved_exp_ty = self.resolve(exp_ty, &e.span); + + elem_ty == resolved_exp_ty && index_ty == self.fcx.tcx.types.usize + } else { + false + } + } + // Similar to operators, indexing is always assumed to be overloaded // Here, correct cases where an indexing expression can be simplified // to use builtin indexing because the index type is known to be @@ -222,8 +243,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ) }); let index_ty = self.fcx.resolve_vars_if_possible(index_ty); + let resolved_base_ty = self.resolve(*base_ty, &base.span); - if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize { + if self.is_builtin_index(&typeck_results, e, resolved_base_ty, index_ty) { // Remove the method call record typeck_results.type_dependent_defs_mut().remove(e.hir_id); typeck_results.node_substs_mut().remove(e.hir_id); @@ -292,6 +314,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { intravisit::walk_expr(self, e); } + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + match &p.kind { + hir::GenericParamKind::Lifetime { .. } => { + // Nothing to write back here + } + hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { + self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}")); + } + } + } + fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { self.visit_node_id(b.span, b.hir_id); intravisit::walk_block(self, b); @@ -468,7 +501,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if !errors_buffer.is_empty() { errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - for mut diag in errors_buffer.drain(..) { + for mut diag in errors_buffer { self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); } } diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index 4a3cfa1ca..1d23ed929 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -1,5 +1,5 @@ +use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -108,25 +108,16 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // We do this in any edition. if extern_crate.warn_if_unused { if let Some(&span) = unused_extern_crates.get(&def_id) { + // Removal suggestion span needs to include attributes (Issue #54400) let id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.struct_span_lint_hir(lint, id, span, |lint| { - // Removal suggestion span needs to include attributes (Issue #54400) - let span_with_attrs = tcx - .hir() - .attrs(id) - .iter() - .map(|attr| attr.span) - .fold(span, |acc, attr_span| acc.to(attr_span)); - - lint.build("unused extern crate") - .span_suggestion_short( - span_with_attrs, - "remove it", - "", - Applicability::MachineApplicable, - ) - .emit(); - }); + let span_with_attrs = tcx + .hir() + .attrs(id) + .iter() + .map(|attr| attr.span) + .fold(span, |acc, attr_span| acc.to(attr_span)); + + tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs }); continue; } } @@ -158,23 +149,23 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { if !tcx.hir().attrs(id).is_empty() { continue; } - tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| { - // Otherwise, we can convert it into a `use` of some kind. - let base_replacement = match extern_crate.orig_name { - Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), - None => format!("use {};", item.ident.name), - }; - let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default(); - let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; - lint.build("`extern crate` is not idiomatic in the new edition") - .span_suggestion_short( - extern_crate.span, - &format!("convert it to a `{}`", add_vis("use".to_string())), - add_vis(base_replacement), - Applicability::MachineApplicable, - ) - .emit(); - }) + + let base_replacement = match extern_crate.orig_name { + Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), + None => format!("use {};", item.ident.name), + }; + let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default(); + let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; + tcx.emit_spanned_lint( + lint, + id, + extern_crate.span, + ExternCrateNotIdiomatic { + span: extern_crate.span, + msg_code: add_vis("use".to_string()), + suggestion_code: add_vis(base_replacement), + }, + ); } } diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 50946cc1d..d08c0d4db 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeV use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { @@ -47,9 +47,11 @@ impl<'tcx> Checker<'tcx> { } fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { - // Destructors only work on nominal types. - if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind() { - return; + // Destructors only work on local ADT types. + match tcx.type_of(impl_did).kind() { + ty::Adt(def, _) if def.did().is_local() => return, + ty::Error(_) => return, + _ => {} } let sp = match tcx.hir().expect_item(impl_did).kind { @@ -109,15 +111,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // it is not immediately clear why Copy is not implemented for a field, since // all we point at is the field itself. tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let mut fulfill_cx = >::new(tcx); - fulfill_cx.register_bound( + for error in traits::fully_solve_bound( &infcx, + traits::ObligationCause::dummy_with_span(field_ty_span), param_env, ty, tcx.lang_items().copy_trait().unwrap(), - traits::ObligationCause::dummy_with_span(field_ty_span), - ); - for error in fulfill_cx.select_all_or_error(&infcx) { + ) { let error_predicate = error.obligation.predicate; // Only note if it's not the root obligation, otherwise it's trivial and // should be self-explanatory (i.e. a field literally doesn't implement Copy). @@ -315,24 +315,20 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: )) .emit(); } else { - let mut fulfill_cx = >::new(infcx.tcx); - - for field in coerced_fields { - let predicate = predicate_for_trait_def( - tcx, - param_env, - cause.clone(), - dispatch_from_dyn_trait, - 0, - field.ty(tcx, substs_a), - &[field.ty(tcx, substs_b).into()], - ); - - fulfill_cx.register_predicate_obligation(&infcx, predicate); - } - - // Check that all transitive obligations are satisfied. - let errors = fulfill_cx.select_all_or_error(&infcx); + let errors = traits::fully_solve_obligations( + &infcx, + coerced_fields.into_iter().map(|field| { + predicate_for_trait_def( + tcx, + param_env, + cause.clone(), + dispatch_from_dyn_trait, + 0, + field.ty(tcx, substs_a), + &[field.ty(tcx, substs_b).into()], + ) + }), + ); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } @@ -363,7 +359,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { - tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); + tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string())); }); let source = tcx.type_of(impl_did); @@ -573,8 +569,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } }; - let mut fulfill_cx = >::new(infcx.tcx); - // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_hir_id); let predicate = predicate_for_trait_def( @@ -586,10 +580,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn source, &[target.into()], ); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - - // Check that all transitive obligations are satisfied. - let errors = fulfill_cx.select_all_or_error(&infcx); + let errors = traits::fully_solve_obligation(&infcx, predicate); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 99996e80c..45a5eca70 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -25,7 +25,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) { /////////////////////////////////////////////////////////////////////////// /// Context specific to some particular item. This is what implements -/// `AstConv`. It has information about the predicates that are defined +/// [`AstConv`]. +/// +/// # `ItemCtxt` vs `FnCtxt` +/// +/// `ItemCtxt` is primarily used to type-check item signatures and lower them +/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`]. +/// It's also used for the bodies of items like structs where the body (the fields) +/// are just signatures. +/// +/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of +/// functions, closures, and `const`s -- anywhere that expressions and statements show up. +/// +/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] -- +/// while `FnCtxt` does do inference. +/// +/// [`FnCtxt`]: crate::check::FnCtxt +/// [`InferCtxt`]: rustc_infer::infer::InferCtxt +/// +/// # Trait predicates +/// +/// `ItemCtxt` has information about the predicates that are defined /// on the trait. Unfortunately, this predicate information is /// available in various different forms at various points in the /// process. So we can't just store a pointer to e.g., the AST or the @@ -553,6 +573,7 @@ fn get_new_lifetime_name<'tcx>( /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. +#[instrument(level = "trace", skip(tcx))] fn type_param_predicates( tcx: TyCtxt<'_>, (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), @@ -659,7 +680,7 @@ impl<'tcx> ItemCtxt<'tcx> { assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); - debug!(?param_def_id); + trace!(?param_def_id); ast_generics .predicates .iter() @@ -688,9 +709,8 @@ impl<'tcx> ItemCtxt<'tcx> { .collect() } + #[instrument(level = "trace", skip(self))] fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { - debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); - match b { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; @@ -832,12 +852,14 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure().type_of(trait_item_id.def_id); } - hir::TraitItemKind::Const(..) => { + hir::TraitItemKind::Const(hir_ty, _) => { tcx.ensure().type_of(trait_item_id.def_id); // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "constant"); + if !tcx.sess.diagnostic().has_stashed_diagnostic(hir_ty.span, StashKey::ItemNoType) { + placeholder_type_error(tcx, None, visitor.0, false, None, "constant"); + } } hir::TraitItemKind::Type(_, Some(_)) => { @@ -1326,16 +1348,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option, - m: hir::TraitBoundModifier, - ) { + fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { if self.has_late_bound_regions.is_some() { return; } self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, tr, m); + intravisit::walk_poly_trait_ref(self, tr); self.outer_index.shift_out(1); } @@ -1565,8 +1583,16 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, .. - }) => Some(fn_def_id.to_def_id()), + }) => { + if in_trait { + assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn)) + } else { + assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn)) + } + Some(fn_def_id.to_def_id()) + } ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { let parent_id = tcx.hir().get_parent_item(hir_id); assert_ne!(parent_id, CRATE_DEF_ID); @@ -1580,6 +1606,13 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { _ => None, }; + enum Defaults { + Allowed, + // See #36887 + FutureCompatDisallowed, + Deny, + } + let no_generics = hir::Generics::empty(); let ast_generics = node.generics().unwrap_or(&no_generics); let (opt_self, allow_defaults) = match node { @@ -1597,22 +1630,30 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: rl::Set1::Empty, synthetic: false, }, }); - (opt_self, true) + (opt_self, Defaults::Allowed) } ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::OpaqueTy(..) - | ItemKind::Union(..) => (None, true), - _ => (None, false), + | ItemKind::Union(..) => (None, Defaults::Allowed), + _ => (None, Defaults::FutureCompatDisallowed), } } - _ => (None, false), + + // GATs + Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { + (None, Defaults::Deny) + } + Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => { + (None, Defaults::Deny) + } + + _ => (None, Defaults::FutureCompatDisallowed), }; let has_self = opt_self.is_some(); @@ -1641,39 +1682,38 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { kind: ty::GenericParamDefKind::Lifetime, })); - let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner); - // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; + const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ + `struct`, `enum`, `type`, or `trait` definitions"; + params.extend(ast_generics.params.iter().filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { ref default, synthetic, .. } => { - if !allow_defaults && default.is_some() { - if !tcx.features().default_type_parameter_fallback { - tcx.struct_span_lint_hir( - lint::builtin::INVALID_TYPE_PARAM_DEFAULT, - param.hir_id, - param.span, - |lint| { - lint.build( - "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions", - ) - .emit(); - }, - ); + if default.is_some() { + match allow_defaults { + Defaults::Allowed => {} + Defaults::FutureCompatDisallowed + if tcx.features().default_type_parameter_fallback => {} + Defaults::FutureCompatDisallowed => { + tcx.struct_span_lint_hir( + lint::builtin::INVALID_TYPE_PARAM_DEFAULT, + param.hir_id, + param.span, + |lint| { + lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit(); + }, + ); + } + Defaults::Deny => { + tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED); + } } } - let kind = ty::GenericParamDefKind::Type { - has_default: default.is_some(), - object_lifetime_default: object_lifetime_defaults - .as_ref() - .map_or(rl::Set1::Empty, |o| o[i]), - synthetic, - }; + let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; let param_def = ty::GenericParamDef { index: type_start + i as u32, @@ -1686,7 +1726,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(param_def) } GenericParamKind::Const { default, .. } => { - if !allow_defaults && default.is_some() { + if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { tcx.sess.span_err( param.span, "defaults for const parameters are only allowed in \ @@ -1725,11 +1765,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(arg), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: rl::Set1::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, })); } @@ -1742,11 +1778,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(""), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: rl::Set1::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, }); } } @@ -1784,7 +1816,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { } Tup(tys) => tys.iter().any(is_suggestable_infer_ty), Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), - OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), + OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), Path(hir::QPath::TypeRelative(ty, segment)) => { is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args) } @@ -1805,6 +1837,7 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir None } +#[instrument(level = "debug", skip(tcx))] fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { use rustc_hir::Node::*; use rustc_hir::*; @@ -2035,8 +2068,8 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( /// Returns a list of type predicates for the definition with ID `def_id`, including inferred /// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus /// inferred constraints concerning which regions outlive other regions. +#[instrument(level = "debug", skip(tcx))] fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - debug!("predicates_defined_on({:?})", def_id); let mut result = tcx.explicit_predicates_of(def_id); debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,); let inferred_outlives = tcx.inferred_outlives_of(def_id); @@ -2102,11 +2135,10 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. +#[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - debug!("explicit_predicates_of(def_id={:?})", def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -2221,6 +2253,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP + has_own_self as u32 + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32; + trace!(?predicates); + trace!(?ast_generics); + // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). for param in ast_generics.params { @@ -2241,7 +2276,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP Some((param.hir_id, ast_generics.predicates)), param.span, ); + trace!(?bounds); predicates.extend(bounds.predicates(tcx, param_ty)); + trace!(?predicates); } GenericParamKind::Const { .. } => { // Bounds on const parameters are currently not possible. @@ -2250,6 +2287,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } } + trace!(?predicates); // Add in the bounds that appear in the where-clause. for predicate in ast_generics.predicates { match predicate { @@ -2335,12 +2373,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP ); } - let result = ty::GenericPredicates { + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), - }; - debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result); - result + } } fn const_evaluatable_predicates_of<'tcx>( @@ -2357,10 +2393,10 @@ fn const_evaluatable_predicates_of<'tcx>( let def_id = self.tcx.hir().local_def_id(c.hir_id); let ct = ty::Const::from_anon_const(self.tcx, def_id); if let ty::ConstKind::Unevaluated(uv) = ct.kind() { - assert_eq!(uv.promoted, None); + assert_eq!(uv.promoted, ()); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) .to_predicate(self.tcx), span, )); @@ -2816,12 +2852,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } Some(_) => { - tcx.sess - .struct_span_err( - attr.span, - "expected `used`, `used(compiler)` or `used(linker)`", - ) - .emit(); + tcx.sess.emit_err(errors::ExpectedUsedSymbol { span: attr.span }); } None => { // Unfortunately, unconditionally using `llvm.used` causes @@ -3278,6 +3309,15 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { use rustc_ast::{Lit, LitIntType, LitKind}; + if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" { + feature_err( + &tcx.sess.parse_sess, + sym::raw_dylib, + attr.span, + "`#[link_ordinal]` is unstable on x86", + ) + .emit(); + } let meta_item_list = attr.meta_item_list(); let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref); let sole_meta_list = match meta_item_list { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 0d2b75d33..0d34a8bfe 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -53,20 +53,28 @@ fn associated_type_bounds<'tcx>( /// impl trait it isn't possible to write a suitable predicate on the /// containing function and for type-alias impl trait we don't have a backwards /// compatibility issue. +#[instrument(level = "trace", skip(tcx), ret)] fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: DefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, + in_trait: bool, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { ty::print::with_no_queries!({ - let item_ty = - tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); + let substs = InternalSubsts::identity_for_item(tcx, opaque_def_id); + let item_ty = if in_trait { + tcx.mk_projection(opaque_def_id, substs) + } else { + tcx.mk_opaque(opaque_def_id, substs) + }; let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); // Opaque types are implicitly sized unless a `?Sized` bound is found >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); + debug!(?bounds); + tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty)) }) } @@ -83,10 +91,10 @@ pub(super) fn explicit_item_bounds( .. }) => associated_type_bounds(tcx, def_id, bounds, *span), hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }), + kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }), span, .. - }) => opaque_type_bounds(tcx, def_id, bounds, *span), + }) => opaque_type_bounds(tcx, def_id, bounds, *span, *in_trait), _ => bug!("item_bounds called on {:?}", def_id), } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 534ddfa95..a1d1f125f 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,6 +1,5 @@ use rustc_errors::{Applicability, StashKey}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; @@ -19,7 +18,6 @@ use crate::errors::UnconstrainedOpaqueType; /// Computes the relevant generic parameter for a potential generic const argument. /// /// This should be called using the query `tcx.opt_const_param_of`. -#[instrument(level = "debug", skip(tcx))] pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { use hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); @@ -67,8 +65,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let ty = item_ctxt.ast_ty_to_ty(hir_ty); // Iterate through the generics of the projection to find the one that corresponds to - // the def_id that this query was called with. We filter to only const args here as a - // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't + // the def_id that this query was called with. We filter to only type and const args here + // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't // but it can't hurt to be safe ^^ if let ty::Projection(projection) = ty.kind() { let generics = tcx.generics_of(projection.item_def_id); @@ -79,7 +77,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) + .position(|arg| arg.hir_id() == hir_id) }) .unwrap_or_else(|| { bug!("no arg matching AnonConst in segment"); @@ -112,7 +110,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) + .position(|arg| arg.hir_id() == hir_id) }) .unwrap_or_else(|| { bug!("no arg matching AnonConst in segment"); @@ -166,7 +164,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) + .position(|arg| arg.hir_id() == hir_id) .map(|index| (index, seg)).or_else(|| args.bindings .iter() .filter_map(TypeBinding::opt_const) @@ -180,15 +178,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< return None; }; - // Try to use the segment resolution if it is valid, otherwise we - // default to the path resolution. - let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); - let generics = match tcx.res_generics_def_id(res) { + let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { tcx.sess.delay_span_bug( tcx.def_span(def_id), - &format!("unexpected anon const res {:?} in path: {:?}", res, path), + &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); return None; } @@ -229,7 +224,7 @@ fn get_path_containing_arg_in_pat<'hir>( .iter() .filter_map(|seg| seg.args) .flat_map(|args| args.args) - .any(|arg| arg.id() == arg_id) + .any(|arg| arg.hir_id() == arg_id) }; let mut arg_path = None; pat.walk(|pat| match pat.kind { @@ -338,8 +333,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { find_opaque_ty_constraints_for_tait(tcx, def_id) } // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => { - find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + ItemKind::OpaqueTy(OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), + in_trait, + .. + }) => { + if in_trait { + span_bug!(item.span, "impl-trait in trait has no default") + } else { + find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + } } ItemKind::Trait(..) | ItemKind::TraitAlias(..) @@ -379,7 +383,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure{..}, .. }) => tcx.typeck(def_id).node_type(hir_id), + Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => { + tcx.typeck(def_id).node_type(hir_id) + } Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { // We defer to `type_of` of the corresponding parameter @@ -411,40 +417,91 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, + | hir::InlineAsmOperand::SymFn { anon_const } => { + anon_const.hir_id == hir_id + } _ => false, }) => { tcx.typeck(def_id).node_type(hir_id) } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx - .adt_def(tcx.hir().get_parent_item(hir_id)) - .repr() - .discr_type() - .to_ty(tcx), + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) + } + + Node::TypeBinding( + binding @ &TypeBinding { + hir_id: binding_id, + kind: TypeBindingKind::Equality { term: Term::Const(ref e) }, + .. + }, + ) if let Node::TraitRef(trait_ref) = + tcx.hir().get(tcx.hir().get_parent_node(binding_id)) + && e.hir_id == hir_id => + { + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); + }; + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, + binding.ident, + ty::AssocKind::Const, + def_id.to_def_id(), + ); + if let Some(assoc_item) = assoc_item { + tcx.type_of(assoc_item.def_id) + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message( + DUMMY_SP, + "Could not find associated const on trait", + ) + } + } - Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) - if let Node::TraitRef(trait_ref) = tcx.hir().get( - tcx.hir().get_parent_node(binding_id) - ) => + Node::TypeBinding( + binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. }, + ) if let Node::TraitRef(trait_ref) = + tcx.hir().get(tcx.hir().get_parent_node(binding_id)) + && let Some((idx, _)) = + gen_args.args.iter().enumerate().find(|(_, arg)| { + if let GenericArg::Const(ct) = arg { + ct.value.hir_id == hir_id + } else { + false + } + }) => { - let Some(trait_def_id) = trait_ref.trait_def_id() else { - return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); - }; - let assoc_items = tcx.associated_items(trait_def_id); - let assoc_item = assoc_items.find_by_name_and_kind( - tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), - ); - if let Some(assoc_item) = assoc_item { - tcx.type_of(assoc_item.def_id) - } else { - // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message( - DUMMY_SP, - "Could not find associated const on trait", - ) - } + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); + }; + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, + binding.ident, + match kind { + // I think `` type bindings requires that `A` is a type + TypeBindingKind::Constraint { .. } + | TypeBindingKind::Equality { term: Term::Ty(..) } => { + ty::AssocKind::Type + } + TypeBindingKind::Equality { term: Term::Const(..) } => { + ty::AssocKind::Const + } + }, + def_id.to_def_id(), + ); + if let Some(assoc_item) = assoc_item { + tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id) + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message( + DUMMY_SP, + "Could not find associated const on trait", + ) + } } Node::GenericParam(&GenericParam { @@ -453,8 +510,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .. }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)), - x => - tcx.ty_error_with_message( + x => tcx.ty_error_with_message( DUMMY_SP, &format!("unexpected const parent in type_of(): {x:?}"), ), @@ -801,6 +857,9 @@ fn infer_placeholder_type<'a>( match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { Some(mut err) => { if !ty.references_error() { + // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic) + let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" }; + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`. @@ -816,7 +875,7 @@ fn infer_placeholder_type<'a>( err.span_suggestion( span, &format!("provide a type for the {item}", item = kind), - format!("{}: {}", item_ident, sugg_ty), + format!("{colon} {sugg_ty}"), Applicability::MachineApplicable, ); } else { diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 0438ac02e..0d2e66745 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,12 +1,12 @@ //! Errors emitted by typeck. -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed}; -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; -use rustc_session::{parse::ParseSess, SessionDiagnostic}; +use rustc_session::SessionDiagnostic; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] -#[error(typeck::field_multiply_specified_in_initializer, code = "E0062")] +#[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")] pub struct FieldMultiplySpecifiedInInitializer { #[primary_span] #[label] @@ -17,7 +17,7 @@ pub struct FieldMultiplySpecifiedInInitializer { } #[derive(SessionDiagnostic)] -#[error(typeck::unrecognized_atomic_operation, code = "E0092")] +#[diag(typeck::unrecognized_atomic_operation, code = "E0092")] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -26,7 +26,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(SessionDiagnostic)] -#[error(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] +#[diag(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -37,7 +37,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(SessionDiagnostic)] -#[error(typeck::unrecognized_intrinsic_function, code = "E0093")] +#[diag(typeck::unrecognized_intrinsic_function, code = "E0093")] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -46,7 +46,7 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] +#[diag(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] @@ -58,7 +58,7 @@ pub struct LifetimesOrBoundsMismatchOnTrait { } #[derive(SessionDiagnostic)] -#[error(typeck::drop_impl_on_wrong_item, code = "E0120")] +#[diag(typeck::drop_impl_on_wrong_item, code = "E0120")] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -66,7 +66,7 @@ pub struct DropImplOnWrongItem { } #[derive(SessionDiagnostic)] -#[error(typeck::field_already_declared, code = "E0124")] +#[diag(typeck::field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] @@ -77,7 +77,7 @@ pub struct FieldAlreadyDeclared { } #[derive(SessionDiagnostic)] -#[error(typeck::copy_impl_on_type_with_dtor, code = "E0184")] +#[diag(typeck::copy_impl_on_type_with_dtor, code = "E0184")] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -85,14 +85,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(SessionDiagnostic)] -#[error(typeck::multiple_relaxed_default_bounds, code = "E0203")] +#[diag(typeck::multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::copy_impl_on_non_adt, code = "E0206")] +#[diag(typeck::copy_impl_on_non_adt, code = "E0206")] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -100,7 +100,7 @@ pub struct CopyImplOnNonAdt { } #[derive(SessionDiagnostic)] -#[error(typeck::trait_object_declared_with_no_traits, code = "E0224")] +#[diag(typeck::trait_object_declared_with_no_traits, code = "E0224")] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, @@ -109,14 +109,14 @@ pub struct TraitObjectDeclaredWithNoTraits { } #[derive(SessionDiagnostic)] -#[error(typeck::ambiguous_lifetime_bound, code = "E0227")] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0227")] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::assoc_type_binding_not_allowed, code = "E0229")] +#[diag(typeck::assoc_type_binding_not_allowed, code = "E0229")] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -124,14 +124,14 @@ pub struct AssocTypeBindingNotAllowed { } #[derive(SessionDiagnostic)] -#[error(typeck::functional_record_update_on_non_struct, code = "E0436")] +#[diag(typeck::functional_record_update_on_non_struct, code = "E0436")] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::typeof_reserved_keyword_used, code = "E0516")] +#[diag(typeck::typeof_reserved_keyword_used, code = "E0516")] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -142,7 +142,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(SessionDiagnostic)] -#[error(typeck::return_stmt_outside_of_fn_body, code = "E0572")] +#[diag(typeck::return_stmt_outside_of_fn_body, code = "E0572")] pub struct ReturnStmtOutsideOfFnBody { #[primary_span] pub span: Span, @@ -153,14 +153,14 @@ pub struct ReturnStmtOutsideOfFnBody { } #[derive(SessionDiagnostic)] -#[error(typeck::yield_expr_outside_of_generator, code = "E0627")] +#[diag(typeck::yield_expr_outside_of_generator, code = "E0627")] pub struct YieldExprOutsideOfGenerator { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::struct_expr_non_exhaustive, code = "E0639")] +#[diag(typeck::struct_expr_non_exhaustive, code = "E0639")] pub struct StructExprNonExhaustive { #[primary_span] pub span: Span, @@ -168,14 +168,14 @@ pub struct StructExprNonExhaustive { } #[derive(SessionDiagnostic)] -#[error(typeck::method_call_on_unknown_type, code = "E0699")] +#[diag(typeck::method_call_on_unknown_type, code = "E0699")] pub struct MethodCallOnUnknownType { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::value_of_associated_struct_already_specified, code = "E0719")] +#[diag(typeck::value_of_associated_struct_already_specified, code = "E0719")] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] @@ -187,7 +187,7 @@ pub struct ValueOfAssociatedStructAlreadySpecified { } #[derive(SessionDiagnostic)] -#[error(typeck::address_of_temporary_taken, code = "E0745")] +#[diag(typeck::address_of_temporary_taken, code = "E0745")] pub struct AddressOfTemporaryTaken { #[primary_span] #[label] @@ -195,7 +195,7 @@ pub struct AddressOfTemporaryTaken { } #[derive(SessionSubdiagnostic)] -pub enum AddReturnTypeSuggestion<'tcx> { +pub enum AddReturnTypeSuggestion { #[suggestion( typeck::add_return_type_add, code = "-> {found} ", @@ -204,7 +204,7 @@ pub enum AddReturnTypeSuggestion<'tcx> { Add { #[primary_span] span: Span, - found: Ty<'tcx>, + found: String, }, #[suggestion( typeck::add_return_type_missing_here, @@ -233,7 +233,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { } #[derive(SessionDiagnostic)] -#[error(typeck::unconstrained_opaque_type)] +#[diag(typeck::unconstrained_opaque_type)] #[note] pub struct UnconstrainedOpaqueType { #[primary_span] @@ -244,14 +244,15 @@ pub struct UnconstrainedOpaqueType { pub struct MissingTypeParams { pub span: Span, pub def_span: Span, + pub span_snippet: Option, pub missing_type_params: Vec, pub empty_generic_args: bool, } // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. impl<'a> SessionDiagnostic<'a> for MissingTypeParams { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = sess.span_diagnostic.struct_span_err_with_code( + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut err = handler.struct_span_err_with_code( self.span, rustc_errors::fluent::typeck::missing_type_params, error_code!(E0393), @@ -269,12 +270,9 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; - if let (Ok(snippet), true) = ( - sess.source_map().span_to_snippet(self.span), - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. - self.empty_generic_args, - ) { + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + if let Some(snippet) = self.span_snippet && self.empty_generic_args { if snippet.ends_with('>') { // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // we would have to preserve the right order. For now, as clearly the user is @@ -309,7 +307,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { } #[derive(SessionDiagnostic)] -#[error(typeck::manual_implementation, code = "E0183")] +#[diag(typeck::manual_implementation, code = "E0183")] #[help] pub struct ManualImplementation { #[primary_span] @@ -319,8 +317,31 @@ pub struct ManualImplementation { } #[derive(SessionDiagnostic)] -#[error(typeck::substs_on_overridden_impl)] +#[diag(typeck::substs_on_overridden_impl)] pub struct SubstsOnOverriddenImpl { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(typeck::unused_extern_crate)] +pub struct UnusedExternCrate { + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(typeck::extern_crate_not_idiomatic)] +pub struct ExternCrateNotIdiomatic { + #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")] + pub span: Span, + pub msg_code: String, + pub suggestion_code: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::expected_used_symbol)] +pub struct ExpectedUsedSymbol { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 74a5b6e42..f483342b4 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -233,8 +233,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(args); } - hir::ExprKind::MethodCall(.., args, _) => { + hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) + self.consume_expr(receiver); self.consume_exprs(args); } @@ -497,7 +498,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); if let Some(els) = els { - // borrowing because we need to test the descriminant + // borrowing because we need to test the discriminant self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter()); self.walk_block(els) } diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index 55c7a15f9..7b080dc29 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -3,11 +3,10 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ForeignItem, ForeignItemKind, HirId}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; -use rustc_trait_selection::traits::{self, TraitEngineExt}; +use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { *providers = Providers { diagnostic_hir_wf_check, ..*providers }; @@ -66,7 +65,6 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { self.tcx.infer_ctxt().enter(|infcx| { - let mut fulfill = >::new(self.tcx); let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( @@ -74,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.hir_id, traits::ObligationCauseCode::WellFormed(None), ); - fulfill.register_predicate_obligation( + let errors = traits::fully_solve_obligation( &infcx, traits::Obligation::new( cause, @@ -83,8 +81,6 @@ fn diagnostic_hir_wf_check<'tcx>( .to_predicate(self.tcx), ), ); - - let errors = fulfill.select_all_or_error(&infcx); if !errors.is_empty() { debug!("Wf-check got errors for {:?}: {:?}", ty, errors); for error in errors { @@ -144,6 +140,10 @@ fn diagnostic_hir_wf_check<'tcx>( hir::Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Static(ty, _), .. }) => Some(*ty), + hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Type { default: Some(ty), .. }, + .. + }) => Some(*ty), ref node => bug!("Unexpected node {:?}", node), }, WellFormedLoc::Param { function: _, param_idx } => { diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 74abb71a1..2741d9f77 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -65,27 +65,25 @@ //! cause use after frees with purely safe code in the same way as specializing //! on traits with methods can. -use crate::check::regionck::OutlivesEnvironmentExt; -use crate::check::wfcheck::impl_implied_bounds; use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::Span; -use rustc_trait_selection::traits::{self, translate_substs, wf}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { - tcx.infer_ctxt().enter(|infcx| { - check_always_applicable(&infcx, impl_def_id, node); - }); + check_always_applicable(tcx, impl_def_id, node); } } @@ -105,16 +103,14 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti } /// Check that `impl1` is a sound specialization -fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId, impl2_node: Node) { - if let Some((impl1_substs, impl2_substs)) = get_impl_substs(infcx, impl1_def_id, impl2_node) { +fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { + if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!( "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)", impl1_def_id, impl2_def_id, impl2_substs ); - let tcx = infcx.tcx; - let parent_substs = if impl2_node.is_from_trait() { impl2_substs.to_vec() } else { @@ -124,7 +120,7 @@ fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId, let span = tcx.def_span(impl1_def_id); check_static_lifetimes(tcx, &parent_substs, span); check_duplicate_params(tcx, impl1_substs, &parent_substs, span); - check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span); + check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span); } } @@ -139,32 +135,38 @@ fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId, /// /// Would return `S1 = [C]` and `S2 = [Vec, C]`. fn get_impl_substs<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + tcx: TyCtxt<'tcx>, impl1_def_id: LocalDefId, impl2_node: Node, ) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> { - let tcx = infcx.tcx; - let param_env = tcx.param_env(impl1_def_id); + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); + let param_env = tcx.param_env(impl1_def_id); + let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); - let impl2_substs = - translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + let assumed_wf_types = + ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); - let mut outlives_env = OutlivesEnvironment::new(param_env); - let implied_bounds = - impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id)); - outlives_env.add_implied_bounds( - infcx, - implied_bounds, - tcx.hir().local_def_id_to_hir_id(impl1_def_id), - ); - infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); - let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { - let span = tcx.def_span(impl1_def_id); - tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); - return None; - }; - Some((impl1_substs, impl2_substs)) + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl2_substs = + translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + ocx.infcx.report_fulfillment_errors(&errors, None, false); + return None; + } + + let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); + let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { + let span = tcx.def_span(impl1_def_id); + tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); + return None; + }; + Some((impl1_substs, impl2_substs)) + }) } /// Returns a list of all of the unconstrained subst of the given impl. @@ -279,14 +281,13 @@ fn check_static_lifetimes<'tcx>( /// * a well-formed predicate of a type argument of the trait being implemented, /// including the `Self`-type. fn check_predicates<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + tcx: TyCtxt<'tcx>, impl1_def_id: LocalDefId, impl1_substs: SubstsRef<'tcx>, impl2_node: Node, impl2_substs: SubstsRef<'tcx>, span: Span, ) { - let tcx = infcx.tcx; let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span( tcx, @@ -343,19 +344,23 @@ fn check_predicates<'tcx>( // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { - if let Some(obligations) = wf::obligations( - infcx, - tcx.param_env(impl1_def_id), - tcx.hir().local_def_id_to_hir_id(impl1_def_id), - 0, - arg, - span, - ) { + tcx.infer_ctxt().enter(|ref infcx| { + let obligations = wf::obligations( + infcx, + tcx.param_env(impl1_def_id), + tcx.hir().local_def_id_to_hir_id(impl1_def_id), + 0, + arg, + span, + ) + .unwrap(); + + assert!(!obligations.needs_infer()); impl2_predicates.extend( traits::elaborate_obligations(tcx, obligations) .map(|obligation| obligation.predicate), ) - } + }) } impl2_predicates.extend( traits::elaborate_predicates_with_span(tcx, always_applicable_traits) diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index f98ae46c5..b1ce972e1 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -64,15 +64,16 @@ This API is completely unstable and subject to change. #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(iter_intersperse)] -#![feature(label_break_value)] +#![cfg_attr(bootstrap, feature(label_break_value))] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(once_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] #![feature(is_some_with)] +#![feature(type_alias_impl_trait)] #![recursion_limit = "256"] #[macro_use] @@ -104,7 +105,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::middle; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -112,11 +112,8 @@ use rustc_middle::util; use rustc_session::config::EntryFnType; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, -}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::iter; @@ -148,18 +145,15 @@ fn require_same_types<'tcx>( ) -> bool { tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); - let mut fulfill_cx = >::new(infcx.tcx); - match infcx.at(cause, param_env).eq(expected, actual) { - Ok(InferOk { obligations, .. }) => { - fulfill_cx.register_predicate_obligations(infcx, obligations); - } + let errors = match infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), Err(err) => { infcx.report_mismatched_types(cause, expected, actual, err).emit(); return false; } - } + }; - match fulfill_cx.select_all_or_error(infcx).as_slice() { + match &errors[..] { [] => true, errors => { infcx.report_fulfillment_errors(errors, None, false); @@ -303,7 +297,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let expected_return_type; - if let Some(term_id) = tcx.lang_items().termination() { + if let Some(term_did) = tcx.lang_items().termination() { let return_ty = main_fnsig.output(); let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); if !return_ty.bound_vars().is_empty() { @@ -314,33 +308,17 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let return_ty = return_ty.skip_binder(); tcx.infer_ctxt().enter(|infcx| { + // Main should have no WC, so empty param env is OK here. + let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_hir_id, ObligationCauseCode::MainFunctionType, ); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - // normalize any potential projections in the return type, then add - // any possible obligations to the fulfillment context. - // HACK(ThePuzzlemaker) this feels symptomatic of a problem within - // checking trait fulfillment, not this here. I'm not sure why it - // works in the example in `fn test()` given in #88609? This also - // probably isn't the best way to do this. - let InferOk { value: norm_return_ty, obligations } = infcx - .partially_normalize_associated_types_in( - cause.clone(), - ty::ParamEnv::empty(), - return_ty, - ); - fulfillment_cx.register_predicate_obligations(&infcx, obligations); - fulfillment_cx.register_bound( - &infcx, - ty::ParamEnv::empty(), - norm_return_ty, - term_id, - cause, - ); - let errors = fulfillment_cx.select_all_or_error(&infcx); + let ocx = traits::ObligationCtxt::new(&infcx); + let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty); + ocx.register_bound(cause, param_env, norm_return_ty, term_did); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); error = true; @@ -466,7 +444,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { fn check_for_entry_fn(tcx: TyCtxt<'_>) { match tcx.entry_fn(()) { - Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id), + Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id), Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id), _ => {} } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 8fa65d51e..e50c26765 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -9,7 +9,6 @@ use rustc_span::Span; mod explicit; mod implicit_infer; -pub(crate) mod outlives_bounds; /// Code to write unit test for outlives. pub mod test; mod utils; diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs deleted file mode 100644 index 229a64650..000000000 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ /dev/null @@ -1,90 +0,0 @@ -use rustc_hir as hir; -use rustc_middle::ty::{self, Ty}; -use rustc_trait_selection::infer::InferCtxt; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::query::NoSolution; -use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; - -pub use rustc_middle::traits::query::OutlivesBound; - -pub trait InferCtxtExt<'tcx> { - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - ) -> Vec>; -} - -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// ``` - /// fn foo<'a,T>(x: &'a T) {} - /// ``` - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - #[instrument(level = "debug", skip(self, param_env, body_id))] - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - ) -> Vec> { - let span = self.tcx.hir().span(body_id); - let result = param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self); - let result = match result { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } - }; - - let TypeOpOutput { output, constraints, .. } = result; - - if let Some(constraints) = constraints { - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = >::new(self.tcx); - let cause = ObligationCause::misc(span, body_id); - for &constraint in &constraints.outlives { - let obligation = self.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - ); - fulfill_cx.register_predicate_obligation(self, obligation); - } - if !constraints.member_constraints.is_empty() { - span_bug!(span, "{:#?}", constraints.member_constraints); - } - let errors = fulfill_cx.select_all_or_error(self); - if !errors.is_empty() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - }; - - output - } -} diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs index b718ca942..3e8d023fb 100644 --- a/compiler/rustc_typeck/src/outlives/utils.rs +++ b/compiler/rustc_typeck/src/outlives/utils.rs @@ -161,12 +161,6 @@ fn is_free_region(region: Region<'_>) -> bool { // ignore it. We can't put it on the struct header anyway. ty::ReLateBound(..) => false, - // This can appear in `where Self: ` bounds (#64855): - // - // struct Bar(::Type) where Self: ; - // struct Baz<'a>(&'a Self) where Self: ; - ty::ReEmpty(_) => false, - // These regions don't appear in types from type declarations: ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => { bug!("unexpected region in outlives inference: {:?}", region); diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 99729391e..435912464 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -4,7 +4,6 @@ use rustc_errors::{ MultiSpan, }; use rustc_hir as hir; -use rustc_middle::hir::map::fn_sig; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_session::Session; use rustc_span::def_id::DefId; @@ -292,62 +291,60 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // Creates lifetime name suggestions from the lifetime parameter names fn get_lifetime_args_suggestions_from_param_names( &self, - path_hir_id: Option, + path_hir_id: hir::HirId, num_params_to_take: usize, ) -> String { debug!(?path_hir_id); - if let Some(path_hir_id) = path_hir_id { - let mut ret = Vec::new(); - for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { - debug!(?id); - let params = if let Some(generics) = node.generics() { - generics.params - } else if let hir::Node::Ty(ty) = node - && let hir::TyKind::BareFn(bare_fn) = ty.kind - { - bare_fn.generic_params - } else { - &[] - }; - ret.extend(params.iter().filter_map(|p| { - let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } - = p.kind - else { return None }; - let hir::ParamName::Plain(name) = p.name else { return None }; - Some(name.to_string()) - })); - // Suggest `'static` when in const/static item-like. - if let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. }, - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const { .. }, - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Const { .. }, - .. - }) - | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Static { .. }, - .. - }) - | hir::Node::AnonConst(..) = node - { - ret.extend( - std::iter::repeat("'static".to_owned()) - .take(num_params_to_take.saturating_sub(ret.len())), - ); - } - if ret.len() >= num_params_to_take { - return ret[..num_params_to_take].join(", "); - } - // We cannot refer to lifetimes defined in an outer function. - if let hir::Node::Item(_) = node { - break; - } + let mut ret = Vec::new(); + for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { + debug!(?id); + let params = if let Some(generics) = node.generics() { + generics.params + } else if let hir::Node::Ty(ty) = node + && let hir::TyKind::BareFn(bare_fn) = ty.kind + { + bare_fn.generic_params + } else { + &[] + }; + ret.extend(params.iter().filter_map(|p| { + let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } + = p.kind + else { return None }; + let hir::ParamName::Plain(name) = p.name else { return None }; + Some(name.to_string()) + })); + // Suggest `'static` when in const/static item-like. + if let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. }, + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const { .. }, + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Const { .. }, + .. + }) + | hir::Node::ForeignItem(hir::ForeignItem { + kind: hir::ForeignItemKind::Static { .. }, + .. + }) + | hir::Node::AnonConst(..) = node + { + ret.extend( + std::iter::repeat("'static".to_owned()) + .take(num_params_to_take.saturating_sub(ret.len())), + ); + } + if ret.len() >= num_params_to_take { + return ret[..num_params_to_take].join(", "); + } + // We cannot refer to lifetimes defined in an outer function. + if let hir::Node::Item(_) = node { + break; } } @@ -368,7 +365,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { &self, num_params_to_take: usize, ) -> String { - let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig); + let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig); let is_used_in_input = |def_id| { fn_sig.map_or(false, |fn_sig| { fn_sig.decl.inputs.iter().any(|ty| match ty.kind { @@ -524,6 +521,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if self.not_enough_args_provided() { self.suggest_adding_args(err); } else if self.too_many_args_provided() { + self.suggest_moving_args_from_assoc_fn_to_trait(err); self.suggest_removing_args_or_generics(err); } else { unreachable!(); @@ -654,6 +652,144 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } + /// Suggests moving redundant argument(s) of an associate function to the + /// trait it belongs to. + /// + /// ```compile_fail + /// Into::into::>(42) // suggests considering `Into::>::into(42)` + /// ``` + fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) { + let trait_ = match self.tcx.trait_of_item(self.def_id) { + Some(def_id) => def_id, + None => return, + }; + + // Skip suggestion when the associated function is itself generic, it is unclear + // how to split the provided parameters between those to suggest to the trait and + // those to remain on the associated type. + let num_assoc_fn_expected_args = + self.num_expected_type_or_const_args() + self.num_expected_lifetime_args(); + if num_assoc_fn_expected_args > 0 { + return; + } + + let num_assoc_fn_excess_args = + self.num_excess_type_or_const_args() + self.num_excess_lifetime_args(); + + let trait_generics = self.tcx.generics_of(trait_); + let num_trait_generics_except_self = + trait_generics.count() - if trait_generics.has_self { 1 } else { 0 }; + + let msg = format!( + "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}", + these = pluralize!("this", num_assoc_fn_excess_args), + s = pluralize!(num_assoc_fn_excess_args), + name = self.tcx.item_name(trait_), + num = num_trait_generics_except_self, + ); + + if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id) + && let Some(parent_node) = self.tcx.hir().find(parent_node) + && let hir::Node::Expr(expr) = parent_node { + match expr.kind { + hir::ExprKind::Path(ref qpath) => { + self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + err, + qpath, + msg, + num_assoc_fn_excess_args, + num_trait_generics_except_self + ) + }, + hir::ExprKind::MethodCall(..) => { + self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + err, + trait_, + expr, + msg, + num_assoc_fn_excess_args, + num_trait_generics_except_self + ) + }, + _ => return, + } + } + } + + fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + &self, + err: &mut Diagnostic, + qpath: &'tcx hir::QPath<'tcx>, + msg: String, + num_assoc_fn_excess_args: usize, + num_trait_generics_except_self: usize, + ) { + if let hir::QPath::Resolved(_, path) = qpath + && let Some(trait_path_segment) = path.segments.get(0) { + let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params(); + + if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait { + if let Some(span) = self.gen_args.span_ext() + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let sugg = vec![ + (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)), + (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()) + ]; + + err.multipart_suggestion( + msg, + sugg, + Applicability::MaybeIncorrect + ); + } + } + } + } + + fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + &self, + err: &mut Diagnostic, + trait_def_id: DefId, + expr: &'tcx hir::Expr<'tcx>, + msg: String, + num_assoc_fn_excess_args: usize, + num_trait_generics_except_self: usize, + ) { + let sm = self.tcx.sess.source_map(); + let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; }; + if num_assoc_fn_excess_args != num_trait_generics_except_self { + return; + } + let Some(gen_args) = self.gen_args.span_ext() else { return; }; + let Ok(generics) = sm.span_to_snippet(gen_args) else { return; }; + let Ok(rcvr) = sm.span_to_snippet( + rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span) + ) else { return; }; + let Ok(rest) = + (match args { + [] => Ok(String::new()), + [arg] => sm.span_to_snippet( + arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span), + ), + [first, .., last] => { + let first_span = + first.span.find_ancestor_inside(expr.span).unwrap_or(first.span); + let last_span = + last.span.find_ancestor_inside(expr.span).unwrap_or(last.span); + sm.span_to_snippet(first_span.to(last_span)) + } + }) else { return; }; + let comma = if args.len() > 0 { ", " } else { "" }; + let trait_path = self.tcx.def_path_str(trait_def_id); + let method_name = self.tcx.item_name(self.def_id); + err.span_suggestion( + expr.span, + msg, + format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"), + Applicability::MaybeIncorrect, + ); + } + /// Suggests to remove redundant argument(s): /// /// ```text @@ -763,16 +899,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // If there is a single unbound associated type and a single excess generic param // suggest replacing the generic param with the associated type bound if provided_args_matches_unbound_traits && !unbound_types.is_empty() { - let mut suggestions = vec![]; let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - for (potential, name) in iter::zip(unused_generics, &unbound_types) { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) { - suggestions.push((potential.span(), format!("{} = {}", name, snippet))); - } - } + let suggestions = iter::zip(unused_generics, &unbound_types) + .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = "))) + .collect::>(); if !suggestions.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_verbose( &format!( "replace the generic bound{s} with the associated type{s}", s = pluralize!(unbound_types.len()) diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index d79450e1a..eaf0310d5 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -257,7 +257,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_invariant_substs(current, substs, variance); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(current, r, contra); @@ -271,11 +271,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } for projection in data.projection_bounds() { - match projection.skip_binder().term { - ty::Term::Ty(ty) => { + match projection.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => { self.add_constraints_from_ty(current, ty, self.invariant); } - ty::Term::Const(c) => { + ty::TermKind::Const(c) => { self.add_constraints_from_const(current, c, self.invariant) } } @@ -411,11 +411,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // way early-bound regions do, so we skip them here. } - ty::ReFree(..) - | ty::ReVar(..) - | ty::RePlaceholder(..) - | ty::ReEmpty(_) - | ty::ReErased => { + ty::ReFree(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. bug!( diff --git a/config.toml.example b/config.toml.example index b3284050f..a967d881b 100644 --- a/config.toml.example +++ b/config.toml.example @@ -666,6 +666,10 @@ changelog-seen = 2 # target. #llvm-config = (path) +# Override detection of whether this is a Rust-patched LLVM. This would be used +# in conjunction with either an llvm-config or build.submodules = false. +#llvm-has-rust-patches = if llvm-config { false } else { true } + # Normally the build system can find LLVM's FileCheck utility, but if # not, you can specify an explicit file name for it. #llvm-filecheck = "/path/to/llvm-version/bin/FileCheck" @@ -721,6 +725,10 @@ changelog-seen = 2 # probably don't want to use this. #qemu-rootfs = (path) +# Skip building the `std` library for this target. Enabled by default for +# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`. +#no-std = (bool) + # ============================================================================= # Distribution options # diff --git a/debian/bin/rust-lld b/debian/bin/rust-lld index 04aec84b4..285f1b0da 100755 --- a/debian/bin/rust-lld +++ b/debian/bin/rust-lld @@ -6,4 +6,4 @@ # However the tests fail for other reasons, namely we can't build rustdoc # (which runs the tests) in wasm32 yet. So this is just WIP at the moment, # it is not expect to work nor to be installed on user machines. -exec /usr/bin/lld-14 "${@/#-Wl,/}" +exec /usr/bin/lld-15 "${@/#-Wl,/}" diff --git a/debian/changelog b/debian/changelog index e4e72ad6d..eaf375290 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,42 @@ +rustc (1.65.0+dfsg1-2) unstable; urgency=medium + + * Team upload + * Source-only upload + + -- Jeremy Bícha Mon, 26 Jun 2023 17:16:27 -0400 + +rustc (1.65.0+dfsg1-1) unstable; urgency=medium + + * Upload to unstable + + -- Fabian Grünbichler Tue, 20 Jun 2023 20:16:50 +0200 + +rustc (1.65.0+dfsg1-1~exp3) experimental; urgency=medium + + * d/rules: fix typo in mipsel workaround + + -- Fabian Grünbichler Sun, 12 Mar 2023 08:54:15 +0100 + +rustc (1.65.0+dfsg1-1~exp2) experimental; urgency=medium + + [ Fabian Grünbichler ] + * d/control: add myself to Uploaders + * cherry-pick fix for failing backtrace test + * bump mipsel test failure allowance to work around broken gdb 13.1 + * drop duplicate lintian override + + -- Fabian Grünbichler Sat, 11 Mar 2023 18:50:19 +0100 + +rustc (1.65.0+dfsg1-1~exp1) experimental; urgency=medium + + [ Fabian Grünbichler ] + * New upstream version 1.65.0+dfsg1 + * switch to LLVM-15 + * cherry-pick fix for compiletest with rpath=false + * add overrides for rust-analyzer test data + + -- Fabian Gruenbichler Wed, 15 Feb 2023 20:12:05 +0100 + rustc (1.64.0+dfsg1-1~progress7.99u1) graograman-backports; urgency=medium * Initial reupload to graograman-backports. diff --git a/debian/control b/debian/control index abaf245fe..f466d8a2d 100644 --- a/debian/control +++ b/debian/control @@ -17,13 +17,13 @@ Build-Depends: dpkg-dev (>= 1.17.14), python3:native, cargo:native (>= 0.60.0) , - rustc:native (>= 1.63.0+dfsg) , - rustc:native (<= 1.64.0++) , - llvm-14-dev:native, - llvm-14-tools:native, + rustc:native (>= 1.64.0+dfsg) , + rustc:native (<= 1.65.0++) , + llvm-15-dev:native, + llvm-15-tools:native, gcc-mingw-w64-x86-64-posix:native [amd64] , gcc-mingw-w64-i686-posix:native [i386] , - libllvm14 (>= 1:14.0.0), + libllvm15 (>= 1:15.0.0), cmake (>= 3.0) | cmake3, # needed by some vendor crates pkg-config, @@ -44,7 +44,7 @@ Build-Depends: Build-Depends-Indep: wasi-libc (>= 0.0~git20220510.9886d3d~~) , wasi-libc (<= 0.0~git20220510.9886d3d++) , - clang-14:native, + clang-15:native, Build-Conflicts: gdb-minimal Standards-Version: 4.2.1 Homepage: http://www.rust-lang.org/ @@ -61,12 +61,12 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, libstd-rust-dev (= ${binary:Version}), gcc, libc-dev, binutils (>= 2.26) Recommends: - cargo (>= 0.65.0~~), cargo (<< 0.66.0~~), + cargo (>= 0.66.0~~), cargo (<< 0.67.0~~), # llvm is needed for llvm-dwp for -C split-debuginfo=packed - llvm-14, + llvm-15, Suggests: # lld and clang are needed for wasm compilation - lld-14, clang-14, + lld-15, clang-15, Replaces: libstd-rust-dev (<< 1.25.0+dfsg1-2~~) Breaks: libstd-rust-dev (<< 1.25.0+dfsg1-2~~) Description: Rust systems programming language @@ -82,7 +82,7 @@ Description: Rust systems programming language generic programming and meta-programming, in both static and dynamic styles. -Package: libstd-rust-1.64 +Package: libstd-rust-1.65 Section: libs Architecture: any Multi-Arch: same @@ -109,7 +109,7 @@ Section: libdevel Architecture: any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends}, - libstd-rust-1.64 (= ${binary:Version}), + libstd-rust-1.65 (= ${binary:Version}), Description: Rust standard libraries - development files Rust is a curly-brace, block-structured expression language. It visually resembles the C language family, but differs significantly @@ -161,7 +161,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends} # Embeds wasi-libc so doesn't need to depend on it # None of its licenses require source redistrib, so no need for Built-Using Recommends: - lld-14, clang-14, + lld-15, clang-15, Suggests: # nodejs contains wasi-node for running the program nodejs (>= 12.16), @@ -207,7 +207,7 @@ Description: Rust debugger (gdb) Package: rust-lldb Architecture: all # When updating, also update rust-lldb.links -Depends: lldb-14, ${misc:Depends}, python3-lldb-14 +Depends: lldb-15, ${misc:Depends}, python3-lldb-15 Replaces: rustc (<< 1.1.0+dfsg1-1) Description: Rust debugger (lldb) Rust is a curly-brace, block-structured expression language. It @@ -272,7 +272,7 @@ Package: rust-clippy Architecture: any Multi-Arch: allowed Depends: ${misc:Depends}, ${shlibs:Depends}, - libstd-rust-1.64 (= ${binary:Version}) + libstd-rust-1.65 (= ${binary:Version}) Recommends: cargo Description: Rust linter Rust is a curly-brace, block-structured expression language. It @@ -327,7 +327,7 @@ Depends: ${misc:Depends}, ${shlibs:Depends}, rust-gdb (>= ${binary:Version}) | rust-lldb (>= ${binary:Version}), cargo, Recommends: - cargo (>= 0.65.0~~), cargo (<< 0.66.0~~) + cargo (>= 0.66.0~~), cargo (<< 0.67.0~~) Suggests: rust-doc (>= ${binary:Version}), rust-src (>= ${binary:Version}), diff --git a/debian/copyright b/debian/copyright index 03380c208..cd920fe5a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -42,17 +42,16 @@ Files-Excluded: # unused dependencies, generated by debian/prune-unused-deps # DO NOT EDIT below, AUTOGENERATED vendor/ahash-0.7.4 - vendor/anyhow-1.0.56 - vendor/anyhow-1.0.58 + vendor/anyhow-1.0.60 + vendor/anyhow-1.0.62 vendor/anymap vendor/arbitrary vendor/ar vendor/arrayvec-0.7.0 - vendor/backtrace-0.3.65 vendor/bitmaps - vendor/byteorder-1.3.4 + vendor/byteorder vendor/bytesize - vendor/cc-1.0.69 + vendor/camino-1.0.9 vendor/chalk-derive vendor/chalk-ir vendor/chalk-recursive @@ -79,16 +78,18 @@ Files-Excluded: vendor/cranelift-module vendor/cranelift-native vendor/cranelift-object + vendor/crossbeam vendor/crossbeam-channel-0.5.4 + vendor/crossbeam-deque-0.8.1 vendor/crossbeam-epoch-0.9.6 vendor/crossbeam-epoch-0.9.8 + vendor/crossbeam-queue vendor/crossbeam-utils-0.8.8 vendor/crypto-common-0.1.2 vendor/crypto-hash vendor/curl vendor/curl-sys vendor/derive_arbitrary - vendor/derive_more vendor/diff-0.1.12 vendor/difference vendor/digest-0.10.2 @@ -109,43 +110,36 @@ Files-Excluded: vendor/fsevent-sys vendor/fs_extra-1.1.0 vendor/fs_extra - vendor/fst-0.4.5 vendor/fst - vendor/futures-0.1.31 vendor/fwdansi vendor/fxhash vendor/generic-array-0.14.4 vendor/getrandom-0.2.0 vendor/getset + vendor/gimli-0.26.1 vendor/git2 vendor/git2-curl vendor/globset-0.4.8 - vendor/hashbrown-0.11.2 - vendor/hashbrown-0.12.1 vendor/heck-0.3.3 vendor/hex-0.3.2 vendor/hex-0.4.2 - vendor/idna-0.1.5 vendor/idna-0.2.0 vendor/im-rc vendor/indenter vendor/inotify vendor/inotify-sys vendor/itertools-0.10.1 + vendor/itoa-1.0.2 vendor/jemalloc-sys vendor/jod-thread - vendor/json - vendor/jsonrpc-client-transports - vendor/jsonrpc-core - vendor/jsonrpc-core-client - vendor/jsonrpc-derive - vendor/jsonrpc-ipc-server - vendor/jsonrpc-pubsub - vendor/jsonrpc-server-utils vendor/kqueue vendor/kqueue-sys vendor/kstring - vendor/lazycell + vendor/libc-0.2.126 + vendor/libc-0.2.127 + vendor/libc-0.2.131 + vendor/libffi + vendor/libffi-sys vendor/libgit2-sys vendor/libloading-0.6.7 vendor/libloading-0.7.1 @@ -155,64 +149,55 @@ Files-Excluded: vendor/libz-sys vendor/linked-hash-map vendor/log-0.4.14 - vendor/lsp-codec - vendor/lsp-types-0.60.0 vendor/lzma-sys-0.1.16 vendor/mach vendor/matches-0.1.8 - vendor/memchr-2.4.1 vendor/mimalloc - vendor/mio-0.7.14 vendor/mio vendor/normalize-line-endings vendor/notify - vendor/ntapi-0.3.6 - vendor/object-0.28.4 - vendor/once_cell-1.10.0 vendor/once_cell-1.12.0 + vendor/once_cell-1.13.0 vendor/oorandom vendor/openssl vendor/openssl-probe vendor/openssl-src vendor/openssl-sys - vendor/ordslice vendor/os_info vendor/owo-colors - vendor/parity-tokio-ipc vendor/paste - vendor/percent-encoding-1.0.1 vendor/pin-project-lite-0.2.8 vendor/pkg-config-0.3.18 - vendor/pretty_assertions vendor/pretty_env_logger vendor/proc-macro2-1.0.37 vendor/proc-macro2-1.0.39 - vendor/proc-macro-crate - vendor/pulldown-cmark-0.9.1 + vendor/protobuf + vendor/protobuf-support vendor/pulldown-cmark-to-cmark vendor/quote-1.0.18 - vendor/rand_xoshiro-0.4.0 vendor/redox_syscall-0.2.10 + vendor/redox_syscall-0.2.13 vendor/regalloc2 + vendor/regex-1.5.6 + vendor/regex-syntax-0.6.26 vendor/region - vendor/rls-vfs vendor/rustc_version + vendor/ryu-1.0.10 vendor/ryu-1.0.5 vendor/salsa vendor/salsa-macros vendor/schannel + vendor/scip vendor/security-framework vendor/security-framework-sys + vendor/semver-1.0.12 vendor/serde-1.0.137 - vendor/serde-1.0.138 vendor/serde_derive-1.0.137 - vendor/serde_derive-1.0.138 vendor/serde_ignored vendor/serde_json-1.0.81 - vendor/serde_repr-0.1.6 + vendor/serde_json-1.0.83 vendor/sha2-0.10.1 vendor/sharded-slab-0.1.1 - vendor/signal-hook-registry vendor/similar vendor/sized-chunks vendor/slice-group-by @@ -226,31 +211,29 @@ Files-Excluded: vendor/syn-1.0.91 vendor/syn-1.0.95 vendor/target-lexicon + vendor/thiserror-1.0.31 + vendor/thiserror-impl-1.0.31 vendor/threadpool vendor/tikv-jemallocator vendor/tikv-jemalloc-ctl vendor/tikv-jemalloc-sys vendor/tinyvec-0.3.4 - vendor/tokio-stream - vendor/tokio-util vendor/toml-0.5.7 vendor/toml_edit - vendor/tower-service - vendor/tracing-0.1.29 - vendor/tracing-attributes-0.1.18 - vendor/tracing-core-0.1.21 + vendor/tracing-0.1.35 + vendor/tracing-core-0.1.28 vendor/tracing-error vendor/tracing-log-0.1.2 vendor/tracing-subscriber-0.3.3 vendor/tracing-tree-0.2.0 vendor/typed-arena vendor/typenum-1.12.0 + vendor/ui_test vendor/unicode-bidi-0.3.4 vendor/unicode-ident-1.0.0 vendor/unicode-normalization-0.1.13 vendor/unicode-width-0.1.8 vendor/unicode-xid-0.2.2 - vendor/url-1.7.2 vendor/utf8parse vendor/vcpkg vendor/vergen @@ -460,7 +443,6 @@ Comment: see https://github.com/notriddle/ammonia Files: vendor/annotate-snippets/* - vendor/annotate-snippets-0.8.0/* Copyright: 2018-2020 Zibi Braniecki License: Apache-2.0 or MIT Comment: see https://github.com/zbraniecki/annotate-snippets-rs @@ -503,15 +485,8 @@ Comment: see https://github.com/rust-lang/backtrace-rs Files: vendor/block-buffer/* - vendor/block-buffer-0*/* - vendor/block-padding/* - vendor/byte-tools/* vendor/digest/* - vendor/digest-0*/* - vendor/fake-simd/* vendor/md-5/* - vendor/opaque-debug/* - vendor/sha-1-0*/* vendor/sha-1/* vendor/sha2/* Copyright: 2016-2020 RustCrypto Developers @@ -533,7 +508,6 @@ License: Apache-2.0 or MIT Comment: see https://github.com/llogiq/bytecount Files: - vendor/byteorder/* vendor/globset/* vendor/ignore/* vendor/same-file/* @@ -543,7 +517,6 @@ Files: Copyright: 2015-2020 Andrew Gallant License: Unlicense or MIT Comment: - see https://github.com/BurntSushi/byteorder see https://github.com/BurntSushi/same-file see https://github.com/BurntSushi/walkdir see https://github.com/BurntSushi/winapi-util @@ -625,11 +598,9 @@ License: MIT OR Apache-2.0 Comment: see https://github.com/srijs/rust-crc32fast Files: - vendor/crossbeam/* vendor/crossbeam-channel/* vendor/crossbeam-deque/* vendor/crossbeam-epoch/* - vendor/crossbeam-queue/* vendor/crossbeam-utils/* Copyright: 2015-2022 The Crossbeam Project Developers License: MIT or Apache-2.0 @@ -791,7 +762,6 @@ Comment: see https://github.com/servo/futf Files: vendor/generic-array/* - vendor/generic-array-0*/* Copyright: 2015-2020 BartÅ‚omiej KamiÅ„ski 2015-2020 Aaron Trent @@ -903,6 +873,12 @@ Copyright: 2018-2021 Changseok Han License: MIT Comment: see https://github.com/freestrings/jsonpath +Files: vendor/lazycell/* +Copyright: 2016-2020 Alex Crichton + 2016-2020 Nikita Pekin +License: MIT or Apache-2.0 +Comment: see https://github.com/indiv0/lazycell + Files: vendor/lazy_static/* Copyright: 2014-2018 Marvin Löbel License: MIT or Apache-2.0 @@ -1117,7 +1093,7 @@ Copyright: 2017-2017 Emilio Cobos Ãlvarez License: MIT Comment: see https://github.com/emilio/precomputed-hash -Files: vendor/pretty_assertions-0.7.2/* +Files: vendor/pretty_assertions/* Copyright: 2017-2022 Colin Kiegel 2017-2022 Florent Fayolle 2017-2022 Tom Milligan @@ -1153,7 +1129,6 @@ Comment: see https://github.com/mcarton/rust-punycode.git Files: vendor/quick-error/* - vendor/quick-error-1*/* Copyright: 2015-2020 Paul Colomiets 2015-2020 Colin Kiegel @@ -1221,11 +1196,6 @@ Copyright: 2020-2020 flip1995 License: MIT OR Apache-2.0 Comment: see https://github.com/flip1995/rustc-semver -Files: vendor/rustc_tools_util/* -Copyright: 2014-2021 Matthias Krüger -License: MIT or Apache-2.0 -Comment: see https://github.com/rust-lang/rust-clippy - Files: vendor/rustfix/* Copyright: 2016-2021 Pascal Hertleif @@ -1371,17 +1341,22 @@ Copyright: 2016-2020 Yuki Okushi License: MIT or Apache-2.0 Comment: see https://github.com/JohnTitor/termize -Files: vendor/textwrap/* -Copyright: 2016-2022 Martin Geisler -License: MIT -Comment: see https://github.com/mgeisler/textwrap - Files: vendor/text-size/* Copyright: 2018-2021 Aleksey Kladov 2018-2021 Christopher Durham (CAD97) License: MIT OR Apache-2.0 Comment: see https://github.com/rust-analyzer/text-size +Files: vendor/textwrap/* +Copyright: 2016-2022 Martin Geisler +License: MIT +Comment: see https://github.com/mgeisler/textwrap + +Files: vendor/thin-vec/* +Copyright: 2017-2022 Aria Beingessner +License: MIT or Apache-2.0 +Comment: see https://github.com/gankra/thin-vec + Files: vendor/thiserror/* vendor/thiserror-impl/* @@ -1619,11 +1594,6 @@ Copyright: 2019-2022 The Cranelift Project Developers License: Apache-2.0 with LLVM exception OR Apache-2.0 OR MIT Comment: see https://github.com/bytecodealliance/wasi -Files: vendor/wasi-0.10.2+wasi-snapshot-preview1/* -Copyright: 2019-2022 The Cranelift Project Developers -License: Apache-2.0 with LLVM exception OR Apache-2.0 OR MIT -Comment: see https://github.com/bytecodealliance/wasi - Files: vendor/windows_aarch64_msvc/* vendor/windows_i686_gnu/* diff --git a/debian/libstd-rust-1.64.install b/debian/libstd-rust-1.64.install deleted file mode 100644 index cd4545cca..000000000 --- a/debian/libstd-rust-1.64.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/${DEB_HOST_MULTIARCH}/ diff --git a/debian/libstd-rust-1.64.lintian-overrides b/debian/libstd-rust-1.64.lintian-overrides deleted file mode 100644 index 1a992afe2..000000000 --- a/debian/libstd-rust-1.64.lintian-overrides +++ /dev/null @@ -1,13 +0,0 @@ -# "libstd" just seemed too generic -libstd-rust-1.64 binary: package-name-doesnt-match-sonames -libstd-rust-1.64 binary: sharedobject-in-library-directory-missing-soname - -# Rust doesn't use dev shlib symlinks nor any of the other shlib support stuff -libstd-rust-1.64 binary: dev-pkg-without-shlib-symlink -libstd-rust-1.64 binary: shlib-without-versioned-soname -libstd-rust-1.64 binary: unused-shlib-entry-in-control-file - -# Libraries that use libc symbols (libterm, libstd, etc) *are* linked -# to libc. Lintian gets upset that some Rust libraries don't need -# libc, boo hoo. -libstd-rust-1.64 binary: library-not-linked-against-libc diff --git a/debian/libstd-rust-1.65.install b/debian/libstd-rust-1.65.install new file mode 100644 index 000000000..cd4545cca --- /dev/null +++ b/debian/libstd-rust-1.65.install @@ -0,0 +1 @@ +usr/lib/${DEB_HOST_MULTIARCH}/ diff --git a/debian/libstd-rust-1.65.lintian-overrides b/debian/libstd-rust-1.65.lintian-overrides new file mode 100644 index 000000000..3218caec4 --- /dev/null +++ b/debian/libstd-rust-1.65.lintian-overrides @@ -0,0 +1,13 @@ +# "libstd" just seemed too generic +libstd-rust-1.65 binary: package-name-doesnt-match-sonames +libstd-rust-1.65 binary: sharedobject-in-library-directory-missing-soname + +# Rust doesn't use dev shlib symlinks nor any of the other shlib support stuff +libstd-rust-1.65 binary: dev-pkg-without-shlib-symlink +libstd-rust-1.65 binary: shlib-without-versioned-soname +libstd-rust-1.65 binary: unused-shlib-entry-in-control-file + +# Libraries that use libc symbols (libterm, libstd, etc) *are* linked +# to libc. Lintian gets upset that some Rust libraries don't need +# libc, boo hoo. +libstd-rust-1.65 binary: library-not-linked-against-libc diff --git a/debian/patches/d-0000-ignore-removed-submodules.patch b/debian/patches/d-0000-ignore-removed-submodules.patch index 3dfaf06cb..26d1e4361 100644 --- a/debian/patches/d-0000-ignore-removed-submodules.patch +++ b/debian/patches/d-0000-ignore-removed-submodules.patch @@ -3,21 +3,22 @@ Date: Sat, 2 Oct 2021 01:07:59 +0100 Subject: d-0000-ignore-removed-submodules --- - Cargo.toml | 36 ++++++++---------------------------- - src/bootstrap/bootstrap.py | 4 ---- - src/bootstrap/builder.rs | 7 +------ - src/bootstrap/doc.rs | 1 - - src/bootstrap/test.rs | 12 +----------- - src/tools/clippy/Cargo.toml | 5 ----- - src/tools/rustfmt/Cargo.toml | 5 ----- - src/tools/tidy/src/deps.rs | 2 +- - 8 files changed, 11 insertions(+), 61 deletions(-) + Cargo.toml | 15 --------------- + src/bootstrap/bootstrap.py | 4 ---- + src/bootstrap/builder.rs | 11 +---------- + src/bootstrap/doc.rs | 1 - + src/bootstrap/test.rs | 12 +----------- + src/tools/clippy/Cargo.toml | 5 ----- + src/tools/rust-analyzer/Cargo.toml | 11 ++++++++++- + src/tools/rustfmt/Cargo.toml | 5 ----- + src/tools/tidy/src/deps.rs | 2 +- + 9 files changed, 13 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml -index ffc886d..7231b60 100644 +index e49fe5e..863c800 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -16,25 +16,14 @@ members = [ +@@ -16,27 +16,15 @@ members = [ "src/tools/tidy", "src/tools/tier-check", "src/tools/build-manifest", @@ -38,38 +39,16 @@ index ffc886d..7231b60 100644 "src/tools/unicode-table-generator", - "src/tools/expand-yaml-anchors", "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/html-checker", - "src/tools/bump-stage0", +- "src/tools/replace-version-placeholder", "src/tools/lld-wrapper", ] -@@ -96,25 +85,16 @@ gimli.debug = 0 - miniz_oxide.debug = 0 +@@ -99,9 +87,6 @@ miniz_oxide.debug = 0 object.debug = 0 --# We want the RLS to use the version of Cargo that we've got vendored in this --# repository to ensure that the same exact version of Cargo is used by both the --# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository --# so we use a `[patch]` here to override the github repository with our local --# vendored copy. --[patch."https://github.com/rust-lang/cargo"] --cargo = { path = "src/tools/cargo" } --cargo-util = { path = "src/tools/cargo/crates/cargo-util" } -- --[patch."https://github.com/rust-lang/rustfmt"] --# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt` --# that we're shipping as well (to ensure that the rustfmt in RLS and the --# `rustfmt` executable are the same exact version). --rustfmt-nightly = { path = "src/tools/rustfmt" } -+# The only package that ever uses debug builds is bootstrap. -+# We care a lot about bootstrap's compile times, so don't include debug info for -+# dependencies, only bootstrap itself. -+[profile.dev] -+debug = 0 -+[profile.dev.package] -+# Only use debuginfo=1 to further reduce compile times. -+bootstrap.debug = 1 - [patch.crates-io] -# See comments in `src/tools/rustc-workspace-hack/README.md` for what's going on -# here @@ -78,7 +57,7 @@ index ffc886d..7231b60 100644 # See comments in `library/rustc-std-workspace-core/README.md` for what's going on # here diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py -index 03eec02..c40811f 100644 +index cc08ae5..bf7d696 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -759,10 +759,6 @@ class RustBuild(object): @@ -93,34 +72,36 @@ index 03eec02..c40811f 100644 args.append("--features") args.append("build-metrics") diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs -index 0ab4824..629e1bb 100644 +index 14e8ebd..6d43333 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs -@@ -600,7 +600,6 @@ impl<'a> Builder<'a> { +@@ -600,8 +600,6 @@ impl<'a> Builder<'a> { + tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, - tool::Rls, +- tool::Rls, - tool::RustAnalyzer, tool::RustAnalyzerProcMacroSrv, tool::RustDemangler, tool::Rustdoc, -@@ -622,7 +620,6 @@ impl<'a> Builder<'a> { +@@ -622,8 +621,6 @@ impl<'a> Builder<'a> { + check::CodegenBackend, check::Clippy, check::Miri, - check::Rls, +- check::Rls, - check::RustAnalyzer, check::Rustfmt, check::Bootstrap ), -@@ -650,7 +647,6 @@ impl<'a> Builder<'a> { +@@ -650,7 +648,6 @@ impl<'a> Builder<'a> { + test::ReplacePlaceholderTest, test::Cargotest, test::Cargo, - test::Rls, - test::RustAnalyzer, test::ErrorIndex, test::Distcheck, test::RunMakeFullDeps, -@@ -698,10 +694,8 @@ impl<'a> Builder<'a> { +@@ -698,10 +695,8 @@ impl<'a> Builder<'a> { doc::RustdocBook, doc::RustByExample, doc::RustcBook, @@ -131,7 +112,15 @@ index 0ab4824..629e1bb 100644 doc::EmbeddedBook, doc::EditionGuide, ), -@@ -723,7 +717,6 @@ impl<'a> Builder<'a> { +@@ -715,15 +712,12 @@ impl<'a> Builder<'a> { + dist::Analysis, + dist::Src, + dist::Cargo, +- dist::Rls, +- dist::RustAnalyzer, + dist::Rustfmt, + dist::RustDemangler, + dist::Clippy, dist::Miri, dist::LlvmTools, dist::RustDev, @@ -139,7 +128,15 @@ index 0ab4824..629e1bb 100644 // It seems that PlainSourceTarball somehow changes how some of the tools // perceive their dependencies (see #93033) which would invalidate fingerprints // and force us to rebuild tools after vendoring dependencies. -@@ -2054,10 +2047,7 @@ impl<'a> Builder<'a> { +@@ -736,7 +725,6 @@ impl<'a> Builder<'a> { + install::Docs, + install::Std, + install::Cargo, +- install::RustAnalyzer, + install::Rustfmt, + install::RustDemangler, + install::Clippy, +@@ -2056,10 +2050,7 @@ impl<'a> Builder<'a> { } } @@ -152,7 +149,7 @@ index 0ab4824..629e1bb 100644 } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs -index 2852442..5faa8e5 100644 +index f909ecc..8bf71b1 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -73,7 +73,6 @@ macro_rules! book { @@ -164,10 +161,10 @@ index 2852442..5faa8e5 100644 EditionGuide, "src/doc/edition-guide", "edition-guide", submodule; EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs -index c0fa8c9..8fbc390 100644 +index dd41f84..ba6227c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs -@@ -1910,17 +1910,7 @@ impl Step for RustcGuide { +@@ -1886,17 +1886,7 @@ impl Step for RustcGuide { } fn run(self, builder: &Builder<'_>) { @@ -187,7 +184,7 @@ index c0fa8c9..8fbc390 100644 } diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml -index 1c875c3..1aad7cf 100644 +index b7e136c..a844a5d 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -36,11 +36,6 @@ walkdir = "2.3" @@ -202,6 +199,26 @@ index 1c875c3..1aad7cf 100644 # UI test dependencies clippy_utils = { path = "clippy_utils" } derive-new = "0.5" +diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml +index 6b68ca8..93f755c 100644 +--- a/src/tools/rust-analyzer/Cargo.toml ++++ b/src/tools/rust-analyzer/Cargo.toml +@@ -1,5 +1,14 @@ + [workspace] +-members = ["xtask/", "lib/*", "crates/*"] ++members = [ ++ "xtask/", ++ "lib/*", ++ "crates/proc-macro-srv", ++ "crates/proc-macro-srv-cli", ++ "crates/tt", ++ "crates/mbe", ++ "crates/paths", ++ "crates/proc-macro-api", ++] + exclude = ["crates/proc-macro-test/imp"] + + [profile.dev] diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 7a4e02d..27b91f2 100644 --- a/src/tools/rustfmt/Cargo.toml @@ -219,10 +236,10 @@ index 7a4e02d..27b91f2 100644 [package.metadata.rust-analyzer] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs -index 333f85f..4df2b54 100644 +index cbd8cfa..6b39fd6 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs -@@ -306,7 +306,7 @@ const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ +@@ -308,7 +308,7 @@ const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ // These two crates take quite a long time to build, so don't allow two versions of them // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times // under control. @@ -231,23 +248,3 @@ index 333f85f..4df2b54 100644 ]; /// Dependency checks. -diff --git a/src/tools/rust-analyzer/Cargo.toml b/src.tools/rust-analyzer/Cargo.toml -index 6b68ca82389..7bc5d1bc5a0 100644 ---- a/src/tools/rust-analyzer/Cargo.toml -+++ b/src/tools/rust-analyzer/Cargo.toml -@@ -1,5 +1,14 @@ - [workspace] --members = ["xtask/", "lib/*", "crates/*"] -+members = [ -+ "xtask/", -+ "lib/*", -+ "crates/proc-macro-srv", -+ "crates/proc-macro-srv-cli", -+ "crates/tt", -+ "crates/mbe", -+ "crates/paths", -+ "crates/proc-macro-api", -+] - exclude = ["crates/proc-macro-test/imp"] - - [profile.dev] diff --git a/debian/patches/d-0004-clippy-feature-sync.patch b/debian/patches/d-0004-clippy-feature-sync.patch index 8c0c0fb97..19c75955e 100644 --- a/debian/patches/d-0004-clippy-feature-sync.patch +++ b/debian/patches/d-0004-clippy-feature-sync.patch @@ -5,15 +5,15 @@ Subject: d-0004-clippy-feature-sync enable features needed by rustfmt to make build system happy and speedup build. this is what rustc_workspace_hack does in the upstream build. --- - src/tools/clippy/Cargo.toml | 3 ++- + src/tools/clippy/Cargo.toml | 2 +- src/tools/rustfmt/Cargo.toml | 2 +- - 2 files changed, 3 insertions(+), 2 deletions(-) + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml -index 1aad7cf..705a880 100644 +index a844a5d..4dd3f55 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml -@@ -42,7 +43,7 @@ if_chain = "1.0" +@@ -43,7 +43,7 @@ if_chain = "1.0" itertools = "0.10.1" quote = "1.0" serde = { version = "1.0.125", features = ["derive"] } diff --git a/debian/patches/d-0005-no-jemalloc.patch b/debian/patches/d-0005-no-jemalloc.patch index 6d8620a01..ca74117bd 100644 --- a/debian/patches/d-0005-no-jemalloc.patch +++ b/debian/patches/d-0005-no-jemalloc.patch @@ -3,8 +3,9 @@ Date: Sat, 2 Oct 2021 01:08:00 +0100 Subject: d-0005-no-jemalloc --- - compiler/rustc/Cargo.toml | 6 ------ - 1 file changed, 6 deletions(-) + compiler/rustc/Cargo.toml | 6 ------ + src/tools/rust-analyzer/crates/profile/Cargo.toml | 2 -- + 2 files changed, 8 deletions(-) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 27ee3dd..87fb29f 100644 @@ -25,7 +26,7 @@ index 27ee3dd..87fb29f 100644 max_level_info = ['rustc_driver/max_level_info'] rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler'] diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml -index 99d4179dc20..0b78a45a24b 100644 +index 0b78a45..99d4179 100644 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml @@ -15,7 +15,6 @@ cfg-if = "1.0.0" @@ -36,7 +37,7 @@ index 99d4179dc20..0b78a45a24b 100644 [target.'cfg(target_os = "linux")'.dependencies] perf-event = "0.4.7" -@@ -24,7 +25,6 @@ winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } +@@ -25,7 +24,6 @@ winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } [features] cpu_profiler = [] diff --git a/debian/patches/d-bootstrap-cargo-check-cfg.patch b/debian/patches/d-bootstrap-cargo-check-cfg.patch index e15707199..c715b1f31 100644 --- a/debian/patches/d-bootstrap-cargo-check-cfg.patch +++ b/debian/patches/d-bootstrap-cargo-check-cfg.patch @@ -5,7 +5,7 @@ diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0ab4824ac0a..76c476f449b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs -@@ -1480,9 +1480,9 @@ impl<'a> Builder<'a> { +@@ -1472,9 +1472,9 @@ impl<'a> Builder<'a> { // complete list of features, so for that reason we don't enable checking of // features for std crates. cargo.arg(if mode != Mode::Std { diff --git a/debian/patches/d-bootstrap-custom-debuginfo-path.patch b/debian/patches/d-bootstrap-custom-debuginfo-path.patch index f955cffbf..2b548abcf 100644 --- a/debian/patches/d-bootstrap-custom-debuginfo-path.patch +++ b/debian/patches/d-bootstrap-custom-debuginfo-path.patch @@ -12,7 +12,7 @@ diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index ddc92ba..259b56e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs -@@ -1023,10 +1023,9 @@ impl Build { +@@ -1026,10 +1026,9 @@ impl Build { match which { GitRepo::Rustc => { diff --git a/debian/patches/d-bootstrap-disable-git.patch b/debian/patches/d-bootstrap-disable-git.patch index ce02d60b3..63823f51b 100644 --- a/debian/patches/d-bootstrap-disable-git.patch +++ b/debian/patches/d-bootstrap-disable-git.patch @@ -31,7 +31,7 @@ diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6181a61..5fe3600 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs -@@ -899,7 +899,10 @@ impl Step for PlainSourceTarball { +@@ -902,7 +902,10 @@ impl Step for PlainSourceTarball { } // If we're building from git sources, we need to vendor a complete distribution. diff --git a/debian/patches/d-bootstrap-read-beta-version-from-file.patch b/debian/patches/d-bootstrap-read-beta-version-from-file.patch index a5b385d13..812a653ba 100644 --- a/debian/patches/d-bootstrap-read-beta-version-from-file.patch +++ b/debian/patches/d-bootstrap-read-beta-version-from-file.patch @@ -11,7 +11,7 @@ diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 68d387b..ddc92ba 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs -@@ -1266,14 +1266,15 @@ impl Build { +@@ -1269,14 +1269,15 @@ impl Build { return s; } diff --git a/debian/patches/d-bootstrap-rustflags.patch b/debian/patches/d-bootstrap-rustflags.patch index a28810e89..dfcdee922 100644 --- a/debian/patches/d-bootstrap-rustflags.patch +++ b/debian/patches/d-bootstrap-rustflags.patch @@ -11,7 +11,7 @@ diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 23ea2fe..b2b1c54 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs -@@ -1505,6 +1505,18 @@ impl<'a> Builder<'a> { +@@ -1499,6 +1499,18 @@ impl<'a> Builder<'a> { } } diff --git a/debian/patches/d-rust-lldb-paths b/debian/patches/d-rust-lldb-paths index 15028a68f..bea7a3844 100644 --- a/debian/patches/d-rust-lldb-paths +++ b/debian/patches/d-rust-lldb-paths @@ -23,7 +23,7 @@ index bce72f1..793f593 100755 RUST_LLDB="$RUSTC_SYSROOT/lib/rustlib/$host/bin/lldb" -lldb=lldb -+lldb=lldb-14 ++lldb=lldb-15 if [ -f "$RUST_LLDB" ]; then lldb="$RUST_LLDB" else diff --git a/debian/patches/d-rustc-add-soname.patch b/debian/patches/d-rustc-add-soname.patch index 70fdf26b8..e69898bf5 100644 --- a/debian/patches/d-rustc-add-soname.patch +++ b/debian/patches/d-rustc-add-soname.patch @@ -28,7 +28,7 @@ diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codege index 04ec1e7..67296ca 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs -@@ -2175,6 +2175,13 @@ fn add_order_independent_options( +@@ -2240,6 +2240,13 @@ fn add_order_independent_options( } add_rpath_args(cmd, sess, codegen_results, out_filename); diff --git a/debian/patches/d-rustc-windows-ssp.patch b/debian/patches/d-rustc-windows-ssp.patch index 5d8ba4785..bbf00594c 100644 --- a/debian/patches/d-rustc-windows-ssp.patch +++ b/debian/patches/d-rustc-windows-ssp.patch @@ -11,7 +11,7 @@ diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc index d11f1f7..137f8eb 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs -@@ -40,6 +40,8 @@ pub fn opts() -> TargetOptions { +@@ -41,6 +41,8 @@ pub fn opts() -> TargetOptions { "-lmsvcrt", "-luser32", "-lkernel32", diff --git a/debian/patches/series b/debian/patches/series index c918b658a..d3c74ae4c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,17 +4,17 @@ u-ignore-reproducible-failure.patch u-reproducible-build.patch u-ignore-endian-big-diff.patch +u-make-compiletest-work-without-rpath.patch +u-fix-backtrace-tests.patch # fixed in 1.66 # can be dropped once upstream updates compiler_builtins u-arm-compiler-builtins-weak-linkage-arm.patch -u-arm-compiler-builtins-add-sync-builtin-fallbacks.patch # can be dropped once upstream updates rustix u-fix-rustix-for-sparc64.patch # not forwarded, or forwarded but unlikely to be merged u-ignore-ppc-hangs.patch -u-ignore-bpf-test.patch u-rustc-llvm-cross-flags.patch u-reproducible-dl-stage0.patch u-make-tests-work-without-rpath.patch @@ -67,4 +67,3 @@ d-rustdoc-disable-embedded-fonts.patch # cherry-picked from ubuntu ubuntu-disable-ppc64el-asm-tests.patch ubuntu-ignore-arm-doctest.patch -ubuntu-Revert-Use-constant-eval-to-do-strict-validity-check.patch diff --git a/debian/patches/u-arm-compiler-builtins-add-sync-builtin-fallbacks.patch b/debian/patches/u-arm-compiler-builtins-add-sync-builtin-fallbacks.patch deleted file mode 100644 index 796c17cef..000000000 --- a/debian/patches/u-arm-compiler-builtins-add-sync-builtin-fallbacks.patch +++ /dev/null @@ -1,223 +0,0 @@ -From 56172fcd8bd045e38bbdf76697d1fcca1e965d6d Mon Sep 17 00:00:00 2001 -From: Alex Huszagh -Date: Fri, 29 Jul 2022 16:58:05 -0500 -Subject: [PATCH] Add compiler-rt fallbacks for sync builtins on armv5te-musl. - ---- -https://github.com/rust-lang/compiler-builtins/pull/484 - - src/arm_linux.rs | 110 +++++++++++++++++++++++++++++++---------------- - 1 file changed, 73 insertions(+), 37 deletions(-) - -diff --git a/vendor/compiler_builtins/src/arm_linux.rs b/vendor/compiler_builtins/src/arm_linux.rs -index 8fe0948..8f22eb6 100644 ---- a/vendor/compiler_builtins/src/arm_linux.rs -+++ b/vendor/compiler_builtins/src/arm_linux.rs -@@ -55,7 +55,7 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { - } - - // Generic atomic read-modify-write operation --unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { -+unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { - let aligned_ptr = align_ptr(ptr); - let (shift, mask) = get_shift_mask(ptr); - -@@ -65,7 +65,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { - let newval = f(curval); - let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); - if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { -- return curval; -+ return g(curval, newval); - } - } - } -@@ -89,13 +89,21 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { - } - - macro_rules! atomic_rmw { -- ($name:ident, $ty:ty, $op:expr) => { -+ ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { - intrinsics! { - pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { -- atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty -+ atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty - } - } - }; -+ -+ (@old $name:ident, $ty:ty, $op:expr) => { -+ atomic_rmw!($name, $ty, $op, |old, _| old); -+ }; -+ -+ (@new $name:ident, $ty:ty, $op:expr) => { -+ atomic_rmw!($name, $ty, $op, |_, new| new); -+ }; - } - macro_rules! atomic_cmpxchg { - ($name:ident, $ty:ty) => { -@@ -107,101 +115,129 @@ macro_rules! atomic_cmpxchg { - }; - } - --atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); --atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a -+atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -+atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a -+ .wrapping_add(b)); -+atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a -+ .wrapping_add(b)); -+ -+atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -+atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a - .wrapping_add(b)); --atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a -+atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a - .wrapping_add(b)); - --atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); --atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a -+atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -+atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a - .wrapping_sub(b)); --atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a -+atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a - .wrapping_sub(b)); - --atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); --atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); --atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); -+atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -+atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a -+ .wrapping_sub(b)); -+atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a -+ .wrapping_sub(b)); -+ -+atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); -+atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); -+atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); -+ -+atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); -+atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); -+atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); -+ -+atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); -+atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); -+atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); -+ -+atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); -+atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); -+atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); -+ -+atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); -+atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); -+atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); - --atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); --atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); --atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); -+atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); -+atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); -+atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); - --atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); --atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); --atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -+atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); -+atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); -+atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); - --atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); --atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); --atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -+atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); -+atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); -+atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); - --atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { -+atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { -+atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { -+atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { - a - } else { - b - }); - --atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { -+atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { -+atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { -+atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { - a - } else { - b - }); - --atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { -+atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { -+atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { -+atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { - a - } else { - b - }); - --atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { -+atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { -+atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { - a - } else { - b - }); --atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { -+atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { - a - } else { - b - }); - --atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); --atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); --atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); -+atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); -+atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); -+atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); - - atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); - atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); --- -2.39.0 - diff --git a/debian/patches/u-fix-backtrace-tests.patch b/debian/patches/u-fix-backtrace-tests.patch new file mode 100644 index 000000000..9a5617ad1 --- /dev/null +++ b/debian/patches/u-fix-backtrace-tests.patch @@ -0,0 +1,54 @@ +From 3d8b3e6ca179dc2ac79c038ad607b2321be70e8d Mon Sep 17 00:00:00 2001 +From: Aaron Hill +Date: Wed, 21 Sep 2022 10:24:16 -0500 +Subject: [PATCH] Set 'exec-env:RUST_BACKTRACE=0' in const-eval-select tests + +This allows the tests to pass even if the user has RUST_BACKTRACE +set when running 'x.py' +--- + src/test/ui/intrinsics/const-eval-select-backtrace-std.rs | 1 + + .../ui/intrinsics/const-eval-select-backtrace-std.run.stderr | 2 +- + src/test/ui/intrinsics/const-eval-select-backtrace.rs | 1 + + src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr | 2 +- + 4 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs +index 29aefe07162b3..1164a3a5b0180 100644 +--- a/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs ++++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs +@@ -1,6 +1,7 @@ + // See issue #100696. + // run-fail + // check-run-results ++// exec-env:RUST_BACKTRACE=0 + fn main() { + &""[1..]; + } +diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr +index e53e6034620ca..463cd52c5aa7b 100644 +--- a/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr ++++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr +@@ -1,2 +1,2 @@ +-thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:5:6 ++thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:6:6 + note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.rs b/src/test/ui/intrinsics/const-eval-select-backtrace.rs +index 99f0725200c1d..ef1c7c4195b91 100644 +--- a/src/test/ui/intrinsics/const-eval-select-backtrace.rs ++++ b/src/test/ui/intrinsics/const-eval-select-backtrace.rs +@@ -2,6 +2,7 @@ + // See issue #100696. + // run-fail + // check-run-results ++// exec-env:RUST_BACKTRACE=0 + + #[track_caller] + fn uhoh() { +diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr +index 2fd730ac7a68a..54e28db5e533d 100644 +--- a/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr ++++ b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr +@@ -1,2 +1,2 @@ +-thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:16:9 ++thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:17:9 + note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/debian/patches/u-ignore-bpf-test.patch b/debian/patches/u-ignore-bpf-test.patch deleted file mode 100644 index 5fa3464ee..000000000 --- a/debian/patches/u-ignore-bpf-test.patch +++ /dev/null @@ -1,18 +0,0 @@ -From: Debian Rust Maintainers -Date: Thu, 14 Jul 2022 13:17:37 +0200 -Subject: u-ignore-bpf-test - -Bug: https://github.com/rust-lang/rust/issues/89689 ---- - src/test/assembly/asm/bpf-types.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/test/assembly/asm/bpf-types.rs b/src/test/assembly/asm/bpf-types.rs -index 3428d93..0e129a7 100644 ---- a/src/test/assembly/asm/bpf-types.rs -+++ b/src/test/assembly/asm/bpf-types.rs -@@ -1,3 +1,4 @@ -+// ignore-test - // min-llvm-version: 13.0 - // assembly-output: emit-asm - // compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 diff --git a/debian/patches/u-make-compiletest-work-without-rpath.patch b/debian/patches/u-make-compiletest-work-without-rpath.patch new file mode 100644 index 000000000..67c3badcd --- /dev/null +++ b/debian/patches/u-make-compiletest-work-without-rpath.patch @@ -0,0 +1,187 @@ +From f8a0cc2ca8a644ddb63867526711ba17cb7508c8 Mon Sep 17 00:00:00 2001 +From: Josh Stone +Date: Fri, 14 Oct 2022 16:11:28 -0700 +Subject: [PATCH] compiletest: set the dylib path when gathering target cfg +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the compiler is built with `rpath = false`, then it won't find its +own libraries unless the library search path is set. We already do that +while running the actual compiletests, but #100260 added another rustc +command for getting the target cfg. + + Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) + thread 'main' panicked at 'error: failed to get cfg info from "[...]/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" + --- stdout + + --- stderr + [...]/build/x86_64-unknown-linux-gnu/stage1/bin/rustc: error while loading shared libraries: librustc_driver-a2a76dc626cd02d2.so: cannot open shared object file: No such file or directory + ', src/tools/compiletest/src/common.rs:476:13 + +Now the library path is set here as well, so it works without rpath. + +FG: Context adapted + +Signed-off-by: Fabian Grünbichler +--- + src/tools/compiletest/src/common.rs | 18 +++++++++++------- + src/tools/compiletest/src/runtest.rs | 27 +++------------------------ + src/tools/compiletest/src/util.rs | 23 +++++++++++++++++++++++ + 3 files changed, 37 insertions(+), 31 deletions(-) + +diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs +index 64df76e2772..98a35810cfd 100644 +--- a/src/tools/compiletest/src/common.rs ++++ b/src/tools/compiletest/src/common.rs +@@ -2,11 +2,12 @@ pub use self::Mode::*; + + use std::ffi::OsString; + use std::fmt; ++use std::iter; + use std::path::{Path, PathBuf}; + use std::process::Command; + use std::str::FromStr; + +-use crate::util::PathBufExt; ++use crate::util::{add_dylib_path, PathBufExt}; + use lazycell::LazyCell; + use test::ColorConfig; + +@@ -389,7 +390,7 @@ impl Config { + } + + fn target_cfg(&self) -> &TargetCfg { +- self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target)) ++ self.target_cfg.borrow_with(|| TargetCfg::new(self)) + } + + pub fn matches_arch(&self, arch: &str) -> bool { +@@ -455,20 +456,22 @@ pub enum Endian { + } + + impl TargetCfg { +- fn new(rustc_path: &Path, target: &str) -> TargetCfg { +- let output = match Command::new(rustc_path) ++ fn new(config: &Config) -> TargetCfg { ++ let mut command = Command::new(&config.rustc_path); ++ add_dylib_path(&mut command, iter::once(&config.compile_lib_path)); ++ let output = match command + .arg("--print=cfg") + .arg("--target") +- .arg(target) ++ .arg(&config.target) + .output() + { + Ok(output) => output, +- Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path), ++ Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", config.rustc_path), + }; + if !output.status.success() { + panic!( + "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}", +- rustc_path, ++ config.rustc_path, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + ); +diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs +index 8f289876f73..eb467170249 100644 +--- a/src/tools/compiletest/src/runtest.rs ++++ b/src/tools/compiletest/src/runtest.rs +@@ -13,7 +13,7 @@ use crate::errors::{self, Error, ErrorKind}; + use crate::header::TestProps; + use crate::json; + use crate::read2::read2_abbreviated; +-use crate::util::{logv, PathBufExt}; ++use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt}; + use crate::ColorConfig; + use regex::{Captures, Regex}; + use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; +@@ -26,6 +26,7 @@ use std::fs::{self, create_dir_all, File, OpenOptions}; + use std::hash::{Hash, Hasher}; + use std::io::prelude::*; + use std::io::{self, BufReader}; ++use std::iter; + use std::path::{Path, PathBuf}; + use std::process::{Child, Command, ExitStatus, Output, Stdio}; + use std::str; +@@ -72,19 +73,6 @@ fn disable_error_reporting R, R>(f: F) -> R { + f() + } + +-/// The name of the environment variable that holds dynamic library locations. +-pub fn dylib_env_var() -> &'static str { +- if cfg!(windows) { +- "PATH" +- } else if cfg!(target_os = "macos") { +- "DYLD_LIBRARY_PATH" +- } else if cfg!(target_os = "haiku") { +- "LIBRARY_PATH" +- } else { +- "LD_LIBRARY_PATH" +- } +-} +- + /// The platform-specific library name + pub fn get_lib_name(lib: &str, dylib: bool) -> String { + // In some casess (e.g. MUSL), we build a static +@@ -1826,16 +1814,7 @@ impl<'test> TestCx<'test> { + + // Need to be sure to put both the lib_path and the aux path in the dylib + // search path for the child. +- let mut path = +- env::split_paths(&env::var_os(dylib_env_var()).unwrap_or_default()).collect::>(); +- if let Some(p) = aux_path { +- path.insert(0, PathBuf::from(p)) +- } +- path.insert(0, PathBuf::from(lib_path)); +- +- // Add the new dylib search path var +- let newpath = env::join_paths(&path).unwrap(); +- command.env(dylib_env_var(), newpath); ++ add_dylib_path(&mut command, iter::once(lib_path).chain(aux_path)); + + let mut child = disable_error_reporting(|| command.spawn()) + .unwrap_or_else(|_| panic!("failed to exec `{:?}`", &command)); +diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs +index 9d047b63c85..4b73be0fbb9 100644 +--- a/src/tools/compiletest/src/util.rs ++++ b/src/tools/compiletest/src/util.rs +@@ -2,6 +2,7 @@ use crate::common::Config; + use std::env; + use std::ffi::OsStr; + use std::path::PathBuf; ++use std::process::Command; + + use tracing::*; + +@@ -105,3 +106,25 @@ impl PathBufExt for PathBuf { + } + } + } ++ ++/// The name of the environment variable that holds dynamic library locations. ++pub fn dylib_env_var() -> &'static str { ++ if cfg!(windows) { ++ "PATH" ++ } else if cfg!(target_os = "macos") { ++ "DYLD_LIBRARY_PATH" ++ } else if cfg!(target_os = "haiku") { ++ "LIBRARY_PATH" ++ } else { ++ "LD_LIBRARY_PATH" ++ } ++} ++ ++/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. ++/// If the dylib_path_var is already set for this cmd, the old value will be overwritten! ++pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator>) { ++ let path_env = env::var_os(dylib_env_var()); ++ let old_paths = path_env.as_ref().map(env::split_paths); ++ let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten()); ++ cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap()); ++} +-- +2.30.2 + diff --git a/debian/patches/u-rustc-llvm-cross-flags.patch b/debian/patches/u-rustc-llvm-cross-flags.patch index 95988249e..0e544db8e 100644 --- a/debian/patches/u-rustc-llvm-cross-flags.patch +++ b/debian/patches/u-rustc-llvm-cross-flags.patch @@ -11,7 +11,7 @@ diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index b8f67ee..e9b1d0a 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs -@@ -294,7 +294,7 @@ fn main() { +@@ -301,7 +301,7 @@ fn main() { if let Some(stripped) = lib.strip_prefix("-LIBPATH:") { println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target)); } else if let Some(stripped) = lib.strip_prefix("-L") { diff --git a/debian/patches/ubuntu-Revert-Use-constant-eval-to-do-strict-validity-check.patch b/debian/patches/ubuntu-Revert-Use-constant-eval-to-do-strict-validity-check.patch deleted file mode 100644 index c9b50d71f..000000000 --- a/debian/patches/ubuntu-Revert-Use-constant-eval-to-do-strict-validity-check.patch +++ /dev/null @@ -1,569 +0,0 @@ -From b9e588dfeecca821a4508166027afb6bda721ed6 Mon Sep 17 00:00:00 2001 -From: Simon Chopin -Date: Wed, 18 Jan 2023 17:03:04 +0100 -Subject: [PATCH] Revert "Use constant eval to do strict validity checks" - -This reverts commit 27412d1e3e128349bc515c16ce882860e20f037d. - -This is likely a LLVM mis-optimization, but we're not really sure. It -leads to ICE on riscv64. - -Bug: https://github.com/rust-lang/rust/issues/102155 - ---- - Cargo.lock | 1 - - .../src/intrinsics/mod.rs | 15 ++++- - compiler/rustc_codegen_ssa/Cargo.toml | 1 - - compiler/rustc_codegen_ssa/src/mir/block.rs | 9 +-- - .../src/const_eval/machine.rs | 2 +- - .../src/interpret/intrinsics.rs | 56 ++++++++-------- - compiler/rustc_const_eval/src/lib.rs | 6 -- - .../src/might_permit_raw_init.rs | 40 ----------- - compiler/rustc_middle/src/query/mod.rs | 8 --- - compiler/rustc_middle/src/ty/query.rs | 1 - - compiler/rustc_query_impl/src/keys.rs | 12 +--- - compiler/rustc_target/src/abi/mod.rs | 38 ++++++----- - .../intrinsics/panic-uninitialized-zeroed.rs | 66 +++++++------------ - 13 files changed, 94 insertions(+), 161 deletions(-) - delete mode 100644 compiler/rustc_const_eval/src/might_permit_raw_init.rs - -diff --git a/Cargo.lock b/Cargo.lock -index 2569b3e1976..b88158f9ff8 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -3731,7 +3731,6 @@ dependencies = [ - "rustc_arena", - "rustc_ast", - "rustc_attr", -- "rustc_const_eval", - "rustc_data_structures", - "rustc_errors", - "rustc_fs_util", -diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs -index b2a83e1d4eb..4f9ced001d4 100644 ---- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs -+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs -@@ -22,6 +22,7 @@ macro_rules! intrinsic_args { - use rustc_middle::ty::print::with_no_trimmed_paths; - use rustc_middle::ty::subst::SubstsRef; - use rustc_span::symbol::{kw, sym, Symbol}; -+use rustc_target::abi::InitKind; - - use crate::prelude::*; - use cranelift_codegen::ir::AtomicRmwOp; -@@ -693,7 +694,12 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value { - return; - } - -- if intrinsic == sym::assert_zero_valid && !fx.tcx.permits_zero_init(layout) { -+ if intrinsic == sym::assert_zero_valid -+ && !layout.might_permit_raw_init( -+ fx, -+ InitKind::Zero, -+ fx.tcx.sess.opts.unstable_opts.strict_init_checks) { -+ - with_no_trimmed_paths!({ - crate::base::codegen_panic( - fx, -@@ -707,7 +713,12 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value { - return; - } - -- if intrinsic == sym::assert_uninit_valid && !fx.tcx.permits_uninit_init(layout) { -+ if intrinsic == sym::assert_uninit_valid -+ && !layout.might_permit_raw_init( -+ fx, -+ InitKind::Uninit, -+ fx.tcx.sess.opts.unstable_opts.strict_init_checks) { -+ - with_no_trimmed_paths!({ - crate::base::codegen_panic( - fx, -diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml -index 46d6344dbb2..e7ee424668b 100644 ---- a/compiler/rustc_codegen_ssa/Cargo.toml -+++ b/compiler/rustc_codegen_ssa/Cargo.toml -@@ -40,7 +40,6 @@ rustc_metadata = { path = "../rustc_metadata" } - rustc_query_system = { path = "../rustc_query_system" } - rustc_target = { path = "../rustc_target" } - rustc_session = { path = "../rustc_session" } --rustc_const_eval = { path = "../rustc_const_eval" } - - [dependencies.object] - version = "0.29.0" -diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs -index 3eee58d9d1c..a9eb4ec6439 100644 ---- a/compiler/rustc_codegen_ssa/src/mir/block.rs -+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs -@@ -22,7 +22,7 @@ - use rustc_span::{sym, Symbol}; - use rustc_symbol_mangling::typeid::typeid_for_fnabi; - use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; --use rustc_target::abi::{self, HasDataLayout, WrappingRange}; -+use rustc_target::abi::{self, HasDataLayout, InitKind, WrappingRange}; - use rustc_target::spec::abi::Abi; - - /// Used by `FunctionCx::codegen_terminator` for emitting common patterns -@@ -528,6 +528,7 @@ fn codegen_panic_intrinsic( - source_info: mir::SourceInfo, - target: Option, - cleanup: Option, -+ strict_validity: bool, - ) -> bool { - // Emit a panic or a no-op for `assert_*` intrinsics. - // These are intrinsics that compile to panics so that we can get a message -@@ -546,13 +547,12 @@ enum AssertIntrinsic { - }); - if let Some(intrinsic) = panic_intrinsic { - use AssertIntrinsic::*; -- - let ty = instance.unwrap().substs.type_at(0); - let layout = bx.layout_of(ty); - let do_panic = match intrinsic { - Inhabited => layout.abi.is_uninhabited(), -- ZeroValid => !bx.tcx().permits_zero_init(layout), -- UninitValid => !bx.tcx().permits_uninit_init(layout), -+ ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity), -+ UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity), - }; - if do_panic { - let msg_str = with_no_visible_paths!({ -@@ -687,6 +687,7 @@ fn codegen_call_terminator( - source_info, - target, - cleanup, -+ self.cx.tcx().sess.opts.unstable_opts.strict_init_checks, - ) { - return; - } -diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs -index fc2e6652a3d..ef6cff42ad9 100644 ---- a/compiler/rustc_const_eval/src/const_eval/machine.rs -+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs -@@ -104,7 +104,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { - } - - impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { -- pub(crate) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self { -+ pub(super) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self { - CompileTimeInterpreter { - steps_remaining: const_eval_limit.0, - stack: Vec::new(), -diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs -index 08209eb7932..e0ce6d9acc8 100644 ---- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs -+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs -@@ -15,7 +15,7 @@ - use rustc_middle::ty::subst::SubstsRef; - use rustc_middle::ty::{Ty, TyCtxt}; - use rustc_span::symbol::{sym, Symbol}; --use rustc_target::abi::{Abi, Align, Primitive, Size}; -+use rustc_target::abi::{Abi, Align, InitKind, Primitive, Size}; - - use super::{ - util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, -@@ -435,33 +435,35 @@ pub fn emulate_intrinsic( - ), - )?; - } -- -- if intrinsic_name == sym::assert_zero_valid { -- let should_panic = !self.tcx.permits_zero_init(layout); -- -- if should_panic { -- M::abort( -- self, -- format!( -- "aborted execution: attempted to zero-initialize type `{}`, which is invalid", -- ty -- ), -- )?; -- } -+ if intrinsic_name == sym::assert_zero_valid -+ && !layout.might_permit_raw_init( -+ self, -+ InitKind::Zero, -+ self.tcx.sess.opts.unstable_opts.strict_init_checks, -+ ) -+ { -+ M::abort( -+ self, -+ format!( -+ "aborted execution: attempted to zero-initialize type `{}`, which is invalid", -+ ty -+ ), -+ )?; - } -- -- if intrinsic_name == sym::assert_uninit_valid { -- let should_panic = !self.tcx.permits_uninit_init(layout); -- -- if should_panic { -- M::abort( -- self, -- format!( -- "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", -- ty -- ), -- )?; -- } -+ if intrinsic_name == sym::assert_uninit_valid -+ && !layout.might_permit_raw_init( -+ self, -+ InitKind::Uninit, -+ self.tcx.sess.opts.unstable_opts.strict_init_checks, -+ ) -+ { -+ M::abort( -+ self, -+ format!( -+ "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", -+ ty -+ ), -+ )?; - } - } - sym::simd_insert => { -diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs -index 72ac6af685d..d65d4f7eb72 100644 ---- a/compiler/rustc_const_eval/src/lib.rs -+++ b/compiler/rustc_const_eval/src/lib.rs -@@ -33,13 +33,11 @@ - pub mod const_eval; - mod errors; - pub mod interpret; --mod might_permit_raw_init; - pub mod transform; - pub mod util; - - use rustc_middle::ty; - use rustc_middle::ty::query::Providers; --use rustc_target::abi::InitKind; - - pub fn provide(providers: &mut Providers) { - const_eval::provide(providers); -@@ -61,8 +59,4 @@ pub fn provide(providers: &mut Providers) { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::deref_mir_constant(tcx, param_env, value) - }; -- providers.permits_uninit_init = -- |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit); -- providers.permits_zero_init = -- |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero); - } -diff --git a/compiler/rustc_const_eval/src/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/might_permit_raw_init.rs -deleted file mode 100644 -index f971c2238c7..00000000000 ---- a/compiler/rustc_const_eval/src/might_permit_raw_init.rs -+++ /dev/null -@@ -1,40 +0,0 @@ --use crate::const_eval::CompileTimeInterpreter; --use crate::interpret::{InterpCx, MemoryKind, OpTy}; --use rustc_middle::ty::layout::LayoutCx; --use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt}; --use rustc_session::Limit; --use rustc_target::abi::InitKind; -- --pub fn might_permit_raw_init<'tcx>( -- tcx: TyCtxt<'tcx>, -- ty: TyAndLayout<'tcx>, -- kind: InitKind, --) -> bool { -- let strict = tcx.sess.opts.unstable_opts.strict_init_checks; -- -- if strict { -- let machine = CompileTimeInterpreter::new(Limit::new(0), false); -- -- let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); -- -- let allocated = cx -- .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) -- .expect("OOM: failed to allocate for uninit check"); -- -- if kind == InitKind::Zero { -- cx.write_bytes_ptr( -- allocated.ptr, -- std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()), -- ) -- .expect("failed to write bytes for zero valid check"); -- } -- -- let ot: OpTy<'_, _> = allocated.into(); -- -- // Assume that if it failed, it's a validation failure. -- cx.validate_operand(&ot).is_ok() -- } else { -- let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() }; -- ty.might_permit_raw_init(&layout_cx, kind) -- } --} -diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs -index d8483e7e409..e498015a4a5 100644 ---- a/compiler/rustc_middle/src/query/mod.rs -+++ b/compiler/rustc_middle/src/query/mod.rs -@@ -2049,12 +2049,4 @@ - desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) } - separate_provide_extern - } -- -- query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool { -- desc { "checking to see if {:?} permits being left uninit", key.ty } -- } -- -- query permits_zero_init(key: TyAndLayout<'tcx>) -> bool { -- desc { "checking to see if {:?} permits being left zeroed", key.ty } -- } - } -diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs -index 2452bcf6a61..3d662ed5de4 100644 ---- a/compiler/rustc_middle/src/ty/query.rs -+++ b/compiler/rustc_middle/src/ty/query.rs -@@ -28,7 +28,6 @@ - use crate::traits::specialization_graph; - use crate::traits::{self, ImplSource}; - use crate::ty::fast_reject::SimplifiedType; --use crate::ty::layout::TyAndLayout; - use crate::ty::subst::{GenericArg, SubstsRef}; - use crate::ty::util::AlwaysRequiresDrop; - use crate::ty::GeneratorDiagnosticData; -diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs -index 49175e97f41..4d6bb02c38e 100644 ---- a/compiler/rustc_query_impl/src/keys.rs -+++ b/compiler/rustc_query_impl/src/keys.rs -@@ -6,7 +6,7 @@ - use rustc_middle::traits; - use rustc_middle::ty::fast_reject::SimplifiedType; - use rustc_middle::ty::subst::{GenericArg, SubstsRef}; --use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt}; -+use rustc_middle::ty::{self, Ty, TyCtxt}; - use rustc_span::symbol::{Ident, Symbol}; - use rustc_span::{Span, DUMMY_SP}; - -@@ -395,16 +395,6 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span { - } - } - --impl<'tcx> Key for TyAndLayout<'tcx> { -- #[inline(always)] -- fn query_crate_is_local(&self) -> bool { -- true -- } -- fn default_span(&self, _: TyCtxt<'_>) -> Span { -- DUMMY_SP -- } --} -- - impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { - #[inline(always)] - fn query_crate_is_local(&self) -> bool { -diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs -index 92ce4d91d84..d103a06060d 100644 ---- a/compiler/rustc_target/src/abi/mod.rs -+++ b/compiler/rustc_target/src/abi/mod.rs -@@ -1378,7 +1378,7 @@ pub struct PointeeInfo { - - /// Used in `might_permit_raw_init` to indicate the kind of initialisation - /// that is checked to be valid --#[derive(Copy, Clone, Debug, PartialEq, Eq)] -+#[derive(Copy, Clone, Debug)] - pub enum InitKind { - Zero, - Uninit, -@@ -1493,18 +1493,14 @@ pub fn is_zst(&self) -> bool { - /// - /// `init_kind` indicates if the memory is zero-initialized or left uninitialized. - /// -- /// This code is intentionally conservative, and will not detect -- /// * zero init of an enum whose 0 variant does not allow zero initialization -- /// * making uninitialized types who have a full valid range (ints, floats, raw pointers) -- /// * Any form of invalid value being made inside an array (unless the value is uninhabited) -+ /// `strict` is an opt-in debugging flag added in #97323 that enables more checks. - /// -- /// A strict form of these checks that uses const evaluation exists in -- /// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks -- /// stricter is . -+ /// This is conservative: in doubt, it will answer `true`. - /// -- /// FIXME: Once all the conservatism is removed from here, and the checks are ran by default, -- /// we can use the const evaluation checks always instead. -- pub fn might_permit_raw_init(self, cx: &C, init_kind: InitKind) -> bool -+ /// FIXME: Once we removed all the conservatism, we could alternatively -+ /// create an all-0/all-undef constant and run the const value validator to see if -+ /// this is a valid value for the given type. -+ pub fn might_permit_raw_init(self, cx: &C, init_kind: InitKind, strict: bool) -> bool - where - Self: Copy, - Ty: TyAbiInterface<'a, C>, -@@ -1517,8 +1513,13 @@ pub fn might_permit_raw_init(self, cx: &C, init_kind: InitKind) -> bool - s.valid_range(cx).contains(0) - } - InitKind::Uninit => { -- // The range must include all values. -- s.is_always_valid(cx) -+ if strict { -+ // The type must be allowed to be uninit (which means "is a union"). -+ s.is_uninit_valid() -+ } else { -+ // The range must include all values. -+ s.is_always_valid(cx) -+ } - } - } - }; -@@ -1539,12 +1540,19 @@ pub fn might_permit_raw_init(self, cx: &C, init_kind: InitKind) -> bool - // If we have not found an error yet, we need to recursively descend into fields. - match &self.fields { - FieldsShape::Primitive | FieldsShape::Union { .. } => {} -- FieldsShape::Array { .. } => { -+ FieldsShape::Array { count, .. } => { - // FIXME(#66151): For now, we are conservative and do not check arrays by default. -+ if strict -+ && *count > 0 -+ && !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict) -+ { -+ // Found non empty array with a type that is unhappy about this kind of initialization -+ return false; -+ } - } - FieldsShape::Arbitrary { offsets, .. } => { - for idx in 0..offsets.len() { -- if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) { -+ if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) { - // We found a field that is unhappy with this kind of initialization. - return false; - } -diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs -index 255151a9603..3ffd35ecdb8 100644 ---- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs -+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs -@@ -57,13 +57,6 @@ enum LR_NonZero { - - struct ZeroSized; - --#[allow(dead_code)] --#[repr(i32)] --enum ZeroIsValid { -- Zero(u8) = 0, -- One(NonNull<()>) = 1, --} -- - fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { - let err = panic::catch_unwind(op).err(); - assert_eq!( -@@ -159,12 +152,33 @@ fn main() { - "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" - ); - -+ /* FIXME(#66151) we conservatively do not error here yet. -+ test_panic_msg( -+ || mem::uninitialized::(), -+ "attempted to leave type `LR_NonZero` uninitialized, which is invalid" -+ ); -+ test_panic_msg( -+ || mem::zeroed::(), -+ "attempted to zero-initialize type `LR_NonZero`, which is invalid" -+ ); -+ -+ test_panic_msg( -+ || mem::uninitialized::>(), -+ "attempted to leave type `std::mem::ManuallyDrop` uninitialized, \ -+ which is invalid" -+ ); -+ test_panic_msg( -+ || mem::zeroed::>(), -+ "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ -+ which is invalid" -+ ); -+ */ -+ - test_panic_msg( - || mem::uninitialized::<(NonNull, u32, u32)>(), - "attempted to leave type `(core::ptr::non_null::NonNull, u32, u32)` uninitialized, \ - which is invalid" - ); -- - test_panic_msg( - || mem::zeroed::<(NonNull, u32, u32)>(), - "attempted to zero-initialize type `(core::ptr::non_null::NonNull, u32, u32)`, \ -@@ -182,23 +196,11 @@ fn main() { - which is invalid" - ); - -- test_panic_msg( -- || mem::uninitialized::(), -- "attempted to leave type `LR_NonZero` uninitialized, which is invalid" -- ); -- -- test_panic_msg( -- || mem::uninitialized::>(), -- "attempted to leave type `core::mem::manually_drop::ManuallyDrop` uninitialized, \ -- which is invalid" -- ); -- - test_panic_msg( - || mem::uninitialized::(), - "attempted to leave type `NoNullVariant` uninitialized, \ - which is invalid" - ); -- - test_panic_msg( - || mem::zeroed::(), - "attempted to zero-initialize type `NoNullVariant`, \ -@@ -210,12 +212,10 @@ fn main() { - || mem::uninitialized::(), - "attempted to leave type `bool` uninitialized, which is invalid" - ); -- - test_panic_msg( - || mem::uninitialized::(), - "attempted to leave type `LR` uninitialized, which is invalid" - ); -- - test_panic_msg( - || mem::uninitialized::>(), - "attempted to leave type `core::mem::manually_drop::ManuallyDrop` uninitialized, which is invalid" -@@ -229,7 +229,6 @@ fn main() { - let _val = mem::zeroed::>(); - let _val = mem::zeroed::>>(); - let _val = mem::zeroed::<[!; 0]>(); -- let _val = mem::zeroed::(); - let _val = mem::uninitialized::>(); - let _val = mem::uninitialized::<[!; 0]>(); - let _val = mem::uninitialized::<()>(); -@@ -260,33 +259,12 @@ fn main() { - || mem::zeroed::<[NonNull<()>; 1]>(), - "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid" - ); -- -- // FIXME(#66151) we conservatively do not error here yet (by default). -- test_panic_msg( -- || mem::zeroed::(), -- "attempted to zero-initialize type `LR_NonZero`, which is invalid" -- ); -- -- test_panic_msg( -- || mem::zeroed::>(), -- "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop`, \ -- which is invalid" -- ); - } else { - // These are UB because they have not been officially blessed, but we await the resolution - // of before doing - // anything about that. - let _val = mem::uninitialized::(); - let _val = mem::uninitialized::<*const ()>(); -- -- // These are UB, but best to test them to ensure we don't become unintentionally -- // stricter. -- -- // It's currently unchecked to create invalid enums and values inside arrays. -- let _val = mem::zeroed::(); -- let _val = mem::zeroed::<[LR_NonZero; 1]>(); -- let _val = mem::zeroed::<[NonNull<()>; 1]>(); -- let _val = mem::uninitialized::<[NonNull<()>; 1]>(); - } - } - } --- -2.37.2 - diff --git a/debian/patches/ubuntu-disable-ppc64el-asm-tests.patch b/debian/patches/ubuntu-disable-ppc64el-asm-tests.patch index bc841cc8b..001305b6e 100644 --- a/debian/patches/ubuntu-disable-ppc64el-asm-tests.patch +++ b/debian/patches/ubuntu-disable-ppc64el-asm-tests.patch @@ -1,6 +1,6 @@ --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs -@@ -2749,11 +2749,13 @@ +@@ -2913,11 +2913,13 @@ declare_lint! { /// /// use std::arch::asm; /// @@ -17,7 +17,7 @@ --- a/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile +++ b/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile @@ -1,6 +1,7 @@ - -include ../tools.mk + include ../tools.mk # ignore-windows-msvc +# needs-asm-support @@ -26,7 +26,7 @@ # https://github.com/llvm-mirror/llvm/commit/64b2297786f7fd6f5fa24cdd4db0298fbf211466 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs -@@ -3136,6 +3136,10 @@ +@@ -3053,6 +3053,10 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail diff --git a/debian/rules b/debian/rules index 8b83b8272..97f2f071d 100755 --- a/debian/rules +++ b/debian/rules @@ -28,8 +28,8 @@ export RUST_LONG_VERSION DEB_DESTDIR := $(CURDIR)/debian/tmp # Use system LLVM (comment out to use vendored LLVM) -LLVM_VERSION = 14 -OLD_LLVM_VERSION = 13 +LLVM_VERSION = 15 +OLD_LLVM_VERSION = 14 # Make it easier to test against a custom LLVM ifneq (,$(LLVM_DESTDIR)) LLVM_LIBRARY_PATH := $(LLVM_DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH):$(LLVM_DESTDIR)/usr/lib @@ -278,9 +278,14 @@ FAILURES_ALLOWED = 8 ifneq (,$(filter $(DEB_BUILD_ARCH), armhf)) FAILURES_ALLOWED = 12 endif -ifneq (,$(filter $(DEB_BUILD_ARCH), armel mips mipsel mips64el)) +ifneq (,$(filter $(DEB_BUILD_ARCH), armel mips mips64el)) FAILURES_ALLOWED = 24 endif +# workaround broken gdb 13.1 - revert to 24 once fixed +# #1031946 / #1032785 +ifneq (,$(filter $(DEB_BUILD_ARCH), mipsel)) + FAILURES_ALLOWED = 25 +endif ifneq (,$(filter $(DEB_BUILD_ARCH), ppc64 s390x)) FAILURES_ALLOWED = 40 endif diff --git a/debian/rust-lldb.links b/debian/rust-lldb.links index d9de18f77..561aff8b5 100644 --- a/debian/rust-lldb.links +++ b/debian/rust-lldb.links @@ -1 +1 @@ -usr/share/man/man1/lldb-14.1.gz usr/share/man/man1/rust-lldb.1.gz +usr/share/man/man1/lldb-15.1.gz usr/share/man/man1/rust-lldb.1.gz diff --git a/debian/rustc.links b/debian/rustc.links index db024ff24..10826e2ef 100644 --- a/debian/rustc.links +++ b/debian/rustc.links @@ -1,6 +1,6 @@ -usr/bin/lld-14 usr/bin/rust-lld -usr/bin/clang-14 usr/bin/rust-clang -usr/bin/llvm-dwp-14 usr/bin/rust-llvm-dwp +usr/bin/lld-15 usr/bin/rust-lld +usr/bin/clang-15 usr/bin/rust-clang +usr/bin/llvm-dwp-15 usr/bin/rust-llvm-dwp # for -Z gcc-ld=lld, see compiler/rustc_codegen_ssa/src/back/link.rs for logic usr/bin/rust-lld usr/lib/rustlib/${env:DEB_HOST_RUST_TYPE}/bin/gcc-ld/ld usr/bin/rust-lld usr/lib/rustlib/${env:DEB_HOST_RUST_TYPE}/bin/gcc-ld/ld64 diff --git a/debian/upstream-tarball-unsuspicious.txt b/debian/upstream-tarball-unsuspicious.txt index 216c81b8f..5d9dbaf38 100644 --- a/debian/upstream-tarball-unsuspicious.txt +++ b/debian/upstream-tarball-unsuspicious.txt @@ -5,9 +5,19 @@ # probably Doing It Wrong. Ask in #debian-rust or the mailing list for pointers. # False-positive, file(1) misidentifies mime type +compiler/rustc_error_codes/src/error_codes/E0469.md +src/doc/reference/src/crates-and-source-files.md +src/doc/reference/src/items/extern-crates.md +src/doc/reference/src/items/modules.md +src/doc/reference/src/types-redirect.html +src/tools/clippy/src/docs/alloc_instead_of_core.txt +src/tools/clippy/src/docs/only_used_in_recursion.txt +vendor/chalk-solve-0.80.0/src/infer/test.rs +vendor/getrandom-0.1.14/src/wasm32_stdweb.rs vendor/itertools*/examples/iris.data -vendor/regex/tests/unicode.rs +vendor/minifier/src/js/tools.rs vendor/regex/tests/suffix_reverse.rs +vendor/regex/tests/unicode.rs vendor/term/src/terminfo/parser/names.rs # False-positive, "verylongtext" but OK @@ -21,6 +31,7 @@ library/portable-simd/*.md library/std/src/sys/sgx/abi/entry.S library/stdarch/CONTRIBUTING.md library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +src/doc/*/CODE_OF_CONDUCT.md src/doc/book/first-edition/src/the-stack-and-the-heap.md src/doc/edition-guide/src/rust-2018/index.md src/doc/edition-guide/src/rust-2021/disjoint-capture-in-closures.md @@ -33,41 +44,43 @@ src/doc/rust-by-example/src/flow_control/if_let.md src/doc/rust-by-example/src/std/arc.md src/doc/rust-by-example/src/trait/dyn.md src/doc/rust-by-example/src/unsafe/asm.md +src/doc/rustc-dev-guide/src/*.md +src/doc/rustc-dev-guide/src/*/*.md src/doc/rustc/src/instrument-coverage.md src/doc/rustc/src/lints/groups.md -src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md +src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md src/doc/rustc/src/targets/known-issues.md -src/doc/rustc-dev-guide/src/*.md -src/doc/rustc-dev-guide/src/*/*.md src/doc/rustdoc/src/*.md -src/doc/*/CODE_OF_CONDUCT.md src/doc/unstable-book/src/*/*.md src/etc/third-party/README.txt src/librustdoc/html/highlight/fixtures/sample.html src/librustdoc/html/static/scrape-examples-help.md -src/tools/rustfmt/*.md -src/tools/rust-analyzer/docs/user/manual.adoc +src/tools/clippy/src/docs/trailing_empty_array.txt src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs -vendor/*/Cargo.toml +src/tools/rust-analyzer/docs/user/manual.adoc +src/tools/rustfmt/*.md +vendor/*/*/*/LICENSE +vendor/*/*/LICENSE vendor/*/CHANGELOG.md vendor/*/CODE_OF_CONDUCT.md -vendor/*/README.md -vendor/*/README.tpl +vendor/*/Cargo.toml vendor/*/LICENSE vendor/*/LICENSE-MIT -vendor/*/*/LICENSE -vendor/*/*/*/LICENSE +vendor/*/README.md vendor/ahash/FAQ.md vendor/ammonia/src/lib.rs -vendor/clap/examples/derive_ref/README.md +vendor/clap/examples/demo.md +vendor/clap/examples/tutorial_*/*.md vendor/generic-array/DESIGN.md vendor/handlebars/src/lib.rs +vendor/handlebars/src/render.rs vendor/handlebars/src/template.rs +vendor/lazy_static/src/lib.rs vendor/maplit/README.rst vendor/mdbook/CONTRIBUTING.md vendor/miniz_oxide/Readme.md -vendor/lazy_static/src/lib.rs vendor/pulldown-cmark/tests/suite/footnotes.rs vendor/rustc-demangle/src/legacy.rs vendor/stable_deref_trait/src/lib.rs @@ -76,15 +89,15 @@ vendor/tracing-subscriber/src/fmt/format/json.rs vendor/unicase/src/lib.rs vendor/unicode-normalization/src/stream_safe.rs vendor/winapi/src/lib.rs +vendor/windows-sys-0.*/src/Windows/Win32/*.rs +vendor/windows-sys-0.*/src/Windows/Win32/*/*.rs +vendor/windows-sys-0.*/src/Windows/Win32/*/*/*.rs +vendor/windows-sys-0.*/src/Windows/Win32/*/*/*/*.rs vendor/windows-sys/readme.md vendor/windows-sys/src/Windows/Win32/*.rs vendor/windows-sys/src/Windows/Win32/*/*.rs vendor/windows-sys/src/Windows/Win32/*/*/*.rs vendor/windows-sys/src/Windows/Win32/*/*/*/*.rs -vendor/windows-sys-0.*/src/Windows/Win32/*.rs -vendor/windows-sys-0.*/src/Windows/Win32/*/*.rs -vendor/windows-sys-0.*/src/Windows/Win32/*/*/*.rs -vendor/windows-sys-0.*/src/Windows/Win32/*/*/*/*.rs # False-positive, audit-vendor-source automatically flags JS/C files # The below ones are OK since they're actually part of rust's own source code @@ -92,18 +105,20 @@ vendor/windows-sys-0.*/src/Windows/Win32/*/*/*/*.rs src/ci/docker/scripts/qemu-bare-bones-addentropy.c src/doc/book/*/ferris.js src/doc/book/ferris.js +src/doc/reference/src/attributes-redirect.html src/doc/rustc-dev-guide/mermaid-init.js src/etc/wasm32-shim.js -src/librustdoc/html/static/js/*.js src/librustdoc/html/static/.eslintrc.js +src/librustdoc/html/static/js/*.js src/test/auxiliary/rust_test_helpers.c +src/test/run-make-fulldeps/*/*.c src/test/run-make/*/*.c src/test/run-make/wasm-*/*.js -src/test/run-make-fulldeps/*/*.c -src/test/rustdoc-js/*.js src/test/rustdoc-js-std/*.js -src/tools/rustdoc-js/tester.js +src/test/rustdoc-js/*.js +src/tools/error_index_generator/*.js src/tools/rustdoc-gui/tester.js +src/tools/rustdoc-js/tester.js # Embedded libraries, justified in README.source vendor/dlmalloc/src/dlmalloc.c @@ -129,85 +144,85 @@ src/tools/clippy/.remarkrc vendor/elasticlunr-rs/src/lang/*.rs # False-positive, hand-editable small image -src/etc/installer/gfx/ -src/doc/embedded-book/src/assets/*.png -src/doc/embedded-book/src/assets/*.svg -src/doc/embedded-book/src/assets/f3.jpg -src/doc/embedded-book/src/assets/verify.jpeg -src/doc/nomicon/src/img/safeandunsafe.svg +src/doc/book/2018-edition/src/img/*.png +src/doc/book/2018-edition/src/img/*.svg +src/doc/book/2018-edition/src/img/ferris/*.svg src/doc/book/second-edition/src/img/*.png src/doc/book/second-edition/src/img/*.svg -src/doc/book/src/img/ferris/*.svg src/doc/book/src/img/*.png src/doc/book/src/img/*.svg -src/doc/book/2018-edition/src/img/ferris/*.svg -src/doc/book/2018-edition/src/img/*.svg -src/doc/book/2018-edition/src/img/*.png +src/doc/book/src/img/ferris/*.svg src/doc/book/tools/docx-to-md.xsl -src/doc/rustc/src/images/*.png +src/doc/embedded-book/src/assets/*.png +src/doc/embedded-book/src/assets/*.svg +src/doc/embedded-book/src/assets/f3.jpg +src/doc/embedded-book/src/assets/verify.jpeg +src/doc/nomicon/src/img/safeandunsafe.svg +src/doc/rustc-dev-guide/src/img/*.png src/doc/rustc-dev-guide/src/img/rustc_stages.svg src/doc/rustc-dev-guide/src/queries/example-0.png -src/doc/rustc-dev-guide/src/img/*.png +src/doc/rustc/src/images/*.png +src/etc/installer/gfx/ src/librustdoc/html/static/images/*.svg src/librustdoc/html/static/images/favicon-*.png src/test/mir-opt/coverage_graphviz.*.InstrumentCoverage.0.dot src/tools/rust-analyzer/assets/logo-*.svg -vendor/mdbook/src/theme/favicon.svg vendor/mdbook/src/theme/favicon.png -vendor/pretty_assertions-0.7.2/examples/*.png +vendor/mdbook/src/theme/favicon.svg +vendor/pretty_assertions/examples/*.png # Example code vendor/html5ever/examples/capi/tokenize.c vendor/sysinfo/examples/simple.c # Test data -library/portable-simd/crates/core_simd/webdriver.json +library/core/benches/str.rs +library/core/tests/num/dec2flt/parse.rs library/portable-simd/crates/core_simd/tests/mask_ops_impl/*.rs +library/portable-simd/crates/core_simd/webdriver.json library/std/src/sys/windows/path/tests.rs library/stdarch/ci/gba.json +library/stdarch/crates/std_detect/src/detect/test_data/*.auxv library/stdarch/crates/stdarch-verify/arm-intrinsics.html library/stdarch/crates/stdarch-verify/x86-intel.xml -library/stdarch/crates/std_detect/src/detect/test_data/*.auxv -library/core/benches/str.rs -library/core/tests/num/dec2flt/parse.rs -src/test/debuginfo/type-names.cdb.js -src/test/mir-opt/*.mir -src/test/mir-opt/*.diff -src/test/mir-opt/*/*.mir -src/test/mir-opt/*/*.diff -src/test/rustdoc/tuples.link2_i32.html src/test/*/*.rs -src/test/*/*.stdout -src/test/*/issues/*.rs -src/test/*/*/issue-*.rs -src/test/*/*/issues/*.rs src/test/*/*.stderr -src/test/*/*/*.rs +src/test/*/*.stdout src/test/*/*/*.json +src/test/*/*/*.rs src/test/*/*/*.stderr src/test/*/*/*.stdout -src/test/*/*/*/*.stdout src/test/*/*/*/*.stderr +src/test/*/*/*/*.stdout src/test/*/*/*/*/*.stderr -src/test/run-make/*-sgx-lvi/enclave/*/*/*.c +src/test/*/*/issue-*.rs +src/test/*/*/issues/*.rs +src/test/*/issues/*.rs +src/test/debuginfo/type-names.cdb.js +src/test/mir-opt/*.diff +src/test/mir-opt/*.mir +src/test/mir-opt/*/*.diff +src/test/mir-opt/*/*.mir src/test/run-make/*-sgx-lvi/enclave/*.c +src/test/run-make/*-sgx-lvi/enclave/*/*/*.c src/test/rustdoc/*.html +src/test/rustdoc/tuples.link2_i32.html src/test/ui/macros/not-utf8.bin src/tools/*/tests/*/*.stderr src/tools/clippy/tests/ui-toml/*/*.stderr src/tools/clippy/tests/ui-toml/large_include_file/too_big.txt src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed -src/tools/rustfmt/tests/writemode/target/*.json -src/tools/rustfmt/tests/writemode/target/*.xml -src/tools/rustfmt/tests/source/*.rs -src/tools/rustfmt/tests/source/*/*.rs -src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs src/tools/rust-analyzer/bench_data/numerous_macro_rules -src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs +src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_*.html +src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/* src/tools/rust-analyzer/crates/project-model/test_data/*.json src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt -src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/* -src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_*.html +src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs +src/tools/rustfmt/tests/source/*.rs +src/tools/rustfmt/tests/source/*/*.rs +src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs +src/tools/rustfmt/tests/writemode/target/*.json +src/tools/rustfmt/tests/writemode/target/*.xml vendor/annotate-snippets/tests/fixtures/no-color/strip_line_non_ws.toml vendor/bstr/src/unicode/data/*Test.txt vendor/cargo_metadata*/tests/test_samples.rs @@ -221,6 +236,7 @@ vendor/fluent-syntax/benches/parser.rs vendor/gimli-0*/fixtures/self/* vendor/gimli/fixtures/self/* vendor/gsgdt/tests/*.json +vendor/handlebars/tests/helper_with_space.rs vendor/html5ever/data/bench/*.html vendor/idna/tests/IdnaTest*.txt vendor/idna/tests/punycode_tests.json @@ -245,8 +261,6 @@ vendor/regex/tests/fowler.rs vendor/rustc-demangle/src/lib.rs vendor/rustc-demangle/src/v0-large-test-symbols/early-recursion-limit vendor/serde_json/tests/lexical/parse.rs -vendor/sha-1-0*/tests/data/*.bin -vendor/sha-1-0*/tests/data/*.blb vendor/sha-1/tests/data/*.blb vendor/sha2/tests/data/*.blb vendor/term/tests/data/* @@ -278,101 +292,115 @@ src/librustdoc/html/static/fonts/*.woff2 vendor/bstr/src/unicode/fsm/*.dfa # file brokenness (detected as Algol source code) -vendor/digest/src/core_api/wrapper.rs -vendor/digest/src/core_api/rt_variable.rs +compiler/rustc_apfloat/src/lib.rs +compiler/rustc_driver/src/lib.rs +compiler/rustc_expand/src/mbe/quoted.rs +compiler/rustc_macros/src/symbols/tests.rs +library/std/src/sys/unix/process/process_unix.rs +library/stdarch/crates/stdarch-verify/src/lib.rs +src/librustdoc/html/markdown/tests.rs +src/test/run-make-fulldeps/symbol-visibility/Makefile +src/test/ui/proc-macro/auxiliary/*.rs +src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +src/tools/clippy/src/docs/from_str_radix_10.txt +src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs +src/tools/rustfmt/src/formatting.rs +src/tools/rustfmt/src/parse/parser.rs +src/tools/rustfmt/src/string.rs vendor/ahash/src/hash_quality_test.rs +vendor/ahash/src/lib.rs +vendor/aho-corasick/src/nfa.rs +vendor/askama_shared/src/generator.rs +vendor/block-buffer/tests/mod.rs vendor/clap/src/derive.rs +vendor/compiler_builtins/libm/src/math/atan.rs +vendor/datafrog/src/lib.rs +vendor/digest/src/core_api/rt_variable.rs +vendor/digest/src/core_api/wrapper.rs +vendor/digest/src/dev.rs +vendor/env_logger-0.*/src/fmt/writer/mod.rs +vendor/env_logger/src/fmt/writer/mod.rs +vendor/flate2/src/mem.rs +vendor/flate2/src/zio.rs +vendor/futures-macro/src/lib.rs vendor/futures-macro/src/select.rs -vendor/nom/src/error.rs -vendor/nom/src/internal.rs +vendor/gimli-0.25.0/src/read/aranges.rs +vendor/gimli-0.25.0/src/read/line.rs +vendor/gimli-0.25.0/src/read/loclists.rs +vendor/gimli-0.25.0/src/read/lookup.rs +vendor/gimli-0.25.0/src/read/rnglists.rs +vendor/gimli-0.25.0/src/read/unit.rs +vendor/gimli/src/read/aranges.rs +vendor/gimli/src/read/line.rs +vendor/gimli/src/read/loclists.rs +vendor/gimli/src/read/lookup.rs +vendor/gimli/src/read/rnglists.rs +vendor/gimli/src/read/unit.rs +vendor/indoc/src/lib.rs +vendor/libm/src/math/atan.rs +vendor/miniz_oxide-0.4.0/src/deflate/mod.rs +vendor/miniz_oxide-0.4.0/src/inflate/mod.rs +vendor/miniz_oxide/src/deflate/mod.rs +vendor/miniz_oxide/src/inflate/mod.rs +vendor/nom/src/bits/complete.rs vendor/nom/src/bits/mod.rs vendor/nom/src/bits/streaming.rs -vendor/nom/src/bits/complete.rs -vendor/nom/src/bytes/streaming.rs -vendor/nom/src/bytes/complete.rs vendor/nom/src/branch/mod.rs vendor/nom/src/branch/tests.rs -vendor/nom/src/multi/tests.rs +vendor/nom/src/bytes/complete.rs +vendor/nom/src/bytes/streaming.rs +vendor/nom/src/character/complete.rs +vendor/nom/src/character/streaming.rs +vendor/nom/src/combinator/mod.rs +vendor/nom/src/combinator/tests.rs +vendor/nom/src/error.rs +vendor/nom/src/internal.rs vendor/nom/src/multi/mod.rs +vendor/nom/src/multi/tests.rs vendor/nom/src/number/complete.rs vendor/nom/src/number/streaming.rs -vendor/nom/src/combinator/tests.rs -vendor/nom/src/character/streaming.rs -vendor/nom/src/character/complete.rs vendor/nom/src/sequence/mod.rs -vendor/nom/tests/multiline.rs vendor/nom/tests/css.rs -vendor/askama_shared/src/generator.rs -vendor/block-buffer/tests/mod.rs -src/tools/rustfmt/src/parse/parser.rs -vendor/libm/src/math/atan.rs -vendor/pest/tests/calculator.rs -vendor/pest/src/position.rs +vendor/nom/tests/issues.rs +vendor/nom/tests/json.rs +vendor/nom/tests/mp4.rs +vendor/nom/tests/multiline.rs vendor/pest/src/parser_state.rs +vendor/pest/src/position.rs vendor/pest/src/span.rs -vendor/aho-corasick/src/nfa.rs -vendor/miniz_oxide/src/deflate/mod.rs -vendor/miniz_oxide/src/inflate/mod.rs -vendor/miniz_oxide-0.4.0/src/deflate/mod.rs -vendor/miniz_oxide-0.4.0/src/inflate/mod.rs -vendor/thiserror-impl/src/attr.rs -vendor/shlex/src/lib.rs -vendor/semver/src/parse.rs -vendor/rustc-rayon/tests/sort-panic-safe.rs -vendor/url/src/parser.rs -vendor/utf-8/tests/unit.rs -vendor/rustversion/src/attr.rs -vendor/env_logger/src/fmt/writer/mod.rs -vendor/env_logger-0.*/src/fmt/writer/mod.rs +vendor/pest/tests/calculator.rs vendor/pest_generator/src/generator.rs -vendor/digest/src/dev.rs vendor/proc-macro2/src/parse.rs -vendor/xz2/src/stream.rs -vendor/xz2/src/bufread.rs -vendor/digest-0.8.1/src/dev.rs -vendor/pulldown-cmark/tests/lib.rs -vendor/pulldown-cmark/src/linklabel.rs vendor/pulldown-cmark/benches/html_rendering.rs -vendor/gimli/src/read/aranges.rs -vendor/gimli/src/read/rnglists.rs -vendor/gimli/src/read/unit.rs -vendor/gimli/src/read/loclists.rs -vendor/gimli/src/read/line.rs -vendor/gimli/src/read/lookup.rs -vendor/gimli-0.25.0/src/read/aranges.rs -vendor/gimli-0.25.0/src/read/rnglists.rs -vendor/gimli-0.25.0/src/read/unit.rs -vendor/gimli-0.25.0/src/read/loclists.rs -vendor/gimli-0.25.0/src/read/line.rs -vendor/gimli-0.25.0/src/read/lookup.rs -vendor/regex-automata/src/regex.rs +vendor/pulldown-cmark/src/linklabel.rs +vendor/pulldown-cmark/tests/lib.rs vendor/rayon/tests/sort-panic-safe.rs -vendor/syn/tests/test_meta.rs -vendor/syn/src/punctuated.rs -vendor/syn/src/derive.rs -vendor/syn/src/token.rs +vendor/regex-automata/src/regex.rs +vendor/rustc-rayon/tests/sort-panic-safe.rs +vendor/rustversion/src/attr.rs +vendor/rustversion/src/lib.rs +vendor/semver/src/parse.rs +vendor/sha2/src/sha256.rs +vendor/sha2/src/sha512.rs +vendor/shlex/src/lib.rs +vendor/snap/src/compress.rs +vendor/snap/src/decompress.rs +vendor/syn/src/attr.rs +vendor/syn/src/custom_punctuation.rs vendor/syn/src/data.rs -vendor/syn/src/ty.rs -vendor/syn/src/stmt.rs +vendor/syn/src/derive.rs +vendor/syn/src/group.rs vendor/syn/src/pat.rs -vendor/syn/src/custom_punctuation.rs vendor/syn/src/path.rs -vendor/syn/src/attr.rs -vendor/syn/src/group.rs -vendor/sha2/src/sha512.rs -vendor/sha2/src/sha256.rs -vendor/compiler_builtins/libm/src/math/atan.rs -vendor/snap/src/decompress.rs -vendor/snap/src/compress.rs -vendor/flate2/src/mem.rs -vendor/flate2/src/zio.rs -compiler/rustc_expand/src/mbe/quoted.rs -compiler/rustc_macros/src/symbols/tests.rs -src/librustdoc/html/markdown/tests.rs -src/test/run-make-fulldeps/symbol-visibility/Makefile -src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs -src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs -src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs -src/tools/rustfmt/src/string.rs -src/tools/rustfmt/src/formatting.rs -library/std/src/sys/unix/process/process_unix.rs +vendor/syn/src/punctuated.rs +vendor/syn/src/stmt.rs +vendor/syn/src/token.rs +vendor/syn/src/ty.rs +vendor/syn/tests/test_meta.rs +vendor/thiserror-impl/src/attr.rs +vendor/url/src/parser.rs +vendor/utf-8/benches/from_utf8_lossy.rs +vendor/utf-8/tests/unit.rs +vendor/xz2/src/bufread.rs +vendor/xz2/src/stream.rs diff --git a/git-commit-hash b/git-commit-hash index 7cc889ca0..19793c62f 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52 \ No newline at end of file +897e37553bba8b42751c67658967889d11ecd120 \ No newline at end of file diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index cc8da7bcc..80b067812 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -30,13 +30,13 @@ extern "Rust" { #[rustc_allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_deallocator)] + #[rustc_deallocator] #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[cfg_attr(not(bootstrap), rustc_reallocator)] + #[rustc_reallocator] #[rustc_allocator_nounwind] fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_allocator_zeroed)] + #[rustc_allocator_zeroed] #[rustc_allocator_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/src/alloc/tests.rs index 7d560964d..b2f019459 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/src/alloc/tests.rs @@ -15,7 +15,7 @@ fn allocate_zeroed() { let end = i.add(layout.size()); while i < end { assert_eq!(*i, 0); - i = i.offset(1); + i = i.add(1); } Global.deallocate(ptr.as_non_null_ptr(), layout); } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index c1ceeb0de..65e323c9e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1,4 +1,4 @@ -//! A pointer type for heap allocation. +//! The `Box` type for heap allocation. //! //! [`Box`], casually referred to as a 'box', provides the simplest form of //! heap allocation in Rust. Boxes provide ownership for this allocation, and @@ -151,6 +151,8 @@ use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::convert::{From, TryFrom}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; @@ -174,6 +176,9 @@ use crate::borrow::Cow; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; @@ -1480,7 +1485,7 @@ impl From<&[T]> for Box<[T]> { /// Converts a `&[T]` into a `Box<[T]>` /// /// This conversion allocates on the heap - /// and performs a copy of `slice`. + /// and performs a copy of `slice` and its contents. /// /// # Examples /// ```rust @@ -2085,3 +2090,304 @@ impl AsyncIterator for Box { (**self).size_hint() } } + +#[cfg(not(bootstrap))] +impl dyn Error { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + if self.is::() { + unsafe { + let raw: *mut dyn Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send + Sync { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send + Sync` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + Sync + 'a> From for Box { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: String) -> Box { + struct StringError(String); + + impl Error for StringError { + #[allow(deprecated)] + fn description(&self) -> &str { + &self.0 + } + } + + impl fmt::Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + // Purposefully skip printing "StringError(..)" + impl fmt::Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; + err2 + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a, 'b> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'b, str>) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'a, str>) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "box_error", since = "1.8.0")] +impl core::error::Error for Box { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } +} diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 649ccfcaa..0a20c74b0 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -2,6 +2,8 @@ // https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs // by matthieu-m use crate::alloc::{self, Layout, LayoutError}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] @@ -271,3 +273,11 @@ impl WithHeader { Layout::new::().extend(value_layout) } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "thin_box", issue = "92791")] +impl Error for ThinBox { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.deref().source() + } +} diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 197e7aaac..4583bc9a1 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1010,7 +1010,8 @@ impl BinaryHeap { /// current length. The allocator may reserve more space to speculatively /// avoid frequent allocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// diff --git a/library/alloc/src/collections/btree/dedup_sorted_iter.rs b/library/alloc/src/collections/btree/dedup_sorted_iter.rs index 60bf83b83..17ee78045 100644 --- a/library/alloc/src/collections/btree/dedup_sorted_iter.rs +++ b/library/alloc/src/collections/btree/dedup_sorted_iter.rs @@ -3,7 +3,9 @@ use core::iter::Peekable; /// A iterator for deduping the key of a sorted iterator. /// When encountering the duplicated key, only the last key-value pair is yielded. /// -/// Used by [`BTreeMap::bulk_build_from_sorted_iter`]. +/// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1]. +/// +/// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter pub struct DedupSortedIter where I: Iterator, diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index b6eecf9b0..cd7cdc192 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -133,6 +133,17 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error + for crate::collections::btree_map::OccupiedError<'a, K, V> +{ + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index d831161bc..f1d2d3b30 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -318,7 +318,7 @@ impl NodeRef pub fn ascend( self, ) -> Result, marker::Edge>, Self> { - assert!(BorrowType::PERMITS_TRAVERSAL); + let _ = BorrowType::TRAVERSAL_PERMIT; // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut, // there might be outstanding mutable references to values that we must not invalidate. let leaf_ptr: *const _ = Self::as_leaf_ptr(&self); @@ -1003,7 +1003,7 @@ impl /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { - assert!(BorrowType::PERMITS_TRAVERSAL); + let _ = BorrowType::TRAVERSAL_PERMIT; // We need to use raw pointers to nodes because, if BorrowType is // marker::ValMut, there might be outstanding mutable references to // values that we must not invalidate. There's no worry accessing the @@ -1666,15 +1666,17 @@ pub mod marker { pub struct ValMut<'a>(PhantomData<&'a mut ()>); pub trait BorrowType { - // Whether node references of this borrow type allow traversing - // to other nodes in the tree. - const PERMITS_TRAVERSAL: bool = true; + // If node references of this borrow type allow traversing to other + // nodes in the tree, this constant can be evaluated. Thus reading it + // serves as a compile-time assertion. + const TRAVERSAL_PERMIT: () = (); } impl BorrowType for Owned { - // Traversal isn't needed, it happens using the result of `borrow_mut`. + // Reject evaluation, because traversal isn't needed. Instead traversal + // happens using the result of `borrow_mut`. // By disabling traversal, and only creating new references to roots, // we know that every reference of the `Owned` type is to a root node. - const PERMITS_TRAVERSAL: bool = false; + const TRAVERSAL_PERMIT: () = panic!(); } impl BorrowType for Dying {} impl<'a> BorrowType for Immut<'a> {} diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index e21c8aa3b..6480fcaf9 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1570,7 +1570,7 @@ impl<'a, T> CursorMut<'a, T> { /// that the cursor points to is unchanged, even if it is the "ghost" node. /// /// This operation should compute in *O*(1) time. - // `push_front` continues to point to "ghost" when it addes a node to mimic + // `push_front` continues to point to "ghost" when it adds a node to mimic // the behavior of `insert_before` on an empty list. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn push_front(&mut self, elt: T) { diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 628a5b155..21d0def08 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -152,3 +152,7 @@ trait SpecExtend { /// Extends `self` with the contents of the given iterator. fn spec_extend(&mut self, iter: I); } + +#[cfg(not(bootstrap))] +#[stable(feature = "try_reserve", since = "1.57.0")] +impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 05f94da6d..41baa7102 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -1,10 +1,12 @@ +use core::fmt; use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem::{self, MaybeUninit}; use core::ptr::{self, NonNull}; -use core::{fmt, mem}; use crate::alloc::{Allocator, Global}; -use super::{count, Iter, VecDeque}; +use super::{count, wrap_index, VecDeque}; /// A draining iterator over the elements of a `VecDeque`. /// @@ -20,18 +22,24 @@ pub struct Drain< > { after_tail: usize, after_head: usize, - iter: Iter<'a, T>, + ring: NonNull<[T]>, + tail: usize, + head: usize, deque: NonNull>, + _phantom: PhantomData<&'a T>, } impl<'a, T, A: Allocator> Drain<'a, T, A> { pub(super) unsafe fn new( after_tail: usize, after_head: usize, - iter: Iter<'a, T>, + ring: &'a [MaybeUninit], + tail: usize, + head: usize, deque: NonNull>, ) -> Self { - Drain { after_tail, after_head, iter, deque } + let ring = unsafe { NonNull::new_unchecked(ring as *const [MaybeUninit] as *mut _) }; + Drain { after_tail, after_head, ring, tail, head, deque, _phantom: PhantomData } } } @@ -41,7 +49,9 @@ impl fmt::Debug for Drain<'_, T, A> { f.debug_tuple("Drain") .field(&self.after_tail) .field(&self.after_head) - .field(&self.iter) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -118,12 +128,21 @@ impl Iterator for Drain<'_, T, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt) }) + if self.tail == self.head { + return None; + } + let tail = self.tail; + self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); + // Safety: + // - `self.tail` in a ring buffer is always a valid index. + // - `self.head` and `self.tail` equality is checked above. + unsafe { Some(ptr::read(self.ring.as_ptr().get_unchecked_mut(tail))) } } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + let len = count(self.tail, self.head, self.ring.len()); + (len, Some(len)) } } @@ -131,7 +150,14 @@ impl Iterator for Drain<'_, T, A> { impl DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option { - self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) + if self.tail == self.head { + return None; + } + self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); + // Safety: + // - `self.head` in a ring buffer is always a valid index. + // - `self.head` and `self.tail` equality is checked above. + unsafe { Some(ptr::read(self.ring.as_ptr().get_unchecked_mut(self.head))) } } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 4d895d837..e3f4deb08 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -794,7 +794,8 @@ impl VecDeque { /// in the given deque. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// @@ -1333,9 +1334,8 @@ impl VecDeque { // it. We do not write to `self` nor reborrow to a mutable reference. // Hence the raw pointer we created above, for `deque`, remains valid. let ring = self.buffer_as_slice(); - let iter = Iter::new(ring, drain_tail, drain_head); - Drain::new(drain_head, head, iter, deque) + Drain::new(drain_head, head, ring, drain_tail, drain_head, deque) } } @@ -2447,8 +2447,8 @@ impl VecDeque { let mut right_offset = 0; for i in left_edge..right_edge { right_offset = (i - left_edge) % (cap - right_edge); - let src: isize = (right_edge + right_offset) as isize; - ptr::swap(buf.add(i), buf.offset(src)); + let src = right_edge + right_offset; + ptr::swap(buf.add(i), buf.add(src)); } let n_ops = right_edge - left_edge; left_edge += n_ops; diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index ae61b1f1e..aede6d54c 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -436,9 +436,9 @@ impl CString { /// /// unsafe { /// assert_eq!(b'f', *ptr as u8); - /// assert_eq!(b'o', *ptr.offset(1) as u8); - /// assert_eq!(b'o', *ptr.offset(2) as u8); - /// assert_eq!(b'\0', *ptr.offset(3) as u8); + /// assert_eq!(b'o', *ptr.add(1) as u8); + /// assert_eq!(b'o', *ptr.add(2) as u8); + /// assert_eq!(b'\0', *ptr.add(3) as u8); /// /// // retake pointer to free memory /// let _ = CString::from_raw(ptr); @@ -1121,3 +1121,29 @@ impl CStr { CString::from(self) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl core::error::Error for NulError { + #[allow(deprecated)] + fn description(&self) -> &str { + "nul byte found in data" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +impl core::error::Error for FromVecWithNulError {} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_into", since = "1.7.0")] +impl core::error::Error for IntoStringError { + #[allow(deprecated)] + fn description(&self) -> &str { + "C string contained non-utf8 bytes" + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + Some(self.__source()) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 8b6f40548..8619467c2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,10 +56,6 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell -// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be -// able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -77,6 +73,10 @@ ))] #![no_std] #![needs_allocator] +// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // // Lints: #![deny(unsafe_op_in_unsafe_fn)] @@ -111,6 +111,8 @@ #![feature(const_pin)] #![feature(cstr_from_bytes_until_nul)] #![feature(dispatch_from_dyn)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] +#![cfg_attr(not(bootstrap), feature(error_in_core))] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(fmt_internals)] @@ -127,10 +129,12 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] #![feature(pointer_byte_offsets)] +#![cfg_attr(not(bootstrap), feature(provide_any))] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] #![feature(receiver_trait)] +#![feature(saturating_int_impl)] #![feature(set_ptr_value)] #![feature(slice_from_ptr_range)] #![feature(slice_group_by)] @@ -145,6 +149,7 @@ #![feature(unchecked_math)] #![feature(unicode_internals)] #![feature(unsize)] +#![feature(utf8_chunks)] #![feature(std_internals)] // // Language features: @@ -164,7 +169,7 @@ #![cfg_attr(not(test), feature(generator_trait))] #![feature(hashmap_internals)] #![feature(lang_items)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] @@ -178,6 +183,7 @@ #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(c_unwind)] +#![feature(with_negative_coherence)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 88eb6aa7a..5198bf297 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -107,6 +107,8 @@ macro_rules! vec { /// format!("test"); /// format!("hello {}", "world!"); /// format!("x = {}, y = {y}", 10, y = 30); +/// let (x, y) = (1, 2); +/// format!("{x} + {y} = 3"); /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index b89b03683..6d247681c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1142,7 +1142,7 @@ impl Rc { /// be cloned. /// /// See also [`get_mut`], which will fail rather than cloning the inner value - /// or diassociating [`Weak`] pointers. + /// or disassociating [`Weak`] pointers. /// /// [`clone`]: Clone::clone /// [`get_mut`]: Rc::get_mut diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 63d4d9452..bcd3f49e2 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -1,82 +1,12 @@ -//! A dynamically-sized view into a contiguous sequence, `[T]`. +//! Utilities for the slice primitive type. //! //! *[See also the slice primitive type](slice).* //! -//! Slices are a view into a block of memory represented as a pointer and a -//! length. +//! Most of the structs in this module are iterator types which can only be created +//! using a certain function. For example, `slice.iter()` yields an [`Iter`]. //! -//! ``` -//! // slicing a Vec -//! let vec = vec![1, 2, 3]; -//! let int_slice = &vec[..]; -//! // coercing an array to a slice -//! let str_slice: &[&str] = &["one", "two", "three"]; -//! ``` -//! -//! Slices are either mutable or shared. The shared slice type is `&[T]`, -//! while the mutable slice type is `&mut [T]`, where `T` represents the element -//! type. For example, you can mutate the block of memory that a mutable slice -//! points to: -//! -//! ``` -//! let x = &mut [1, 2, 3]; -//! x[1] = 7; -//! assert_eq!(x, &[1, 7, 3]); -//! ``` -//! -//! Here are some of the things this module contains: -//! -//! ## Structs -//! -//! There are several structs that are useful for slices, such as [`Iter`], which -//! represents iteration over a slice. -//! -//! ## Trait Implementations -//! -//! There are several implementations of common traits for slices. Some examples -//! include: -//! -//! * [`Clone`] -//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`]. -//! * [`Hash`] - for slices whose element type is [`Hash`]. -//! -//! ## Iteration -//! -//! The slices implement `IntoIterator`. The iterator yields references to the -//! slice elements. -//! -//! ``` -//! let numbers = &[0, 1, 2]; -//! for n in numbers { -//! println!("{n} is a number!"); -//! } -//! ``` -//! -//! The mutable slice yields mutable references to the elements: -//! -//! ``` -//! let mut scores = [7, 8, 9]; -//! for score in &mut scores[..] { -//! *score += 1; -//! } -//! ``` -//! -//! This iterator yields mutable references to the slice's elements, so while -//! the element type of the slice is `i32`, the element type of the iterator is -//! `&mut i32`. -//! -//! * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default -//! iterators. -//! * Further methods that return iterators are [`.split`], [`.splitn`], -//! [`.chunks`], [`.windows`] and more. -//! -//! [`Hash`]: core::hash::Hash -//! [`.iter`]: slice::iter -//! [`.iter_mut`]: slice::iter_mut -//! [`.split`]: slice::split -//! [`.splitn`]: slice::splitn -//! [`.chunks`]: slice::chunks -//! [`.windows`]: slice::windows +//! A few functions are provided to create a slice from a value reference +//! or from a raw pointer. #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. // It's cleaner to just turn off the unused_imports warning than to fix them. @@ -1024,7 +954,7 @@ where // Consume the greater side. // If equal, prefer the right run to maintain stability. unsafe { - let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) { + let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { decrement_and_get(left) } else { decrement_and_get(right) @@ -1038,12 +968,12 @@ where unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { let old = *ptr; - *ptr = unsafe { ptr.offset(1) }; + *ptr = unsafe { ptr.add(1) }; old } unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { - *ptr = unsafe { ptr.offset(-1) }; + *ptr = unsafe { ptr.sub(1) }; *ptr } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index d5ed2c4ad..b28d20cda 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -1,26 +1,6 @@ -//! Unicode string slices. +//! Utilities for the `str` primitive type. //! //! *[See also the `str` primitive type](str).* -//! -//! The `&str` type is one of the two main string types, the other being `String`. -//! Unlike its `String` counterpart, its contents are borrowed. -//! -//! # Basic Usage -//! -//! A basic string declaration of `&str` type: -//! -//! ``` -//! let hello_world = "Hello, World!"; -//! ``` -//! -//! Here we have declared a string literal, also known as a string slice. -//! String literals have a static lifetime, which means the string `hello_world` -//! is guaranteed to be valid for the duration of the entire program. -//! We can explicitly specify `hello_world`'s lifetime as well: -//! -//! ``` -//! let hello_world: &'static str = "Hello, world!"; -//! ``` #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -71,6 +51,8 @@ pub use core::str::{RSplit, Split}; pub use core::str::{RSplitN, SplitN}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitTerminator, SplitTerminator}; +#[unstable(feature = "utf8_chunks", issue = "99543")] +pub use core::str::{Utf8Chunk, Utf8Chunks}; /// Note: `str` in `Concat` is not meaningful here. /// This type parameter of the trait only exists to enable another impl. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index a5118e533..f2448396c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -44,6 +44,8 @@ #[cfg(not(no_global_oom_handling))] use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::hash; use core::iter::FusedIterator; @@ -58,9 +60,9 @@ use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr; use core::slice; -#[cfg(not(no_global_oom_handling))] -use core::str::lossy; use core::str::pattern::Pattern; +#[cfg(not(no_global_oom_handling))] +use core::str::Utf8Chunks; #[cfg(not(no_global_oom_handling))] use crate::borrow::{Cow, ToOwned}; @@ -628,11 +630,11 @@ impl String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { - let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks(); + let mut iter = Utf8Chunks::new(v); let first_valid = if let Some(chunk) = iter.next() { - let lossy::Utf8LossyChunk { valid, broken } = chunk; - if broken.is_empty() { + let valid = chunk.valid(); + if chunk.invalid().is_empty() { debug_assert_eq!(valid.len(), v.len()); return Cow::Borrowed(valid); } @@ -647,9 +649,9 @@ impl String { res.push_str(first_valid); res.push_str(REPLACEMENT); - for lossy::Utf8LossyChunk { valid, broken } in iter { - res.push_str(valid); - if !broken.is_empty() { + for chunk in iter { + res.push_str(chunk.valid()); + if !chunk.invalid().is_empty() { res.push_str(REPLACEMENT); } } @@ -1080,7 +1082,8 @@ impl String { /// current length. The allocator may reserve more space to speculatively /// avoid frequent allocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// @@ -1938,6 +1941,24 @@ impl fmt::Display for FromUtf16Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-16" + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4c03cc3ed..4377edeee 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2763,3 +2763,25 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } + +#[cfg(not(bootstrap))] +#[stable(feature = "arc_error", since = "1.52.0")] +impl core::error::Error for Arc { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } + + fn provide<'a>(&'a self, req: &mut core::any::Demand<'a>) { + core::error::Error::provide(&**self, req); + } +} diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 202d0e7f0..0fae8953a 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -618,3 +618,22 @@ fn test_arc_cyclic_two_refs() { assert_eq!(Arc::strong_count(&two_refs), 3); assert_eq!(Arc::weak_count(&two_refs), 2); } + +/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) +#[test] +#[cfg(miri)] // relies on Stacked Borrows in Miri +fn arc_drop_dereferenceable_race() { + // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). + for _ in 0..750 { + let arc_1 = Arc::new(()); + let arc_2 = arc_1.clone(); + let thread = thread::spawn(|| drop(arc_2)); + // Spin a bit; makes the race more likely to appear + let mut i = 0; + while i < 256 { + i += 1; + } + drop(arc_1); + thread.join().unwrap(); + } +} diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index 5cdee0bd4..5b73906a1 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -1,7 +1,7 @@ use crate::alloc::{Allocator, Global}; use core::fmt; use core::iter::{FusedIterator, TrustedLen}; -use core::mem; +use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use core::slice::{self}; @@ -65,6 +65,77 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> { pub fn allocator(&self) -> &A { unsafe { self.vec.as_ref().allocator() } } + + /// Keep unyielded elements in the source `Vec`. + /// + /// # Examples + /// + /// ``` + /// #![feature(drain_keep_rest)] + /// + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain(..); + /// + /// assert_eq!(drain.next().unwrap(), 'a'); + /// + /// // This call keeps 'b' and 'c' in the vec. + /// drain.keep_rest(); + /// + /// // If we wouldn't call `keep_rest()`, + /// // `vec` would be empty. + /// assert_eq!(vec, ['b', 'c']); + /// ``` + #[unstable(feature = "drain_keep_rest", issue = "101122")] + pub fn keep_rest(self) { + // At this moment layout looks like this: + // + // [head] [yielded by next] [unyielded] [yielded by next_back] [tail] + // ^-- start \_________/-- unyielded_len \____/-- self.tail_len + // ^-- unyielded_ptr ^-- tail + // + // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`. + // Here we want to + // 1. Move [unyielded] to `start` + // 2. Move [tail] to a new start at `start + len(unyielded)` + // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)` + // a. In case of ZST, this is the only thing we want to do + // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do + let mut this = ManuallyDrop::new(self); + + unsafe { + let source_vec = this.vec.as_mut(); + + let start = source_vec.len(); + let tail = this.tail_start; + + let unyielded_len = this.iter.len(); + let unyielded_ptr = this.iter.as_slice().as_ptr(); + + // ZSTs have no identity, so we don't need to move them around. + let needs_move = mem::size_of::() != 0; + + if needs_move { + let start_ptr = source_vec.as_mut_ptr().add(start); + + // memmove back unyielded elements + if unyielded_ptr != start_ptr { + let src = unyielded_ptr; + let dst = start_ptr; + + ptr::copy(src, dst, unyielded_len); + } + + // memmove back untouched tail + if tail != (start + unyielded_len) { + let src = source_vec.as_ptr().add(tail); + let dst = start_ptr.add(unyielded_len); + ptr::copy(src, dst, this.tail_len); + } + } + + source_vec.set_len(start + unyielded_len + this.tail_len); + } + } } #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] diff --git a/library/alloc/src/vec/drain_filter.rs b/library/alloc/src/vec/drain_filter.rs index 3c37c92ae..8c03f1692 100644 --- a/library/alloc/src/vec/drain_filter.rs +++ b/library/alloc/src/vec/drain_filter.rs @@ -1,6 +1,7 @@ use crate::alloc::{Allocator, Global}; -use core::ptr::{self}; -use core::slice::{self}; +use core::mem::{self, ManuallyDrop}; +use core::ptr; +use core::slice; use super::Vec; @@ -54,6 +55,61 @@ where pub fn allocator(&self) -> &A { self.vec.allocator() } + + /// Keep unyielded elements in the source `Vec`. + /// + /// # Examples + /// + /// ``` + /// #![feature(drain_filter)] + /// #![feature(drain_keep_rest)] + /// + /// let mut vec = vec!['a', 'b', 'c']; + /// let mut drain = vec.drain_filter(|_| true); + /// + /// assert_eq!(drain.next().unwrap(), 'a'); + /// + /// // This call keeps 'b' and 'c' in the vec. + /// drain.keep_rest(); + /// + /// // If we wouldn't call `keep_rest()`, + /// // `vec` would be empty. + /// assert_eq!(vec, ['b', 'c']); + /// ``` + #[unstable(feature = "drain_keep_rest", issue = "101122")] + pub fn keep_rest(self) { + // At this moment layout looks like this: + // + // _____________________/-- old_len + // / \ + // [kept] [yielded] [tail] + // \_______/ ^-- idx + // \-- del + // + // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`) + // + // 1. Move [tail] after [kept] + // 2. Update length of the original vec to `old_len - del` + // a. In case of ZST, this is the only thing we want to do + // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do + let mut this = ManuallyDrop::new(self); + + unsafe { + // ZSTs have no identity, so we don't need to move them around. + let needs_move = mem::size_of::() != 0; + + if needs_move && this.idx < this.old_len && this.del > 0 { + let ptr = this.vec.as_mut_ptr(); + let src = ptr.add(this.idx); + let dst = src.sub(this.del); + let tail_len = this.old_len - this.idx; + src.copy_to(dst, tail_len); + } + + let new_len = this.old_len - this.del; + this.vec.set_len(new_len); + } + } } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 55dcb84ad..b211421b2 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -267,7 +267,7 @@ where // one slot in the underlying storage will have been freed up and we can immediately // write back the result. unsafe { - let dst = dst_buf.offset(i as isize); + let dst = dst_buf.add(i); debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation"); ptr::write(dst, self.__iterator_get_unchecked(i)); // Since this executes user code which can panic we have to bump the pointer diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 1b483e3fc..b4157fd58 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -4,7 +4,6 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; use core::array; use core::fmt; -use core::intrinsics::arith_offset; use core::iter::{ FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, }; @@ -148,19 +147,19 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - if self.ptr as *const _ == self.end { + if self.ptr == self.end { None } else if mem::size_of::() == 0 { // purposefully don't use 'ptr.offset' because for // vectors with 0-size elements this would return the // same pointer. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; + self.ptr = self.ptr.wrapping_byte_add(1); // Make up a value of this ZST. Some(unsafe { mem::zeroed() }) } else { let old = self.ptr; - self.ptr = unsafe { self.ptr.offset(1) }; + self.ptr = unsafe { self.ptr.add(1) }; Some(unsafe { ptr::read(old) }) } @@ -184,7 +183,7 @@ impl Iterator for IntoIter { // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound // effectively results in unsigned pointers representing positions 0..usize::MAX, // which is valid for ZSTs. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } + self.ptr = self.ptr.wrapping_byte_add(step_size); } else { // SAFETY: the min() above ensures that step_size is in bounds self.ptr = unsafe { self.ptr.add(step_size) }; @@ -217,7 +216,7 @@ impl Iterator for IntoIter { return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) }); } - self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T }; + self.ptr = self.ptr.wrapping_byte_add(N); // Safety: ditto return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) }); } @@ -267,12 +266,12 @@ impl DoubleEndedIterator for IntoIter { None } else if mem::size_of::() == 0 { // See above for why 'ptr.offset' isn't used - self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; + self.end = self.end.wrapping_byte_sub(1); // Make up a value of this ZST. Some(unsafe { mem::zeroed() }) } else { - self.end = unsafe { self.end.offset(-1) }; + self.end = unsafe { self.end.sub(1) }; Some(unsafe { ptr::read(self.end) }) } @@ -283,12 +282,10 @@ impl DoubleEndedIterator for IntoIter { let step_size = self.len().min(n); if mem::size_of::() == 0 { // SAFETY: same as for advance_by() - self.end = unsafe { - arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T - } + self.end = self.end.wrapping_byte_sub(step_size); } else { // SAFETY: same as for advance_by() - self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; + self.end = unsafe { self.end.sub(step_size) }; } let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); // SAFETY: same as for advance_by() diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 92a32779b..2e025c8a4 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -1,3 +1,5 @@ +use core::num::{Saturating, Wrapping}; + use crate::boxed::Box; #[rustc_specialization_trait] @@ -144,3 +146,17 @@ impl_is_zero_option_of_nonzero!( NonZeroUsize, NonZeroIsize, ); + +unsafe impl IsZero for Wrapping { + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +unsafe impl IsZero for Saturating { + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index fa9f2131c..60b36af5e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -59,7 +59,7 @@ use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; -use core::intrinsics::{arith_offset, assume}; +use core::intrinsics::assume; use core::iter; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; @@ -436,7 +436,7 @@ impl Vec { /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// - /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// If it is important to know the exact allocated capacity of a `Vec`, /// always use the [`capacity`] method after construction. /// /// For `Vec` where `T` is a zero-sized type, there will be no allocation @@ -542,8 +542,8 @@ impl Vec { /// /// unsafe { /// // Overwrite memory with 4, 5, 6 - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); + /// for i in 0..len { + /// ptr::write(p.add(i), 4 + i); /// } /// /// // Put everything back together into a Vec @@ -591,7 +591,7 @@ impl Vec { /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// - /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// If it is important to know the exact allocated capacity of a `Vec`, /// always use the [`capacity`] method after construction. /// /// For `Vec` where `T` is a zero-sized type, there will be no allocation @@ -702,8 +702,8 @@ impl Vec { /// /// unsafe { /// // Overwrite memory with 4, 5, 6 - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); + /// for i in 0..len { + /// ptr::write(p.add(i), 4 + i); /// } /// /// // Put everything back together into a Vec @@ -875,7 +875,8 @@ impl Vec { /// in the given `Vec`. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// @@ -1393,7 +1394,7 @@ impl Vec { if index < len { // Shift everything over to make space. (Duplicating the // `index`th element into two consecutive places.) - ptr::copy(p, p.offset(1), len - index); + ptr::copy(p, p.add(1), len - index); } else if index == len { // No elements need shifting. } else { @@ -1455,7 +1456,7 @@ impl Vec { ret = ptr::read(ptr); // Shift everything down to fill in that spot. - ptr::copy(ptr.offset(1), ptr, len - index - 1); + ptr::copy(ptr.add(1), ptr, len - index - 1); } self.set_len(len - 1); ret @@ -2408,7 +2409,7 @@ impl Vec { // Write all elements except the last one for _ in 1..n { ptr::write(ptr, value.next()); - ptr = ptr.offset(1); + ptr = ptr.add(1); // Increment the length in every step in case next() panics local_len.increment_len(1); } @@ -2677,7 +2678,7 @@ impl IntoIterator for Vec { let alloc = ManuallyDrop::new(ptr::read(me.allocator())); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { - arith_offset(begin as *const i8, me.len() as isize) as *const T + begin.wrapping_byte_add(me.len()) } else { begin.add(me.len()) as *const T }; @@ -2927,6 +2928,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] impl const Default for Vec { /// Creates an empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. fn default() -> Vec { Vec::new() } diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 506ee0ecf..1ea9c827a 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -39,7 +39,7 @@ where let mut local_len = SetLenOnDrop::new(&mut self.len); iterator.for_each(move |element| { ptr::write(ptr, element); - ptr = ptr.offset(1); + ptr = ptr.add(1); // Since the loop executes user code which can panic we have to bump the pointer // after each step. // NB can't overflow since we would have had to alloc the address space diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index d83cd29dd..490c0d8f7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -38,11 +38,13 @@ #![feature(const_str_from_utf8)] #![feature(nonnull_slice_from_raw_parts)] #![feature(panic_update_hook)] +#![feature(pointer_is_aligned)] #![feature(slice_flatten)] #![feature(thin_box)] #![feature(bench_black_box)] #![feature(strict_provenance)] #![feature(once_cell)] +#![feature(drain_keep_rest)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 7379569dd..e30329aa1 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1010,11 +1010,11 @@ fn test_as_bytes_fail() { fn test_as_ptr() { let buf = "hello".as_ptr(); unsafe { - assert_eq!(*buf.offset(0), b'h'); - assert_eq!(*buf.offset(1), b'e'); - assert_eq!(*buf.offset(2), b'l'); - assert_eq!(*buf.offset(3), b'l'); - assert_eq!(*buf.offset(4), b'o'); + assert_eq!(*buf.add(0), b'h'); + assert_eq!(*buf.add(1), b'e'); + assert_eq!(*buf.add(2), b'l'); + assert_eq!(*buf.add(3), b'l'); + assert_eq!(*buf.add(4), b'o'); } } diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index b6836fdc8..99d1296a4 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -693,12 +693,6 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = usize::BITS < 64; - { // Note: basic stuff is checked by test_reserve let mut empty_string: String = String::new(); @@ -712,35 +706,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX + 1 is an OOM - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - // Check usize::MAX is an OOM - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -753,19 +731,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -785,8 +757,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = usize::BITS < 64; - { let mut empty_string: String = String::new(); @@ -799,31 +769,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -839,19 +795,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs index 368aa564f..e008b0cc3 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloc/tests/thin_box.rs @@ -48,11 +48,11 @@ fn verify_aligned(ptr: *const T) { // practice these checks are mostly just smoke-detectors for an extremely // broken `ThinBox` impl, since it's an extremely subtle piece of code. let ptr = core::hint::black_box(ptr); - let align = core::mem::align_of::(); assert!( - (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(), - "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}", - core::any::type_name::(), + ptr.is_aligned() && !ptr.is_null(), + "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}", + ty = core::any::type_name::(), + align = core::mem::align_of::(), ); } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index b797e2375..f140fc414 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -293,6 +293,22 @@ fn test_retain() { assert_eq!(vec, [2, 4]); } +#[test] +fn test_retain_predicate_order() { + for to_keep in [true, false] { + let mut number_of_executions = 0; + let mut vec = vec![1, 2, 3, 4]; + let mut next_expected = 1; + vec.retain(|&x| { + assert_eq!(next_expected, x); + next_expected += 1; + number_of_executions += 1; + to_keep + }); + assert_eq!(number_of_executions, 4); + } +} + #[test] fn test_retain_pred_panic_with_hole() { let v = (0..5).map(Rc::new).collect::>(); @@ -354,6 +370,35 @@ fn test_retain_drop_panic() { assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); } +#[test] +fn test_retain_maybeuninits() { + // This test aimed to be run under miri. + use core::mem::MaybeUninit; + let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into(); + vec.retain(|x| { + // SAFETY: Retain must visit every element of Vec in original order and exactly once. + // Our values is initialized at creation of Vec. + let v = unsafe { x.assume_init_ref()[0] }; + if v & 1 == 0 { + return true; + } + // SAFETY: Value is initialized. + // Value wouldn't be dropped by `Vec::retain` + // because `MaybeUninit` doesn't drop content. + drop(unsafe { x.assume_init_read() }); + false + }); + let vec: Vec = vec + .into_iter() + .map(|x| unsafe { + // SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`. + // Remaining values are initialized. + x.assume_init()[0] + }) + .collect(); + assert_eq!(vec, [2, 4]); +} + #[test] fn test_dedup() { fn case(a: Vec, b: Vec) { @@ -794,6 +839,36 @@ fn test_drain_leak() { assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); } +#[test] +fn test_drain_keep_rest() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain(1..6); + assert_eq!(drain.next(), Some(1)); + assert_eq!(drain.next_back(), Some(5)); + assert_eq!(drain.next(), Some(2)); + + drain.keep_rest(); + assert_eq!(v, &[0, 3, 4, 6]); +} + +#[test] +fn test_drain_keep_rest_all() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + v.drain(1..6).keep_rest(); + assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]); +} + +#[test] +fn test_drain_keep_rest_none() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain(1..6); + + drain.by_ref().for_each(drop); + + drain.keep_rest(); + assert_eq!(v, &[0, 6]); +} + #[test] fn test_splice() { let mut v = vec![1, 2, 3, 4, 5]; @@ -1029,6 +1104,12 @@ fn test_into_iter_drop_allocator() { assert_eq!(drop_count, 2); } +#[test] +fn test_into_iter_zst() { + for _ in vec![[0u64; 0]].into_iter() {} + for _ in vec![[0u64; 0]; 5].into_iter().rev() {} +} + #[test] fn test_from_iter_specialization() { let src: Vec = vec![0usize; 1]; @@ -1488,6 +1569,35 @@ fn drain_filter_unconsumed() { assert_eq!(vec, [2, 4]); } +#[test] +fn test_drain_filter_keep_rest() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain_filter(|&mut x| x % 2 == 0); + assert_eq!(drain.next(), Some(0)); + assert_eq!(drain.next(), Some(2)); + + drain.keep_rest(); + assert_eq!(v, &[1, 3, 4, 5, 6]); +} + +#[test] +fn test_drain_filter_keep_rest_all() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + v.drain_filter(|_| true).keep_rest(); + assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]); +} + +#[test] +fn test_drain_filter_keep_rest_none() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain_filter(|_| true); + + drain.by_ref().for_each(drop); + + drain.keep_rest(); + assert_eq!(v, &[]); +} + #[test] fn test_reserve_exact() { // This is all the same as test_reserve @@ -1527,12 +1637,6 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = usize::BITS < 64; - { // Note: basic stuff is checked by test_reserve let mut empty_bytes: Vec = Vec::new(); @@ -1546,35 +1650,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX + 1 is an OOM - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - // Check usize::MAX is an OOM - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1587,19 +1675,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1620,19 +1702,13 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1652,8 +1728,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::() < 8; - { let mut empty_bytes: Vec = Vec::new(); @@ -1666,31 +1740,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1706,19 +1766,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1739,19 +1793,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 89cc7f905..019d73c0b 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,7 +2,6 @@ use std::assert_matches::assert_matches; use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; -use std::mem::size_of; use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -1161,12 +1160,6 @@ fn test_try_reserve() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; - { // Note: basic stuff is checked by test_reserve let mut empty_bytes: VecDeque = VecDeque::new(); @@ -1180,31 +1173,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX is an OOM - // VecDeque starts with capacity 7, always adds 1 to the capacity - // and also rounds the number to next power of 2 so this is the - // furthest we can go without triggering CapacityOverflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1217,19 +1198,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1250,19 +1225,13 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1282,8 +1251,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::() < 8; - { let mut empty_bytes: VecDeque = VecDeque::new(); @@ -1296,29 +1263,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX is an OOM - // VecDeque starts with capacity 7, always adds 1 to the capacity - // and also rounds the number to next power of 2 so this is the - // furthest we can go without triggering CapacityOverflow - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1334,19 +1289,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1367,19 +1316,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/backtrace/.github/workflows/main.yml b/library/backtrace/.github/workflows/main.yml index 5f4bd505b..c11b08dfd 100644 --- a/library/backtrace/.github/workflows/main.yml +++ b/library/backtrace/.github/workflows/main.yml @@ -33,8 +33,6 @@ jobs: rust: stable-i686-msvc - os: windows-latest rust: stable-x86_64-gnu - - os: windows-latest - rust: stable-i686-gnu steps: - uses: actions/checkout@v1 with: @@ -244,4 +242,4 @@ jobs: rustup toolchain install nightly --component miri rustup override set nightly cargo miri setup - - run: MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-strict-provenance" cargo miri test + - run: MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test diff --git a/library/backtrace/Cargo.toml b/library/backtrace/Cargo.toml index 2881c8e8f..ef1c5ec00 100644 --- a/library/backtrace/Cargo.toml +++ b/library/backtrace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "backtrace" -version = "0.3.65" +version = "0.3.66" authors = ["The Rust Project Developers"] build = "build.rs" license = "MIT/Apache-2.0" @@ -44,7 +44,7 @@ addr2line = { version = "0.17.0", default-features = false } miniz_oxide = { version = "0.5.0", default-features = false } [dependencies.object] -version = "0.28.0" +version = "0.29.0" default-features = false features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] diff --git a/library/backtrace/src/backtrace/miri.rs b/library/backtrace/src/backtrace/miri.rs index 9a5f65b80..f8c496428 100644 --- a/library/backtrace/src/backtrace/miri.rs +++ b/library/backtrace/src/backtrace/miri.rs @@ -91,7 +91,7 @@ pub fn resolve_addr(ptr: *mut c_void) -> Frame { } } -pub unsafe fn trace_unsynchronized bool>(mut cb: F) { +unsafe fn trace_unsynchronized bool>(mut cb: F) { let len = miri_backtrace_size(0); let mut frames = Vec::with_capacity(len); @@ -102,6 +102,8 @@ pub unsafe fn trace_unsynchronized bool>(mut cb: F) { for ptr in frames.iter() { let frame = resolve_addr(*ptr as *mut c_void); - cb(&super::Frame { inner: frame }); + if !cb(&super::Frame { inner: frame }) { + return; + } } } diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs index 19864d2d4..3c01e2998 100644 --- a/library/core/benches/num/int_log/mod.rs +++ b/library/core/benches/num/int_log/mod.rs @@ -9,7 +9,7 @@ macro_rules! int_log_bench { for n in 0..(<$t>::BITS / 8) { for i in 1..=(100 as $t) { let x = black_box(i << (n * 8)); - black_box(x.log10()); + black_box(x.ilog10()); } } }); @@ -27,7 +27,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } @@ -44,7 +44,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 887246c60..6756eecd0 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -74,7 +74,7 @@ use crate::ptr; /// { /// return null_mut(); /// }; -/// (self.arena.get() as *mut u8).add(allocated) +/// self.arena.get().cast::().add(allocated) /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2f378836c..f03502429 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -1,4 +1,12 @@ +// Seemingly inconsequential code changes to this file can lead to measurable +// performance impact on compilation times, due at least in part to the fact +// that the layout code gets called from many instantiations of the various +// collections, resulting in having to optimize down excess IR multiple times. +// Your performance intuition is useless. Run perf. + use crate::cmp; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::mem::{self, ValidAlign}; use crate::ptr::NonNull; @@ -52,8 +60,8 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e., the rounded value must be less than - /// or equal to `usize::MAX`). + /// must not overflow isize (i.e., the rounded value must be + /// less than or equal to `isize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] @@ -62,6 +70,12 @@ impl Layout { return Err(LayoutError); } + // SAFETY: just checked that align is a power of two. + Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) }) + } + + #[inline(always)] + const fn max_size_for_align(align: ValidAlign) -> usize { // (power-of-two implies align != 0.) // Rounded up size is: @@ -76,13 +90,18 @@ impl Layout { // // Above implies that checking for summation overflow is both // necessary and sufficient. - if size > usize::MAX - (align - 1) { + isize::MAX as usize - (align.as_usize() - 1) + } + + /// Internal helper constructor to skip revalidating alignment validity. + #[inline] + const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result { + if size > Self::max_size_for_align(align) { return Err(LayoutError); } - // SAFETY: the conditions for `from_size_align_unchecked` have been - // checked above. - unsafe { Ok(Layout::from_size_align_unchecked(size, align)) } + // SAFETY: Layout::size invariants checked above. + Ok(Layout { size, align }) } /// Creates a layout, bypassing all checks. @@ -96,8 +115,8 @@ impl Layout { #[must_use] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - // SAFETY: the caller must ensure that `align` is a power of two. - Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } } + // SAFETY: the caller is required to uphold the preconditions. + unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } } } /// The minimum size in bytes for a memory block of this layout. @@ -116,7 +135,7 @@ impl Layout { without modifying the layout"] #[inline] pub const fn align(&self) -> usize { - self.align.as_nonzero().get() + self.align.as_usize() } /// Constructs a `Layout` suitable for holding a value of type `T`. @@ -126,10 +145,9 @@ impl Layout { #[inline] pub const fn new() -> Self { let (size, align) = size_align::(); - // SAFETY: the align is guaranteed by Rust to be a power of two and - // the size+align combo is guaranteed to fit in our address space. As a - // result use the unchecked constructor here to avoid inserting code - // that panics if it isn't optimized well enough. + // SAFETY: if the type is instantiated, rustc already ensures that its + // layout is valid. Use the unchecked constructor to avoid inserting a + // panicking codepath that needs to be optimized out. unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -141,7 +159,6 @@ impl Layout { #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -176,7 +193,6 @@ impl Layout { pub unsafe fn for_value_raw(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -276,12 +292,11 @@ impl Layout { let pad = self.padding_needed_for(self.align()); // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let new_size = self.size() + pad; - // SAFETY: self.align is already known to be valid and new_size has been - // padded already. + // SAFETY: padded size is guaranteed to not exceed `isize::MAX`. unsafe { Layout::from_size_align_unchecked(new_size, self.align()) } } @@ -298,14 +313,13 @@ impl Layout { pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; - // SAFETY: self.align is already known to be valid and alloc_size has been - // padded already. - unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) } + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -356,13 +370,14 @@ impl Layout { #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { - let new_align = cmp::max(self.align(), next.align()); + let new_align = cmp::max(self.align, next.align); let pad = self.padding_needed_for(next.align()); let offset = self.size().checked_add(pad).ok_or(LayoutError)?; let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?; - let layout = Layout::from_size_align(new_size, new_align)?; + // The safe constructor is called here to enforce the isize size limit. + let layout = Layout::from_size_valid_align(new_size, new_align)?; Ok((layout, offset)) } @@ -382,7 +397,8 @@ impl Layout { #[inline] pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutError)?; - Layout::from_size_align(size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(size, self.align) } /// Creates a layout describing the record for `self` followed by @@ -395,26 +411,39 @@ impl Layout { #[inline] pub fn extend_packed(&self, next: Self) -> Result { let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; - Layout::from_size_align(new_size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(new_size, self.align) } /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `LayoutError`. + /// On arithmetic overflow or when the total size would exceed + /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn array(n: usize) -> Result { - let array_size = mem::size_of::().checked_mul(n).ok_or(LayoutError)?; - - // SAFETY: - // - Size: `array_size` cannot be too big because `size_of::()` must - // be a multiple of `align_of::()`. Therefore, `array_size` - // rounded up to the nearest multiple of `align_of::()` is just - // `array_size`. And `array_size` cannot be too big because it was - // just checked by the `checked_mul()`. - // - Alignment: `align_of::()` will always give an acceptable - // (non-zero, power of two) alignment. - Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::()) }) + // Reduce the amount of code we need to monomorphize per `T`. + return inner(mem::size_of::(), ValidAlign::of::(), n); + + #[inline] + fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result { + // We need to check two things about the size: + // - That the total size won't overflow a `usize`, and + // - That the total size still fits in an `isize`. + // By using division we can check them both with a single threshold. + // That'd usually be a bad idea, but thankfully here the element size + // and alignment are constants, so the compiler will fold all of it. + if element_size != 0 && n > Layout::max_size_for_align(align) / element_size { + return Err(LayoutError); + } + + let array_size = element_size * n; + + // SAFETY: We just checked above that the `array_size` will not + // exceed `isize::MAX` even when rounded up to the alignment. + // And `ValidAlign` guarantees it's a power of two. + unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) } + } } } @@ -434,6 +463,10 @@ pub type LayoutErr = LayoutError; #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutError; +#[cfg(not(bootstrap))] +#[stable(feature = "alloc_layout", since = "1.28.0")] +impl Error for LayoutError {} + // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutError { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6cc6e359e..94efa7666 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -21,6 +21,8 @@ pub use self::layout::LayoutErr; #[stable(feature = "alloc_layout_error", since = "1.50.0")] pub use self::layout::LayoutError; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::ptr::{self, NonNull}; @@ -32,6 +34,14 @@ use crate::ptr::{self, NonNull}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; +#[cfg(not(bootstrap))] +#[unstable( + feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838" +)] +impl Error for AllocError {} + // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocError { diff --git a/library/core/src/any.rs b/library/core/src/any.rs index f20c497a1..1a379ecc1 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -1,7 +1,4 @@ -//! This module contains the `Any` trait, which enables dynamic typing -//! of any `'static` type through runtime reflection. It also contains the -//! `Provider` trait and accompanying API, which enable trait objects to provide -//! data based on typed requests, an alternate form of runtime reflection. +//! Utilities for dynamic typing or type reflection. //! //! # `Any` and `TypeId` //! @@ -799,7 +796,7 @@ pub trait Provider { /// impl Provider for SomeConcreteType { /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { /// demand.provide_ref::(&self.field) - /// .provide_value::(|| self.num_field); + /// .provide_value::(self.num_field); /// } /// } /// ``` @@ -884,28 +881,55 @@ impl<'a> Demand<'a> { /// /// # Examples /// + /// Provides an `u8`. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// # struct SomeConcreteType { field: u8 } + /// + /// impl Provider for SomeConcreteType { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand.provide_value::(self.field); + /// } + /// } + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn provide_value(&mut self, value: T) -> &mut Self + where + T: 'static, + { + self.provide::>(value) + } + + /// Provide a value or other type with only static lifetimes computed using a closure. + /// + /// # Examples + /// /// Provides a `String` by cloning. /// /// ```rust - /// # #![feature(provide_any)] + /// #![feature(provide_any)] + /// /// use std::any::{Provider, Demand}; /// # struct SomeConcreteType { field: String } /// /// impl Provider for SomeConcreteType { /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { - /// demand.provide_value::(|| self.field.clone()); + /// demand.provide_value_with::(|| self.field.clone()); /// } /// } /// ``` #[unstable(feature = "provide_any", issue = "96024")] - pub fn provide_value(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self + pub fn provide_value_with(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self where T: 'static, { self.provide_with::>(fulfil) } - /// Provide a reference, note that the referee type must be bounded by `'static`, + /// Provide a reference. The referee type must be bounded by `'static`, /// but may be unsized. /// /// # Examples @@ -913,7 +937,8 @@ impl<'a> Demand<'a> { /// Provides a reference to a field as a `&str`. /// /// ```rust - /// # #![feature(provide_any)] + /// #![feature(provide_any)] + /// /// use std::any::{Provider, Demand}; /// # struct SomeConcreteType { field: String } /// @@ -928,6 +953,40 @@ impl<'a> Demand<'a> { self.provide::>>(value) } + /// Provide a reference computed using a closure. The referee type + /// must be bounded by `'static`, but may be unsized. + /// + /// # Examples + /// + /// Provides a reference to a field as a `&str`. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// # struct SomeConcreteType { business: String, party: String } + /// # fn today_is_a_weekday() -> bool { true } + /// + /// impl Provider for SomeConcreteType { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand.provide_ref_with::(|| { + /// if today_is_a_weekday() { + /// &self.business + /// } else { + /// &self.party + /// } + /// }); + /// } + /// } + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn provide_ref_with( + &mut self, + fulfil: impl FnOnce() -> &'a T, + ) -> &mut Self { + self.provide_with::>>(fulfil) + } + /// Provide a value with the given `Type` tag. fn provide(&mut self, value: I::Reified) -> &mut Self where @@ -949,6 +1008,156 @@ impl<'a> Demand<'a> { } self } + + /// Check if the `Demand` would be satisfied if provided with a + /// value of the specified type. If the type does not match or has + /// already been provided, returns false. + /// + /// # Examples + /// + /// Check if an `u8` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// + /// struct Parent(Option); + /// + /// impl Provider for Parent { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// if let Some(v) = self.0 { + /// demand.provide_value::(v); + /// } + /// } + /// } + /// + /// struct Child { + /// parent: Parent, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option { + /// Some(99) + /// } + /// } + /// + /// impl Provider for Child { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// // In general, we don't know if this call will provide + /// // an `u8` value or not... + /// self.parent.provide(demand); + /// + /// // ...so we check to see if the `u8` is needed before + /// // we run our expensive computation. + /// if demand.would_be_satisfied_by_value_of::() { + /// if let Some(v) = self.an_expensive_computation() { + /// demand.provide_value::(v); + /// } + /// } + /// + /// // The demand will be satisfied now, regardless of if + /// // the parent provided the value or we did. + /// assert!(!demand.would_be_satisfied_by_value_of::()); + /// } + /// } + /// + /// let parent = Parent(Some(42)); + /// let child = Child { parent }; + /// assert_eq!(Some(42), std::any::request_value::(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent }; + /// assert_eq!(Some(99), std::any::request_value::(&child)); + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn would_be_satisfied_by_value_of(&self) -> bool + where + T: 'static, + { + self.would_be_satisfied_by::>() + } + + /// Check if the `Demand` would be satisfied if provided with a + /// reference to a value of the specified type. If the type does + /// not match or has already been provided, returns false. + /// + /// # Examples + /// + /// Check if a `&str` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// + /// struct Parent(Option); + /// + /// impl Provider for Parent { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// if let Some(v) = &self.0 { + /// demand.provide_ref::(v); + /// } + /// } + /// } + /// + /// struct Child { + /// parent: Parent, + /// name: String, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option<&str> { + /// Some(&self.name) + /// } + /// } + /// + /// impl Provider for Child { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// // In general, we don't know if this call will provide + /// // a `str` reference or not... + /// self.parent.provide(demand); + /// + /// // ...so we check to see if the `&str` is needed before + /// // we run our expensive computation. + /// if demand.would_be_satisfied_by_ref_of::() { + /// if let Some(v) = self.an_expensive_computation() { + /// demand.provide_ref::(v); + /// } + /// } + /// + /// // The demand will be satisfied now, regardless of if + /// // the parent provided the reference or we did. + /// assert!(!demand.would_be_satisfied_by_ref_of::()); + /// } + /// } + /// + /// let parent = Parent(Some("parent".into())); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("parent"), std::any::request_ref::(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("child"), std::any::request_ref::(&child)); + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn would_be_satisfied_by_ref_of(&self) -> bool + where + T: ?Sized + 'static, + { + self.would_be_satisfied_by::>>() + } + + fn would_be_satisfied_by(&self) -> bool + where + I: tags::Type<'a>, + { + matches!(self.0.downcast::(), Some(TaggedOption(None))) + } } #[unstable(feature = "provide_any", issue = "96024")] @@ -1053,6 +1262,21 @@ impl<'a> dyn Erased<'a> + 'a { /// Returns some reference to the dynamic value if it is tagged with `I`, /// or `None` otherwise. #[inline] + fn downcast(&self) -> Option<&TaggedOption<'a, I>> + where + I: tags::Type<'a>, + { + if self.tag_id() == TypeId::of::() { + // SAFETY: Just checked whether we're pointing to an I. + Some(unsafe { &*(self as *const Self).cast::>() }) + } else { + None + } + } + + /// Returns some mutable reference to the dynamic value if it is tagged with `I`, + /// or `None` otherwise. + #[inline] fn downcast_mut(&mut self) -> Option<&mut TaggedOption<'a, I>> where I: tags::Type<'a>, diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 33f7f494e..b2c895f88 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable { )+}; } -// SAFETY: All the ordinary integer types allow all bit patterns as distinct values +// SAFETY: All the ordinary integer types have no padding, and are not pointers. is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -// SAFETY: bool and char have *niches*, but no *padding*, so this is sound +// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this +// is sound is_raw_eq_comparable!(bool, char); -// SAFETY: Similarly, the non-zero types have a niche, but no undef, +// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, // and they compare like their underlying numeric type. is_raw_eq_comparable!( NonZeroU8, diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c9823a136..9effb3790 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -1,4 +1,4 @@ -//! Helper functions and types for fixed-length arrays. +//! Utilities for the array primitive type. //! //! *[See also the array primitive type](array).* @@ -7,6 +7,8 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; @@ -119,6 +121,15 @@ impl fmt::Display for TryFromSliceError { } } +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromSliceError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + impl TryFromSliceError { #[unstable( feature = "array_error_internals", diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index f7a8aa0d9..7667a6508 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -6,6 +6,12 @@ impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. /// + /// Arguments passed to `then_some` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use + /// [`then`], which is lazily evaluated. + /// + /// [`then`]: bool::then + /// /// # Examples /// /// ``` diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index 58eabecf3..8378611eb 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -1,4 +1,4 @@ -//! A module for working with borrowed data. +//! Utilities for working with borrowed data. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 71297acd1..dc8ea66cc 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -1,5 +1,7 @@ //! UTF-8 and UTF-16 decoding iterators +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use super::from_u32_unchecked; @@ -121,3 +123,12 @@ impl fmt::Display for DecodeUtf16Error { write!(f, "unpaired surrogate found: {:x}", self.code) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl Error for DecodeUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "unpaired surrogate found" + } +} diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index eae567cad..b7a63b7c6 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -746,10 +746,19 @@ impl char { /// assert!(!'中'.is_lowercase()); /// assert!(!' '.is_lowercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase(); + /// assert!(!CAPITAL_DELTA_IS_LOWERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_lowercase(self) -> bool { + pub const fn is_lowercase(self) -> bool { match self { 'a'..='z' => true, c => c > '\x7f' && unicode::Lowercase(c), @@ -779,10 +788,19 @@ impl char { /// assert!(!'中'.is_uppercase()); /// assert!(!' '.is_uppercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase(); + /// assert!(CAPITAL_DELTA_IS_UPPERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_uppercase(self) -> bool { + pub const fn is_uppercase(self) -> bool { match self { 'A'..='Z' => true, c => c > '\x7f' && unicode::Uppercase(c), @@ -892,8 +910,7 @@ impl char { /// /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric /// characters, and `No` for other numeric characters) are specified in the [Unicode Character - /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三' - /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`. + /// Database][ucd] [`UnicodeData.txt`]. /// /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'. /// If you want everything including characters with overlapping purposes then you might want to use diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 0df23e7bb..72d63ac4b 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -1,4 +1,6 @@ -//! A character type. +//! Utilities for the `char` primitive type. +//! +//! *[See also the `char` primitive type](primitive@char).* //! //! The `char` type represents a single character. More specifically, since //! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode @@ -36,6 +38,8 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Write}; use crate::iter::FusedIterator; @@ -582,3 +586,7 @@ impl fmt::Display for TryFromCharError { "unicode code point out of range".fmt(fmt) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "u8_from_char", since = "1.59.0")] +impl Error for TryFromCharError {} diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 20bb67687..d9f2d3d64 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1,6 +1,6 @@ -//! Functionality for ordering and comparison. +//! Utilities for comparing and ordering values. //! -//! This module contains various tools for ordering and comparing values. In +//! This module contains various tools for comparing and ordering values. In //! summary: //! //! * [`Eq`] and [`PartialEq`] are traits that allow you to define total and @@ -23,6 +23,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::marker::Destruct; +use crate::marker::StructuralPartialEq; use self::Ordering::*; @@ -38,8 +39,10 @@ use self::Ordering::*; /// /// Implementations must ensure that `eq` and `ne` are consistent with each other: /// -/// - `a != b` if and only if `!(a == b)` -/// (ensured by the default implementation). +/// - `a != b` if and only if `!(a == b)`. +/// +/// The default implementation of `ne` provides this consistency and is almost +/// always sufficient. It should not be overridden without very good reason. /// /// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also /// be consistent with `PartialEq` (see the documentation of those traits for the exact @@ -225,7 +228,8 @@ pub trait PartialEq { #[stable(feature = "rust1", since = "1.0.0")] fn eq(&self, other: &Rhs) -> bool; - /// This method tests for `!=`. + /// This method tests for `!=`. The default implementation is almost always + /// sufficient, and should not be overridden without very good reason. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -335,7 +339,7 @@ pub struct AssertParamIsEq { /// let result = 2.cmp(&1); /// assert_eq!(Ordering::Greater, result); /// ``` -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, Eq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] #[repr(i8)] pub enum Ordering { @@ -881,6 +885,18 @@ pub macro Ord($item:item) { /* compiler built-in */ } +#[stable(feature = "rust1", since = "1.0.0")] +impl StructuralPartialEq for Ordering {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] +impl const PartialEq for Ordering { + #[inline] + fn eq(&self, other: &Self) -> bool { + (*self as i32).eq(&(*other as i32)) + } +} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for Ordering { @@ -1139,11 +1155,7 @@ pub trait PartialOrd: PartialEq { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn le(&self, other: &Rhs) -> bool { - // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`. - // FIXME: The root cause was fixed upstream in LLVM with: - // https://github.com/llvm/llvm-project/commit/9bad7de9a3fb844f1ca2965f35d0c2a3d1e11775 - // Revert this workaround once support for LLVM 12 gets dropped. - !matches!(self.partial_cmp(other), None | Some(Greater)) + matches!(self.partial_cmp(other), Some(Less | Equal)) } /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4ae..05637c166 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,6 +34,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{Hash, Hasher}; @@ -556,6 +558,7 @@ where #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for T { /// Returns the argument unchanged. + #[inline(always)] fn from(t: T) -> T { t } @@ -715,6 +718,14 @@ impl fmt::Display for Infallible { } } +#[cfg(not(bootstrap))] +#[stable(feature = "str_parse_error2", since = "1.8.0")] +impl Error for Infallible { + fn description(&self) -> &str { + match *self {} + } +} + #[stable(feature = "convert_infallible", since = "1.34.0")] impl PartialEq for Infallible { fn eq(&self, _: &Infallible) -> bool { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 1ce00828b..b53cd6074 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -1,4 +1,4 @@ -//! The `Default` trait for types which may have meaningful default values. +//! The `Default` trait for types with a default value. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/error.md b/library/core/src/error.md new file mode 100644 index 000000000..891abebbf --- /dev/null +++ b/library/core/src/error.md @@ -0,0 +1,137 @@ +Interfaces for working with Errors. + +# Error Handling In Rust + +The Rust language provides two complementary systems for constructing / +representing, reporting, propagating, reacting to, and discarding errors. +These responsibilities are collectively known as "error handling." The +components of the first system, the panic runtime and interfaces, are most +commonly used to represent bugs that have been detected in your program. The +components of the second system, `Result`, the error traits, and user +defined types, are used to represent anticipated runtime failure modes of +your program. + +## The Panic Interfaces + +The following are the primary interfaces of the panic system and the +responsibilities they cover: + +* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +* [`PanicInfo`] (Reporting) +* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) + +The following are the primary interfaces of the error system and the +responsibilities they cover: + +* [`Result`] (Propagating, Reacting) +* The [`Error`] trait (Reporting) +* User defined types (Constructing / Representing) +* [`match`] and [`downcast`] (Reacting) +* The question mark operator ([`?`]) (Propagating) +* The partially stable [`Try`] traits (Propagating, Constructing) +* [`Termination`] (Reporting) + +## Converting Errors into Panics + +The panic and error systems are not entirely distinct. Often times errors +that are anticipated runtime failures in an API might instead represent bugs +to a caller. For these situations the standard library provides APIs for +constructing panics with an `Error` as it's source. + +* [`Result::unwrap`] +* [`Result::expect`] + +These functions are equivalent, they either return the inner value if the +`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +as the source. The only difference between them is that with `expect` you +provide a panic error message to be printed alongside the source, whereas +`unwrap` has a default message indicating only that you unwraped an `Err`. + +Of the two, `expect` is generally preferred since its `msg` field allows you +to convey your intent and assumptions which makes tracking down the source +of a panic easier. `unwrap` on the other hand can still be a good fit in +situations where you can trivially show that a piece of code will never +panic, such as `"127.0.0.1".parse::().unwrap()` or early +prototyping. + +# Common Message Styles + +There are two common styles for how people word `expect` messages. Using +the message to present information to users encountering a panic +("expect as error message") or using the message to present information +to developers debugging the panic ("expect as precondition"). + +In the former case the expect message is used to describe the error that +has occurred which is considered a bug. Consider the following example: + +```should_panic +// Read environment variable, panic if it is not present +let path = std::env::var("IMPORTANT_PATH").unwrap(); +``` + +In the "expect as error message" style we would use expect to describe +that the environment variable was not set when it should have been: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` is not set"); +``` + +In the "expect as precondition" style, we would instead describe the +reason we _expect_ the `Result` should be `Ok`. With this style we would +prefer to write: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +``` + +The "expect as error message" style does not work as well with the +default output of the std panic hooks, and often ends up repeating +information that is already communicated by the source error being +unwrapped: + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +``` + +In this example we end up mentioning that an env variable is not set, +followed by our source message that says the env is not present, the +only additional information we're communicating is the name of the +environment variable being checked. + +The "expect as precondition" style instead focuses on source code +readability, making it easier to understand what must have gone wrong in +situations where panics are being used to represent bugs exclusively. +Also, by framing our expect in terms of what "SHOULD" have happened to +prevent the source error, we end up introducing new information that is +independent from our source error. + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +``` + +In this example we are communicating not only the name of the +environment variable that should have been set, but also an explanation +for why it should have been set, and we let the source error display as +a clear contradiction to our expectation. + +**Hint**: If you're having trouble remembering how to phrase +expect-as-precondition style error messages remember to focus on the word +"should" as in "env variable should be set by blah" or "the given binary +should be available and executable by the current user". + +[`panic_any`]: ../../std/panic/fn.panic_any.html +[`PanicInfo`]: crate::panic::PanicInfo +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +[`resume_unwind`]: ../../std/panic/fn.resume_unwind.html +[`downcast`]: crate::error::Error +[`Termination`]: ../../std/process/trait.Termination.html +[`Try`]: crate::ops::Try +[panic hook]: ../../std/panic/fn.set_hook.html +[`set_hook`]: ../../std/panic/fn.set_hook.html +[`take_hook`]: ../../std/panic/fn.take_hook.html +[panic-handler]: +[`match`]: ../../std/keyword.match.html +[`?`]: ../../std/result/index.html#the-question-mark-operator- diff --git a/library/core/src/error.rs b/library/core/src/error.rs new file mode 100644 index 000000000..4a8efe15e --- /dev/null +++ b/library/core/src/error.rs @@ -0,0 +1,508 @@ +#![doc = include_str!("error.md")] +#![unstable(feature = "error_in_core", issue = "none")] + +#[cfg(test)] +mod tests; + +use crate::any::{Demand, Provider, TypeId}; +use crate::fmt::{Debug, Display}; + +/// `Error` is a trait representing the basic expectations for error values, +/// i.e., values of type `E` in [`Result`]. +/// +/// Errors must describe themselves through the [`Display`] and [`Debug`] +/// traits. Error messages are typically concise lowercase sentences without +/// trailing punctuation: +/// +/// ``` +/// let err = "NaN".parse::().unwrap_err(); +/// assert_eq!(err.to_string(), "invalid digit found in string"); +/// ``` +/// +/// Errors may provide cause information. [`Error::source()`] is generally +/// used when errors cross "abstraction boundaries". If one module must report +/// an error that is caused by an error from a lower-level module, it can allow +/// accessing that error via [`Error::source()`]. This makes it possible for the +/// high-level module to provide its own errors while also revealing some of the +/// implementation for debugging. +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[rustc_has_incoherent_inherent_impls] +pub trait Error: Debug + Display { + /// The lower-level source of this error, if any. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// source: SuperErrorSideKick, + /// } + /// + /// impl fmt::Display for SuperError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperError is here!") + /// } + /// } + /// + /// impl Error for SuperError { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// Some(&self.source) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick; + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick {} + /// + /// fn get_super_error() -> Result<(), SuperError> { + /// Err(SuperError { source: SuperErrorSideKick }) + /// } + /// + /// fn main() { + /// match get_super_error() { + /// Err(e) => { + /// println!("Error: {e}"); + /// println!("Caused by: {}", e.source().unwrap()); + /// } + /// _ => println!("No error"), + /// } + /// } + /// ``` + #[stable(feature = "error_source", since = "1.30.0")] + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } + + /// Gets the `TypeId` of `self`. + #[doc(hidden)] + #[unstable( + feature = "error_type_id", + reason = "this is memory-unsafe to override in user code", + issue = "60784" + )] + fn type_id(&self, _: private::Internal) -> TypeId + where + Self: 'static, + { + TypeId::of::() + } + + /// ``` + /// if let Err(e) = "xc".parse::() { + /// // Print `e` itself, no need for description(). + /// eprintln!("Error: {e}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")] + fn description(&self) -> &str { + "description() is deprecated; use Display" + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated( + since = "1.33.0", + note = "replaced by Error::source, which can support downcasting" + )] + #[allow(missing_docs)] + fn cause(&self) -> Option<&dyn Error> { + self.source() + } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand + /// .provide_ref::(&self.backtrace) + /// .provide_ref::(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) {} +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl Provider for E +where + E: Error + ?Sized, +{ + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.provide(demand) + } +} + +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + +#[unstable(feature = "never_type", issue = "35121")] +impl Error for ! {} + +impl<'a> dyn Error + 'a { + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&'a self) -> Option<&'a T> { + core::any::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&'a self) -> Option { + core::any::request_value(self) + } +} + +// Copied from `any.rs`. +impl dyn Error + 'static { + /// Returns `true` if the inner type is the same as `T`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = TypeId::of::(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(private::Internal); + + // Compare both `TypeId`s on equality. + t == concrete + } + + /// Returns some reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&*(self as *const dyn Error as *const T)) } + } else { + None + } + } + + /// Returns some mutable reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) } + } else { + None + } + } +} + +impl dyn Error + 'static + Send { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error + 'static + Send + Sync { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error { + /// Returns an iterator starting with the current error and continuing with + /// recursively calling [`Error::source`]. + /// + /// If you want to omit the current error and only use its sources, + /// use `skip(1)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// + /// // let err : Box = b.into(); // or + /// let err = &b as &(dyn Error); + /// + /// let mut iter = err.sources(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "error_iter", issue = "58520")] + #[inline] + pub fn sources(&self) -> Source<'_> { + // You may think this method would be better in the Error trait, and you'd be right. + // Unfortunately that doesn't work, not because of the object safety rules but because we + // save a reference to self in Sources below as a trait object. If this method was + // declared in Error, then self would have the type &T where T is some concrete type which + // implements Error. We would need to coerce self to have type &dyn Error, but that requires + // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error + // since that would forbid Error trait objects, and we can't put that bound on the method + // because that means the method can't be called on trait objects (we'd also need the + // 'static bound, but that isn't allowed because methods with bounds on Self other than + // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible. + + Source { current: Some(self) } + } +} + +/// An iterator over an [`Error`] and its sources. +/// +/// If you want to omit the initial error and only process +/// its sources, use `skip(1)`. +#[unstable(feature = "error_iter", issue = "58520")] +#[derive(Clone, Debug)] +pub struct Source<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> Iterator for Source<'a> { + type Item = &'a (dyn Error + 'static); + + fn next(&mut self) -> Option { + let current = self.current; + self.current = self.current.and_then(Error::source); + current + } +} + +#[stable(feature = "error_by_ref", since = "1.51.0")] +impl<'a, T: Error + ?Sized> Error for &'a T { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn provide<'b>(&'b self, demand: &mut Demand<'b>) { + Error::provide(&**self, demand); + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for crate::fmt::Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already mutably borrowed" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowMutError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already borrowed" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for crate::char::CharTryFromError { + #[allow(deprecated)] + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl Error for crate::char::ParseCharError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl Error for crate::time::FromFloatSecsError {} + +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for crate::ffi::FromBytesWithNulError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] +impl Error for crate::ffi::FromBytesUntilNulError {} diff --git a/library/core/src/ffi/c_double.md b/library/core/src/ffi/c_double.md index 57f453482..d49e29b6e 100644 --- a/library/core/src/ffi/c_double.md +++ b/library/core/src/ffi/c_double.md @@ -1,6 +1,6 @@ Equivalent to C's `double` type. -This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. +This type will almost always be [`f64`], which is guaranteed to be an [IEEE 754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. -[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[IEEE 754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 [`float`]: c_float diff --git a/library/core/src/ffi/c_float.md b/library/core/src/ffi/c_float.md index 61e2abc05..36374ef43 100644 --- a/library/core/src/ffi/c_float.md +++ b/library/core/src/ffi/c_float.md @@ -1,5 +1,5 @@ Equivalent to C's `float` type. -This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. +This type will almost always be [`f32`], which is guaranteed to be an [IEEE 754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. -[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[IEEE 754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 82e63a7fe..21f80ec02 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -1,7 +1,6 @@ -use crate::ascii; use crate::cmp::Ordering; use crate::ffi::c_char; -use crate::fmt::{self, Write}; +use crate::fmt; use crate::intrinsics; use crate::ops; use crate::slice; @@ -121,10 +120,10 @@ enum FromBytesWithNulErrorKind { } impl FromBytesWithNulError { - fn interior_nul(pos: usize) -> FromBytesWithNulError { + const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - fn not_nul_terminated() -> FromBytesWithNulError { + const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -161,11 +160,7 @@ impl fmt::Display for FromBytesUntilNulError { #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"")?; - for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { - f.write_char(byte as char)?; - } - write!(f, "\"") + write!(f, "\"{}\"", self.to_bytes().escape_ascii()) } } @@ -299,7 +294,8 @@ impl CStr { /// ``` /// #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] - pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { + #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] + pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) => { @@ -348,7 +344,8 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) if nul_pos + 1 == bytes.len() => { @@ -387,6 +384,7 @@ impl CStr { #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] #[rustc_allow_const_fn_unstable(const_eval_select)] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + #[inline] fn rt_impl(bytes: &[u8]) -> &CStr { // Chance at catching some UB at runtime with debug builds. debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); @@ -497,7 +495,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); // SAFETY: to_bytes_with_nul returns slice with length at least 1 unsafe { bytes.get_unchecked(..bytes.len() - 1) } @@ -524,7 +523,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes_with_nul(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } @@ -547,7 +547,8 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 32d1a4e55..7da49b04a 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> { } impl fmt::Write for PadAdapter<'_, '_> { - fn write_str(&mut self, mut s: &str) -> fmt::Result { - while !s.is_empty() { + fn write_str(&mut self, s: &str) -> fmt::Result { + for s in s.split_inclusive('\n') { if self.state.on_newline { self.buf.write_str(" ")?; } - let split = match s.find('\n') { - Some(pos) => { - self.state.on_newline = true; - pos + 1 - } - None => { - self.state.on_newline = false; - s.len() - } - }; - self.buf.write_str(&s[..split])?; - s = &s[split..]; + self.state.on_newline = s.ends_with('\n'); + self.buf.write_str(s)?; } Ok(()) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 372141e09..905212eb3 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -119,6 +119,10 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// + /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying + /// destination encounters some error preventing it from accepting more text; it should + /// generally be propagated rather than handled, at least when implementing formatting traits. + /// /// # Examples /// /// ``` @@ -1815,7 +1819,7 @@ impl<'a> Formatter<'a> { /// write!(formatter, /// "Foo({}{})", /// if self.0 < 0 { '-' } else { '+' }, - /// self.0) + /// self.0.abs()) /// } else { /// write!(formatter, "Foo({})", self.0) /// } @@ -1823,6 +1827,7 @@ impl<'a> Formatter<'a> { /// } /// /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)"); /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] @@ -2562,7 +2567,7 @@ macro_rules! tuple { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index db2a52332..90cb79739 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -5,7 +5,9 @@ use crate::task::{Context, Poll}; /// Creates a future that wraps a function returning [`Poll`]. /// -/// Polling the future delegates to the wrapped function. +/// Polling the future delegates to the wrapped function. If the returned future is pinned, then the +/// captured environment of the wrapped function is also pinned in-place, so as long as the closure +/// does not move out of its captures it can soundly create pinned references to them. /// /// # Examples /// @@ -41,7 +43,7 @@ pub struct PollFn { } #[stable(feature = "future_poll_fn", since = "1.64.0")] -impl Unpin for PollFn {} +impl Unpin for PollFn {} #[stable(feature = "future_poll_fn", since = "1.64.0")] impl fmt::Debug for PollFn { @@ -57,7 +59,8 @@ where { type Output = T; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - (&mut self.f)(cx) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: We are not moving out of the pinned field. + (unsafe { &mut self.get_unchecked_mut().f })(cx) } } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 5974562ac..aa13435e6 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -900,7 +900,7 @@ mod impls { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 81b6d5737..764e27962 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -31,7 +31,7 @@ use crate::intrinsics; /// /// `unreachable_unchecked()` can be used in situations where the compiler /// can't prove invariants that were previously established. Such situations -/// have a higher chance of occuring if those invariants are upheld by +/// have a higher chance of occurring if those invariants are upheld by /// external code that the compiler can't analyze. /// ``` /// fn prepare_inputs(divisors: &mut Vec) { @@ -160,19 +160,16 @@ pub const unsafe fn unreachable_unchecked() -> ! { #[inline] #[stable(feature = "renamed_spin_loop", since = "1.49.0")] pub fn spin_loop() { - #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] + #[cfg(target_arch = "x86")] { - #[cfg(target_arch = "x86")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. - unsafe { crate::arch::x86::_mm_pause() }; - } + // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. + unsafe { crate::arch::x86::_mm_pause() }; + } - #[cfg(target_arch = "x86_64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. - unsafe { crate::arch::x86_64::_mm_pause() }; - } + #[cfg(target_arch = "x86_64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. + unsafe { crate::arch::x86_64::_mm_pause() }; } // RISC-V platform spin loop hint implementation diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cabc5017f..11c75e2c9 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -54,7 +54,9 @@ )] #![allow(missing_docs)] -use crate::marker::{Destruct, DiscriminantKind}; +#[cfg(bootstrap)] +use crate::marker::Destruct; +use crate::marker::DiscriminantKind; use crate::mem; // These imports are used for simplifying intra-doc links @@ -63,7 +65,7 @@ use crate::mem; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place(to_drop: *mut T) { @@ -71,214 +73,6 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { unsafe { crate::ptr::drop_in_place(to_drop) } } -// These have been renamed. -#[cfg(bootstrap)] -extern "rust-intrinsic" { - pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_load(src: *const T) -> T; - pub fn atomic_load_acq(src: *const T) -> T; - pub fn atomic_load_relaxed(src: *const T) -> T; - pub fn atomic_load_unordered(src: *const T) -> T; - pub fn atomic_store(dst: *mut T, val: T); - pub fn atomic_store_rel(dst: *mut T, val: T); - pub fn atomic_store_relaxed(dst: *mut T, val: T); - pub fn atomic_store_unordered(dst: *mut T, val: T); - pub fn atomic_xchg(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acq(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_rel(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_xadd(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acq(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_rel(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_xsub(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acq(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_rel(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_and(dst: *mut T, src: T) -> T; - pub fn atomic_and_acq(dst: *mut T, src: T) -> T; - pub fn atomic_and_rel(dst: *mut T, src: T) -> T; - pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_nand(dst: *mut T, src: T) -> T; - pub fn atomic_nand_acq(dst: *mut T, src: T) -> T; - pub fn atomic_nand_rel(dst: *mut T, src: T) -> T; - pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_or(dst: *mut T, src: T) -> T; - pub fn atomic_or_acq(dst: *mut T, src: T) -> T; - pub fn atomic_or_rel(dst: *mut T, src: T) -> T; - pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_xor(dst: *mut T, src: T) -> T; - pub fn atomic_xor_acq(dst: *mut T, src: T) -> T; - pub fn atomic_xor_rel(dst: *mut T, src: T) -> T; - pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_max(dst: *mut T, src: T) -> T; - pub fn atomic_max_acq(dst: *mut T, src: T) -> T; - pub fn atomic_max_rel(dst: *mut T, src: T) -> T; - pub fn atomic_max_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_max_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_min(dst: *mut T, src: T) -> T; - pub fn atomic_min_acq(dst: *mut T, src: T) -> T; - pub fn atomic_min_rel(dst: *mut T, src: T) -> T; - pub fn atomic_min_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_min_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_umin(dst: *mut T, src: T) -> T; - pub fn atomic_umin_acq(dst: *mut T, src: T) -> T; - pub fn atomic_umin_rel(dst: *mut T, src: T) -> T; - pub fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_umax(dst: *mut T, src: T) -> T; - pub fn atomic_umax_acq(dst: *mut T, src: T) -> T; - pub fn atomic_umax_rel(dst: *mut T, src: T) -> T; - pub fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; - pub fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; - pub fn atomic_fence(); - pub fn atomic_fence_acq(); - pub fn atomic_fence_rel(); - pub fn atomic_fence_acqrel(); - pub fn atomic_singlethreadfence(); - pub fn atomic_singlethreadfence_acq(); - pub fn atomic_singlethreadfence_rel(); - pub fn atomic_singlethreadfence_acqrel(); -} - -// These have been renamed. -#[cfg(bootstrap)] -mod atomics { - pub use super::atomic_cxchg as atomic_cxchg_seqcst_seqcst; - pub use super::atomic_cxchg_acq as atomic_cxchg_acquire_acquire; - pub use super::atomic_cxchg_acq_failrelaxed as atomic_cxchg_acquire_relaxed; - pub use super::atomic_cxchg_acqrel as atomic_cxchg_acqrel_acquire; - pub use super::atomic_cxchg_acqrel_failrelaxed as atomic_cxchg_acqrel_relaxed; - pub use super::atomic_cxchg_failacq as atomic_cxchg_seqcst_acquire; - pub use super::atomic_cxchg_failrelaxed as atomic_cxchg_seqcst_relaxed; - pub use super::atomic_cxchg_rel as atomic_cxchg_release_relaxed; - pub use super::atomic_cxchg_relaxed as atomic_cxchg_relaxed_relaxed; - - pub use super::atomic_cxchgweak as atomic_cxchgweak_seqcst_seqcst; - pub use super::atomic_cxchgweak_acq as atomic_cxchgweak_acquire_acquire; - pub use super::atomic_cxchgweak_acq_failrelaxed as atomic_cxchgweak_acquire_relaxed; - pub use super::atomic_cxchgweak_acqrel as atomic_cxchgweak_acqrel_acquire; - pub use super::atomic_cxchgweak_acqrel_failrelaxed as atomic_cxchgweak_acqrel_relaxed; - pub use super::atomic_cxchgweak_failacq as atomic_cxchgweak_seqcst_acquire; - pub use super::atomic_cxchgweak_failrelaxed as atomic_cxchgweak_seqcst_relaxed; - pub use super::atomic_cxchgweak_rel as atomic_cxchgweak_release_relaxed; - pub use super::atomic_cxchgweak_relaxed as atomic_cxchgweak_relaxed_relaxed; - - pub use super::atomic_load as atomic_load_seqcst; - pub use super::atomic_load_acq as atomic_load_acquire; - pub use super::atomic_load_relaxed; - pub use super::atomic_load_unordered; - - pub use super::atomic_store as atomic_store_seqcst; - pub use super::atomic_store_rel as atomic_store_release; - pub use super::atomic_store_relaxed; - pub use super::atomic_store_unordered; - - pub use super::atomic_xchg as atomic_xchg_seqcst; - pub use super::atomic_xchg_acq as atomic_xchg_acquire; - pub use super::atomic_xchg_acqrel; - pub use super::atomic_xchg_rel as atomic_xchg_release; - pub use super::atomic_xchg_relaxed; - - pub use super::atomic_xadd as atomic_xadd_seqcst; - pub use super::atomic_xadd_acq as atomic_xadd_acquire; - pub use super::atomic_xadd_acqrel; - pub use super::atomic_xadd_rel as atomic_xadd_release; - pub use super::atomic_xadd_relaxed; - - pub use super::atomic_xsub as atomic_xsub_seqcst; - pub use super::atomic_xsub_acq as atomic_xsub_acquire; - pub use super::atomic_xsub_acqrel; - pub use super::atomic_xsub_rel as atomic_xsub_release; - pub use super::atomic_xsub_relaxed; - - pub use super::atomic_and as atomic_and_seqcst; - pub use super::atomic_and_acq as atomic_and_acquire; - pub use super::atomic_and_acqrel; - pub use super::atomic_and_rel as atomic_and_release; - pub use super::atomic_and_relaxed; - - pub use super::atomic_nand as atomic_nand_seqcst; - pub use super::atomic_nand_acq as atomic_nand_acquire; - pub use super::atomic_nand_acqrel; - pub use super::atomic_nand_rel as atomic_nand_release; - pub use super::atomic_nand_relaxed; - - pub use super::atomic_or as atomic_or_seqcst; - pub use super::atomic_or_acq as atomic_or_acquire; - pub use super::atomic_or_acqrel; - pub use super::atomic_or_rel as atomic_or_release; - pub use super::atomic_or_relaxed; - - pub use super::atomic_xor as atomic_xor_seqcst; - pub use super::atomic_xor_acq as atomic_xor_acquire; - pub use super::atomic_xor_acqrel; - pub use super::atomic_xor_rel as atomic_xor_release; - pub use super::atomic_xor_relaxed; - - pub use super::atomic_max as atomic_max_seqcst; - pub use super::atomic_max_acq as atomic_max_acquire; - pub use super::atomic_max_acqrel; - pub use super::atomic_max_rel as atomic_max_release; - pub use super::atomic_max_relaxed; - - pub use super::atomic_min as atomic_min_seqcst; - pub use super::atomic_min_acq as atomic_min_acquire; - pub use super::atomic_min_acqrel; - pub use super::atomic_min_rel as atomic_min_release; - pub use super::atomic_min_relaxed; - - pub use super::atomic_umin as atomic_umin_seqcst; - pub use super::atomic_umin_acq as atomic_umin_acquire; - pub use super::atomic_umin_acqrel; - pub use super::atomic_umin_rel as atomic_umin_release; - pub use super::atomic_umin_relaxed; - - pub use super::atomic_umax as atomic_umax_seqcst; - pub use super::atomic_umax_acq as atomic_umax_acquire; - pub use super::atomic_umax_acqrel; - pub use super::atomic_umax_rel as atomic_umax_release; - pub use super::atomic_umax_relaxed; - - pub use super::atomic_fence as atomic_fence_seqcst; - pub use super::atomic_fence_acq as atomic_fence_acquire; - pub use super::atomic_fence_acqrel; - pub use super::atomic_fence_rel as atomic_fence_release; - - pub use super::atomic_singlethreadfence as atomic_singlethreadfence_seqcst; - pub use super::atomic_singlethreadfence_acq as atomic_singlethreadfence_acquire; - pub use super::atomic_singlethreadfence_acqrel; - pub use super::atomic_singlethreadfence_rel as atomic_singlethreadfence_release; -} - -#[cfg(bootstrap)] -pub use atomics::*; - -#[cfg(not(bootstrap))] extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -945,30 +739,7 @@ extern "rust-intrinsic" { /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. pub fn atomic_singlethreadfence_acqrel(); -} -// These have been renamed. -// -// These are the aliases for the old names. -// To be removed when stdarch and panic_unwind have been updated. -#[cfg(not(bootstrap))] -mod atomics { - pub use super::atomic_cxchg_acqrel_acquire as atomic_cxchg_acqrel; - pub use super::atomic_cxchg_acqrel_relaxed as atomic_cxchg_acqrel_failrelaxed; - pub use super::atomic_cxchg_acquire_acquire as atomic_cxchg_acq; - pub use super::atomic_cxchg_acquire_relaxed as atomic_cxchg_acq_failrelaxed; - pub use super::atomic_cxchg_relaxed_relaxed as atomic_cxchg_relaxed; - pub use super::atomic_cxchg_release_relaxed as atomic_cxchg_rel; - pub use super::atomic_cxchg_seqcst_acquire as atomic_cxchg_failacq; - pub use super::atomic_cxchg_seqcst_relaxed as atomic_cxchg_failrelaxed; - pub use super::atomic_cxchg_seqcst_seqcst as atomic_cxchg; - pub use super::atomic_store_seqcst as atomic_store; -} - -#[cfg(not(bootstrap))] -pub use atomics::*; - -extern "rust-intrinsic" { /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance @@ -1313,7 +1084,7 @@ extern "rust-intrinsic" { /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferrable to + /// Depending on what the code is doing, the following alternatives are preferable to /// pointer-to-integer transmutation: /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a /// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit]. @@ -1463,7 +1234,7 @@ extern "rust-intrinsic" { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] + #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] pub fn transmute(e: T) -> U; @@ -1518,6 +1289,17 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; + /// Masks out bits of the pointer according to a mask. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// Consider using [`pointer::mask`] instead. + #[cfg(not(bootstrap))] + pub fn ptr_mask(ptr: *const T, mask: usize) -> *const T; + /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` @@ -2223,29 +2005,32 @@ extern "rust-intrinsic" { pub fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// See documentation of `<*const T>::sub_ptr` for details. - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; /// See documentation of `<*const T>::guaranteed_eq` for details. + /// Returns `2` if the result is unknown. + /// Returns `1` if the pointers are guaranteed equal + /// Returns `0` if the pointers are guaranteed inequal /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(not(bootstrap))] + pub fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8; + + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(bootstrap)] pub fn ptr_guaranteed_eq(ptr: *const T, other: *const T) -> bool; - /// See documentation of `<*const T>::guaranteed_ne` for details. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(bootstrap)] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; /// Allocates a block of memory at compile time. @@ -2282,7 +2067,8 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. + /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a + /// pointer value. /// Note that this is a stricter criterion than just the *values* being /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. /// @@ -2299,13 +2085,70 @@ extern "rust-intrinsic" { /// `ptr` must point to a vtable. /// The intrinsic will return the size stored in that vtable. - #[cfg(not(bootstrap))] pub fn vtable_size(ptr: *const ()) -> usize; /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. - #[cfg(not(bootstrap))] pub fn vtable_align(ptr: *const ()) -> usize; + + /// Selects which function to call depending on the context. + /// + /// If this function is evaluated at compile-time, then a call to this + /// intrinsic will be replaced with a call to `called_in_const`. It gets + /// replaced with a call to `called_at_rt` otherwise. + /// + /// # Type Requirements + /// + /// The two functions must be both function items. They cannot be function + /// pointers or closures. The first function must be a `const fn`. + /// + /// `arg` will be the tupled arguments that will be passed to either one of + /// the two functions, therefore, both functions must accept the same type of + /// arguments. Both functions must return RET. + /// + /// # Safety + /// + /// The two functions must behave observably equivalent. Safe code in other + /// crates may assume that calling a `const fn` at compile-time and at run-time + /// produces the same result. A function that produces a different result when + /// evaluated at run-time, or has any other observable side-effects, is + /// *unsound*. + /// + /// Here is an example of how this could cause a problem: + /// ```no_run + /// #![feature(const_eval_select)] + /// #![feature(core_intrinsics)] + /// use std::hint::unreachable_unchecked; + /// use std::intrinsics::const_eval_select; + /// + /// // Crate A + /// pub const fn inconsistent() -> i32 { + /// fn runtime() -> i32 { 1 } + /// const fn compiletime() -> i32 { 2 } + /// + /// unsafe { + // // âš  This code violates the required equivalence of `compiletime` + /// // and `runtime`. + /// const_eval_select((), compiletime, runtime) + /// } + /// } + /// + /// // Crate B + /// const X: i32 = inconsistent(); + /// let x = inconsistent(); + /// if x != X { unsafe { unreachable_unchecked(); }} + /// ``` + /// + /// This code causes Undefined Behavior when being run, since the + /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, + /// which violates the principle that a `const fn` must behave the same at + /// compile-time and at run-time. The unsafe code in crate B is fine. + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] + pub fn const_eval_select(arg: ARG, called_in_const: F, called_at_rt: G) -> RET + where + G: FnOnce, + F: FnOnce; } // Some functions are defined here because they accidentally got made @@ -2316,6 +2159,11 @@ extern "rust-intrinsic" { /// Check that the preconditions of an unsafe function are followed, if debug_assertions are on, /// and only at runtime. /// +/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)` +/// where the names specified will be moved into the macro as captured variables, and defines an item +/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics +/// for the function declaractions and can be omitted if there is no generics. +/// /// # Safety /// /// Invoking this macro is only sound if the following code is already UB when the passed @@ -2330,18 +2178,21 @@ extern "rust-intrinsic" { /// the occasional mistake, and this check should help them figure things out. #[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn macro_rules! assert_unsafe_precondition { - ($e:expr) => { + ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => { if cfg!(debug_assertions) { - // Use a closure so that we can capture arbitrary expressions from the invocation - let runtime = || { + // allow non_snake_case to allow capturing const generics + #[allow(non_snake_case)] + #[inline(always)] + fn runtime$(<$($tt)*>)?($($i:$ty),*) { if !$e { // abort instead of panicking to reduce impact on code size ::core::intrinsics::abort(); } - }; - const fn comptime() {} + } + #[allow(non_snake_case)] + const fn comptime$(<$($tt)*>)?($(_:$ty),*) {} - ::core::intrinsics::const_eval_select((), comptime, runtime); + ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime); } }; } @@ -2350,7 +2201,7 @@ pub(crate) use assert_unsafe_precondition; /// Checks whether `ptr` is properly aligned with respect to /// `align_of::()`. pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { - !ptr.is_null() && ptr.addr() % mem::align_of::() == 0 + !ptr.is_null() && ptr.is_aligned() } /// Checks whether the regions of memory starting at `src` and `dst` of size @@ -2365,6 +2216,16 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - diff >= size } +#[cfg(bootstrap)] +pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 { + match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) { + (false, false) => 2, + (true, false) => 1, + (false, true) => 0, + (true, true) => unreachable!(), + } +} + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination must *not* overlap. /// @@ -2420,9 +2281,9 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// dst.reserve(src_len); /// /// unsafe { -/// // The call to offset is always safe because `Vec` will never +/// // The call to add is always safe because `Vec` will never /// // allocate more than `isize::MAX` bytes. -/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let dst_ptr = dst.as_mut_ptr().add(dst_len); /// let src_ptr = src.as_ptr(); /// /// // Truncate `src` without dropping its contents. We do this first, @@ -2451,7 +2312,7 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2464,7 +2325,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us // SAFETY: the safety contract for `copy_nonoverlapping` must be // upheld by the caller. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) => is_aligned_and_not_null(src) && is_aligned_and_not_null(dst) && is_nonoverlapping(src, dst, count) @@ -2538,7 +2399,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2550,7 +2411,8 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](src: *const T, dst: *mut T) => + is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); copy(src, dst, count) } } @@ -2606,7 +2468,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2618,63 +2480,12 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); write_bytes(dst, val, count) } } -/// Selects which function to call depending on the context. -/// -/// If this function is evaluated at compile-time, then a call to this -/// intrinsic will be replaced with a call to `called_in_const`. It gets -/// replaced with a call to `called_at_rt` otherwise. -/// -/// # Type Requirements -/// -/// The two functions must be both function items. They cannot be function -/// pointers or closures. -/// -/// `arg` will be the arguments that will be passed to either one of the -/// two functions, therefore, both functions must accept the same type of -/// arguments. Both functions must return RET. -/// -/// # Safety -/// -/// The two functions must behave observably equivalent. Safe code in other -/// crates may assume that calling a `const fn` at compile-time and at run-time -/// produces the same result. A function that produces a different result when -/// evaluated at run-time, or has any other observable side-effects, is -/// *unsound*. -/// -/// Here is an example of how this could cause a problem: -/// ```no_run -/// #![feature(const_eval_select)] -/// #![feature(core_intrinsics)] -/// use std::hint::unreachable_unchecked; -/// use std::intrinsics::const_eval_select; -/// -/// // Crate A -/// pub const fn inconsistent() -> i32 { -/// fn runtime() -> i32 { 1 } -/// const fn compiletime() -> i32 { 2 } -/// -/// unsafe { -// // âš  This code violates the required equivalence of `compiletime` -/// // and `runtime`. -/// const_eval_select((), compiletime, runtime) -/// } -/// } -/// -/// // Crate B -/// const X: i32 = inconsistent(); -/// let x = inconsistent(); -/// if x != X { unsafe { unreachable_unchecked(); }} -/// ``` -/// -/// This code causes Undefined Behavior when being run, since the -/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, -/// which violates the principle that a `const fn` must behave the same at -/// compile-time and at run-time. The unsafe code in crate B is fine. +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", @@ -2696,6 +2507,7 @@ where called_at_rt.call_once(arg) } +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs new file mode 100644 index 000000000..9b479a9f8 --- /dev/null +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -0,0 +1,182 @@ +use crate::array; +use crate::iter::{ByRefSized, FusedIterator, Iterator}; +use crate::ops::{ControlFlow, NeverShortCircuit, Try}; + +/// An iterator over `N` elements of the iterator at a time. +/// +/// The chunks do not overlap. If `N` does not divide the length of the +/// iterator, then the last up to `N-1` elements will be omitted. +/// +/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks] +/// method on [`Iterator`]. See its documentation for more. +#[derive(Debug, Clone)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub struct ArrayChunks { + iter: I, + remainder: Option>, +} + +impl ArrayChunks +where + I: Iterator, +{ + #[track_caller] + pub(in crate::iter) fn new(iter: I) -> Self { + assert!(N != 0, "chunk size must be non-zero"); + Self { iter, remainder: None } + } + + /// Returns an iterator over the remaining elements of the original iterator + /// that are not going to be returned by this iterator. The returned + /// iterator will yield at most `N-1` elements. + #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + #[inline] + pub fn into_remainder(self) -> Option> { + self.remainder + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl Iterator for ArrayChunks +where + I: Iterator, +{ + type Item = [I::Item; N]; + + #[inline] + fn next(&mut self) -> Option { + self.try_for_each(ControlFlow::Break).break_value() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + + (lower / N, upper.map(|n| n / N)) + } + + #[inline] + fn count(self) -> usize { + self.iter.count() / N + } + + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let mut acc = init; + loop { + match self.iter.next_chunk() { + Ok(chunk) => acc = f(acc, chunk)?, + Err(remainder) => { + // Make sure to not override `self.remainder` with an empty array + // when `next` is called after `ArrayChunks` exhaustion. + self.remainder.get_or_insert(remainder); + + break try { acc }; + } + } + } + } + + fn fold(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl DoubleEndedIterator for ArrayChunks +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value() + } + + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + // We are iterating from the back we need to first handle the remainder. + self.next_back_remainder(); + + let mut acc = init; + let mut iter = ByRefSized(&mut self.iter).rev(); + + // NB remainder is handled by `next_back_remainder`, so + // `next_chunk` can't return `Err` with non-empty remainder + // (assuming correct `I as ExactSizeIterator` impl). + while let Ok(mut chunk) = iter.next_chunk() { + // FIXME: do not do double reverse + // (we could instead add `next_chunk_back` for example) + chunk.reverse(); + acc = f(acc, chunk)? + } + + try { acc } + } + + fn rfold(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } +} + +impl ArrayChunks +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`. + fn next_back_remainder(&mut self) { + // Make sure to not override `self.remainder` with an empty array + // when `next_back` is called after `ArrayChunks` exhaustion. + if self.remainder.is_some() { + return; + } + + // We use the `ExactSizeIterator` implementation of the underlying + // iterator to know how many remaining elements there are. + let rem = self.iter.len() % N; + + // Take the last `rem` elements out of `self.iter`. + let mut remainder = + // SAFETY: `unwrap_err` always succeeds because x % N < N for all x. + unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() }; + + // We used `.rev()` above, so we need to re-reverse the reminder + remainder.as_mut_slice().reverse(); + self.remainder = Some(remainder); + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl FusedIterator for ArrayChunks where I: FusedIterator {} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl ExactSizeIterator for ArrayChunks +where + I: ExactSizeIterator, +{ + #[inline] + fn len(&self) -> usize { + self.iter.len() / N + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.len() < N + } +} diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index cc1e8e8a2..477e7117c 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -1,4 +1,4 @@ -use crate::ops::Try; +use crate::ops::{NeverShortCircuit, Try}; /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics. /// @@ -8,28 +8,31 @@ use crate::ops::Try; #[derive(Debug)] pub struct ByRefSized<'a, I>(pub &'a mut I); +// The following implementations use UFCS-style, rather than trusting autoderef, +// to avoid accidentally calling the `&mut Iterator` implementations. + #[unstable(feature = "std_internals", issue = "none")] impl Iterator for ByRefSized<'_, I> { type Item = I::Item; #[inline] fn next(&mut self) -> Option { - self.0.next() + I::next(self.0) } #[inline] fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() + I::size_hint(self.0) } #[inline] fn advance_by(&mut self, n: usize) -> Result<(), usize> { - self.0.advance_by(n) + I::advance_by(self.0, n) } #[inline] fn nth(&mut self, n: usize) -> Option { - self.0.nth(n) + I::nth(self.0, n) } #[inline] @@ -37,7 +40,8 @@ impl Iterator for ByRefSized<'_, I> { where F: FnMut(B, Self::Item) -> B, { - self.0.fold(init, f) + // `fold` needs ownership, so this can't forward directly. + I::try_fold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] @@ -46,7 +50,7 @@ impl Iterator for ByRefSized<'_, I> { F: FnMut(B, Self::Item) -> R, R: Try, { - self.0.try_fold(init, f) + I::try_fold(self.0, init, f) } } @@ -54,17 +58,17 @@ impl Iterator for ByRefSized<'_, I> { impl DoubleEndedIterator for ByRefSized<'_, I> { #[inline] fn next_back(&mut self) -> Option { - self.0.next_back() + I::next_back(self.0) } #[inline] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - self.0.advance_back_by(n) + I::advance_back_by(self.0, n) } #[inline] fn nth_back(&mut self, n: usize) -> Option { - self.0.nth_back(n) + I::nth_back(self.0, n) } #[inline] @@ -72,7 +76,8 @@ impl DoubleEndedIterator for ByRefSized<'_, I> { where F: FnMut(B, Self::Item) -> B, { - self.0.rfold(init, f) + // `rfold` needs ownership, so this can't forward directly. + I::try_rfold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] @@ -81,6 +86,6 @@ impl DoubleEndedIterator for ByRefSized<'_, I> { F: FnMut(B, Self::Item) -> R, R: Try, { - self.0.try_rfold(init, f) + I::try_rfold(self.0, init, f) } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 15a120e35..307016c26 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,6 +1,6 @@ use crate::fmt; use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. @@ -73,6 +73,21 @@ where { self.inner.fold(init, fold) } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_by(n) + } + + #[inline] + fn count(self) -> usize { + self.inner.count() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -103,6 +118,11 @@ where { self.inner.rfold(init, fold) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_back_by(n) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -214,6 +234,21 @@ where { self.inner.fold(init, fold) } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_by(n) + } + + #[inline] + fn count(self) -> usize { + self.inner.count() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } } #[stable(feature = "iterator_flatten", since = "1.29.0")] @@ -244,6 +279,11 @@ where { self.inner.rfold(init, fold) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_back_by(n) + } } #[stable(feature = "iterator_flatten", since = "1.29.0")] @@ -280,6 +320,144 @@ where } } +impl FlattenCompat +where + I: Iterator>, +{ + /// Folds the inner iterators into an accumulator by applying an operation. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `fold`, `count`, + /// and `last` methods. + #[inline] + fn iter_fold(self, mut acc: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, U) -> Acc, + { + #[inline] + fn flatten( + fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + '_ { + move |acc, iter| fold(acc, iter.into_iter()) + } + + if let Some(iter) = self.frontiter { + acc = fold(acc, iter); + } + + acc = self.iter.fold(acc, flatten(&mut fold)); + + if let Some(iter) = self.backiter { + acc = fold(acc, iter); + } + + acc + } + + /// Folds over the inner iterators as long as the given function returns successfully, + /// always storing the most recent inner iterator in `self.frontiter`. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `try_fold` and + /// `advance_by` methods. + #[inline] + fn iter_try_fold(&mut self, mut acc: Acc, mut fold: Fold) -> R + where + Fold: FnMut(Acc, &mut U) -> R, + R: Try, + { + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try>( + frontiter: &'a mut Option, + fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, iter| fold(acc, frontiter.insert(iter.into_iter())) + } + + if let Some(iter) = &mut self.frontiter { + acc = fold(acc, iter)?; + } + self.frontiter = None; + + acc = self.iter.try_fold(acc, flatten(&mut self.frontiter, &mut fold))?; + self.frontiter = None; + + if let Some(iter) = &mut self.backiter { + acc = fold(acc, iter)?; + } + self.backiter = None; + + try { acc } + } +} + +impl FlattenCompat +where + I: DoubleEndedIterator>, +{ + /// Folds the inner iterators into an accumulator by applying an operation, starting form the + /// back. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `rfold` method. + #[inline] + fn iter_rfold(self, mut acc: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, U) -> Acc, + { + #[inline] + fn flatten( + fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + '_ { + move |acc, iter| fold(acc, iter.into_iter()) + } + + if let Some(iter) = self.backiter { + acc = fold(acc, iter); + } + + acc = self.iter.rfold(acc, flatten(&mut fold)); + + if let Some(iter) = self.frontiter { + acc = fold(acc, iter); + } + + acc + } + + /// Folds over the inner iterators in reverse order as long as the given function returns + /// successfully, always storing the most recent inner iterator in `self.backiter`. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `try_rfold` and + /// `advance_back_by` methods. + #[inline] + fn iter_try_rfold(&mut self, mut acc: Acc, mut fold: Fold) -> R + where + Fold: FnMut(Acc, &mut U) -> R, + R: Try, + { + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try>( + backiter: &'a mut Option, + fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, iter| fold(acc, backiter.insert(iter.into_iter())) + } + + if let Some(iter) = &mut self.backiter { + acc = fold(acc, iter)?; + } + self.backiter = None; + + acc = self.iter.try_rfold(acc, flatten(&mut self.backiter, &mut fold))?; + self.backiter = None; + + if let Some(iter) = &mut self.frontiter { + acc = fold(acc, iter)?; + } + self.frontiter = None; + + try { acc } + } +} + impl Iterator for FlattenCompat where I: Iterator>, @@ -323,99 +501,74 @@ where } #[inline] - fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( - frontiter: &'a mut Option, - fold: &'a mut impl FnMut(Acc, T::Item) -> R, - ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_fold(acc, &mut *fold); - *frontiter = Some(mid); - r - } - } - - if let Some(ref mut front) = self.frontiter { - init = front.try_fold(init, &mut fold)?; + fn flatten>( + mut fold: impl FnMut(Acc, U::Item) -> R, + ) -> impl FnMut(Acc, &mut U) -> R { + move |acc, iter| iter.try_fold(acc, &mut fold) } - self.frontiter = None; - init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?; - self.frontiter = None; - - if let Some(ref mut back) = self.backiter { - init = back.try_fold(init, &mut fold)?; - } - self.backiter = None; - - try { init } + self.iter_try_fold(init, flatten(fold)) } #[inline] - fn fold(self, mut init: Acc, mut fold: Fold) -> Acc + fn fold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn flatten( - fold: &mut impl FnMut(Acc, T::Item) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ { - move |acc, x| x.into_iter().fold(acc, &mut *fold) - } - - if let Some(front) = self.frontiter { - init = front.fold(init, &mut fold); - } - - init = self.iter.fold(init, flatten(&mut fold)); - - if let Some(back) = self.backiter { - init = back.fold(init, &mut fold); + fn flatten( + mut fold: impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc { + move |acc, iter| iter.fold(acc, &mut fold) } - init + self.iter_fold(init, flatten(fold)) } #[inline] #[rustc_inherit_overflow_checks] fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - loop { - if let Some(ref mut front) = self.frontiter { - match front.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } - } - self.frontiter = match self.iter.next() { - Some(iterable) => Some(iterable.into_iter()), - _ => break, + #[inline] + #[rustc_inherit_overflow_checks] + fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { + match iter.advance_by(n) { + Ok(()) => ControlFlow::BREAK, + Err(advanced) => ControlFlow::Continue(n - advanced), } } - self.frontiter = None; - - if let Some(ref mut back) = self.backiter { - match back.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } + match self.iter_try_fold(n, advance) { + ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), + _ => Ok(()), } + } - if rem > 0 { - return Err(n - rem); + #[inline] + fn count(self) -> usize { + #[inline] + #[rustc_inherit_overflow_checks] + fn count(acc: usize, iter: U) -> usize { + acc + iter.count() } - self.backiter = None; + self.iter_fold(0, count) + } + + #[inline] + fn last(self) -> Option { + #[inline] + fn last(last: Option, iter: U) -> Option { + iter.last().or(last) + } - Ok(()) + self.iter_fold(None, last) } } @@ -438,105 +591,53 @@ where } #[inline] - fn try_rfold(&mut self, mut init: Acc, mut fold: Fold) -> R + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( - backiter: &'a mut Option, - fold: &'a mut impl FnMut(Acc, T::Item) -> R, - ) -> impl FnMut(Acc, T) -> R + 'a - where - T::IntoIter: DoubleEndedIterator, - { - move |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_rfold(acc, &mut *fold); - *backiter = Some(mid); - r - } + fn flatten>( + mut fold: impl FnMut(Acc, U::Item) -> R, + ) -> impl FnMut(Acc, &mut U) -> R { + move |acc, iter| iter.try_rfold(acc, &mut fold) } - if let Some(ref mut back) = self.backiter { - init = back.try_rfold(init, &mut fold)?; - } - self.backiter = None; - - init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?; - self.backiter = None; - - if let Some(ref mut front) = self.frontiter { - init = front.try_rfold(init, &mut fold)?; - } - self.frontiter = None; - - try { init } + self.iter_try_rfold(init, flatten(fold)) } #[inline] - fn rfold(self, mut init: Acc, mut fold: Fold) -> Acc + fn rfold(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn flatten( - fold: &mut impl FnMut(Acc, T::Item) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ - where - T::IntoIter: DoubleEndedIterator, - { - move |acc, x| x.into_iter().rfold(acc, &mut *fold) - } - - if let Some(back) = self.backiter { - init = back.rfold(init, &mut fold); + fn flatten( + mut fold: impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc { + move |acc, iter| iter.rfold(acc, &mut fold) } - init = self.iter.rfold(init, flatten(&mut fold)); - - if let Some(front) = self.frontiter { - init = front.rfold(init, &mut fold); - } - - init + self.iter_rfold(init, flatten(fold)) } #[inline] #[rustc_inherit_overflow_checks] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - loop { - if let Some(ref mut back) = self.backiter { - match back.advance_back_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } - } - match self.iter.next_back() { - Some(iterable) => self.backiter = Some(iterable.into_iter()), - _ => break, - } - } - - self.backiter = None; - - if let Some(ref mut front) = self.frontiter { - match front.advance_back_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, + #[inline] + #[rustc_inherit_overflow_checks] + fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { + match iter.advance_back_by(n) { + Ok(()) => ControlFlow::BREAK, + Err(advanced) => ControlFlow::Continue(n - advanced), } } - if rem > 0 { - return Err(n - rem); + match self.iter_try_rfold(n, advance) { + ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), + _ => Ok(()), } - - self.frontiter = None; - - Ok(()) } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 916a26e24..bf4fabad3 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,6 +1,7 @@ use crate::iter::{InPlaceIterable, Iterator}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try}; +mod array_chunks; mod by_ref_sized; mod chain; mod cloned; @@ -32,6 +33,9 @@ pub use self::{ scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip, }; +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub use self::array_chunks::ArrayChunks; + #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index 2c283100f..dbf0ae9ec 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -33,21 +33,32 @@ where #[inline] fn next(&mut self) -> Option { if unlikely(self.n > 0) { - self.iter.nth(crate::mem::take(&mut self.n) - 1)?; + self.iter.nth(crate::mem::take(&mut self.n)) + } else { + self.iter.next() } - self.iter.next() } #[inline] fn nth(&mut self, n: usize) -> Option { - // Can't just add n + self.n due to overflow. if self.n > 0 { - let to_skip = self.n; - self.n = 0; - // nth(n) skips n+1 - self.iter.nth(to_skip - 1)?; + let skip: usize = crate::mem::take(&mut self.n); + // Checked add to handle overflow case. + let n = match skip.checked_add(n) { + Some(nth) => nth, + None => { + // In case of overflow, load skip value, before loading `n`. + // Because the amount of elements to iterate is beyond `usize::MAX`, this + // is split into two `nth` calls where the `skip` `nth` call is discarded. + self.iter.nth(skip - 1)?; + n + } + }; + // Load nth element including skip. + self.iter.nth(n) + } else { + self.iter.nth(n) } - self.iter.nth(n) } #[inline] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index d5c6aed5b..9514466bd 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -398,6 +398,8 @@ pub use self::traits::{ #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::adapters::zip; +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub use self::adapters::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::adapters::ByRefSized; #[stable(feature = "iter_cloned", since = "1.1.0")] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 275412b57..b2d08f4b0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; -use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ @@ -3316,6 +3316,49 @@ pub trait Iterator { Cycle::new(self) } + /// Returns an iterator over `N` elements of the iterator at a time. + /// + /// The chunks do not overlap. If `N` does not divide the length of the + /// iterator, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder] + /// function of the iterator. + /// + /// # Panics + /// + /// Panics if `N` is 0. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_array_chunks)] + /// + /// let mut iter = "lorem".chars().array_chunks(); + /// assert_eq!(iter.next(), Some(['l', 'o'])); + /// assert_eq!(iter.next(), Some(['r', 'e'])); + /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']); + /// ``` + /// + /// ``` + /// #![feature(iter_array_chunks)] + /// + /// let data = [1, 1, 2, -2, 6, 0, 3, 1]; + /// // ^-----^ ^------^ + /// for [x, y, z] in data.iter().array_chunks() { + /// assert_eq!(x + y + z, 4); + /// } + /// ``` + #[track_caller] + #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + fn array_chunks(self) -> ArrayChunks + where + Self: Sized, + { + ArrayChunks::new(self) + } + /// Sums the elements of an iterator. /// /// Takes each element, adds them together, and returns the result. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49..5621d15c1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -93,6 +93,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] // // Library features: #![feature(const_align_offset)] @@ -130,7 +131,6 @@ #![feature(const_replace)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] -#![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] @@ -143,12 +143,14 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_default_impls)] +#![feature(const_unicode_case_lookup)] #![feature(const_unsafecell_get_mut)] #![feature(core_panic)] #![feature(duration_consts_float)] #![feature(maybe_uninit_uninit_array)] #![feature(ptr_metadata)] #![feature(slice_ptr_get)] +#![feature(slice_split_at_unchecked)] #![feature(str_internals)] #![feature(utf16_extra)] #![feature(utf16_extra_const)] @@ -157,9 +159,11 @@ #![feature(const_slice_from_ref)] #![feature(const_slice_index)] #![feature(const_is_char_boundary)] +#![feature(const_cstr_methods)] // // Language features: #![feature(abi_unadjusted)] +#![feature(adt_const_params)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] @@ -302,6 +306,8 @@ pub mod clone; pub mod cmp; pub mod convert; pub mod default; +#[cfg(not(bootstrap))] +pub mod error; pub mod marker; pub mod ops; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3a115a8b8..fd96e1ff7 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -350,10 +350,12 @@ macro_rules! matches { /// Unwraps a result or propagates its error. /// -/// The `?` operator was added to replace `try!` and should be used instead. -/// Furthermore, `try` is a reserved word in Rust 2018, so if you must use -/// it, you will need to use the [raw-identifier syntax][ris]: `r#try`. +/// The [`?` operator][propagating-errors] was added to replace `try!` +/// and should be used instead. Furthermore, `try` is a reserved word +/// in Rust 2018, so if you must use it, you will need to use the +/// [raw-identifier syntax][ris]: `r#try`. /// +/// [propagating-errors]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator /// [ris]: https://doc.rust-lang.org/nightly/rust-by-example/compatibility/raw_identifiers.html /// /// `try!` matches the given [`Result`]. In case of the `Ok` variant, the @@ -457,11 +459,12 @@ macro_rules! r#try { /// /// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects /// implementing either, as objects do not typically implement both. However, the module must -/// import the traits qualified so their names do not conflict: +/// avoid conflict between the trait names, such as by importing them as `_` or otherwise renaming +/// them: /// /// ``` -/// use std::fmt::Write as FmtWrite; -/// use std::io::Write as IoWrite; +/// use std::fmt::Write as _; +/// use std::io::Write as _; /// /// fn main() -> Result<(), Box> { /// let mut s = String::new(); @@ -474,6 +477,23 @@ macro_rules! r#try { /// } /// ``` /// +/// If you also need the trait names themselves, such as to implement one or both on your types, +/// import the containing module and then name them with a prefix: +/// +/// ``` +/// # #![allow(unused_imports)] +/// use std::fmt::{self, Write as _}; +/// use std::io::{self, Write as _}; +/// +/// struct Example; +/// +/// impl fmt::Write for Example { +/// fn write_str(&mut self, _s: &str) -> core::fmt::Result { +/// unimplemented!(); +/// } +/// } +/// ``` +/// /// Note: This macro can be used in `no_std` setups as well. /// In a `no_std` setup you are responsible for the implementation details of the components. /// @@ -526,25 +546,6 @@ macro_rules! write { /// Ok(()) /// } /// ``` -/// -/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects -/// implementing either, as objects do not typically implement both. However, the module must -/// import the traits qualified so their names do not conflict: -/// -/// ``` -/// use std::fmt::Write as FmtWrite; -/// use std::io::Write as IoWrite; -/// -/// fn main() -> Result<(), Box> { -/// let mut s = String::new(); -/// let mut v = Vec::new(); -/// -/// writeln!(&mut s, "{} {}", "abc", 123)?; // uses fmt::Write::write_fmt -/// writeln!(&mut v, "s = {:?}", s)?; // uses io::Write::write_fmt -/// assert_eq!(v, b"s = \"abc 123\\n\"\n"); -/// Ok(()) -/// } -/// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")] @@ -1015,7 +1016,7 @@ pub(crate) mod builtin { /// Concatenates literals into a byte slice. /// /// This macro takes any number of comma-separated literals, and concatenates them all into - /// one, yielding an expression of type `&[u8, _]`, which represents all of the literals + /// one, yielding an expression of type `&[u8; _]`, which represents all of the literals /// concatenated left-to-right. The literals passed can be any combination of: /// /// - byte literals (`b'r'`) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2c5789795..b8239ed88 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -343,7 +343,7 @@ pub trait StructuralEq { /// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get /// the error [E0204]. /// -/// [E0204]: ../../error-index.html#E0204 +/// [E0204]: ../../error_codes/E0204.html /// /// ## When *should* my type be `Copy`? /// @@ -800,6 +800,15 @@ impl Unpin for *mut T {} #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] pub trait Destruct {} +/// A marker for tuple types. +/// +/// The implementation of this trait is built-in and cannot be implemented +/// for any user type. +#[unstable(feature = "tuple_trait", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "tuple_trait")] +#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +pub trait Tuple {} + /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4ea53608..2490c0767 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -54,9 +54,6 @@ use crate::slice; /// // The equivalent code with `MaybeUninit`: /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! âš ï¸ /// ``` -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] /// is considered initialized (under the current implementation; this does not constitute @@ -130,11 +127,8 @@ use crate::slice; /// MaybeUninit::uninit().assume_init() /// }; /// -/// // Dropping a `MaybeUninit` does nothing. Thus using raw pointer -/// // assignment instead of `ptr::write` does not cause the old -/// // uninitialized value to be dropped. Also if there is a panic during -/// // this loop, we have a memory leak, but there is no memory safety -/// // issue. +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. /// for elem in &mut data[..] { /// elem.write(vec![42]); /// } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 20b2d5e26..d2dd2941d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -665,14 +665,14 @@ pub unsafe fn zeroed() -> T { /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit]. /// As the [`assume_init` documentation][assume_init] explains, /// [the Rust compiler assumes][inv] that values are properly initialized. -/// As a consequence, calling e.g. `mem::uninitialized::()` causes immediate -/// undefined behavior for returning a `bool` that is not definitely either `true` -/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// +/// Truly uninitialized memory like what gets returned here /// is special in that the compiler knows that it does not have a fixed value. /// This makes it undefined behavior to have uninitialized data in a variable even /// if that variable has an integer type. -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) +/// +/// Therefore, it is immediate undefined behavior to call this function on nearly all types, +/// including integer types and arrays of integer types, and even if the result is unused. /// /// [uninit]: MaybeUninit::uninit /// [assume_init]: MaybeUninit::assume_init diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index b59a5b89d..87a378631 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -9,20 +9,15 @@ message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." )] -pub unsafe trait BikeshedIntrinsicFrom< - Src, - Context, - const ASSUME_ALIGNMENT: bool, - const ASSUME_LIFETIMES: bool, - const ASSUME_VALIDITY: bool, - const ASSUME_VISIBILITY: bool, -> where +pub unsafe trait BikeshedIntrinsicFrom +where Src: ?Sized, { } /// What transmutation safety conditions shall the compiler assume that *you* are checking? #[unstable(feature = "transmutability", issue = "99571")] +#[cfg_attr(not(bootstrap), lang = "transmute_opts")] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that @@ -33,11 +28,80 @@ pub struct Assume { /// that violates Rust's memory model. pub lifetimes: bool, + /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the + /// type and field privacy of the destination type (and sometimes of the source type, too). + pub safety: bool, + /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid /// instance of the destination type. pub validity: bool, +} - /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the - /// type and field privacy of the destination type (and sometimes of the source type, too). - pub visibility: bool, +impl Assume { + /// Do not assume that *you* have ensured any safety properties are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const NOTHING: Self = + Self { alignment: false, lifetimes: false, safety: false, validity: false }; + + /// Assume only that alignment conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING }; + + /// Assume only that lifetime conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING }; + + /// Assume only that safety conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING }; + + /// Assume only that dynamically-satisfiable validity conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING }; + + /// Assume both `self` and `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn and(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment || other_assumptions.alignment, + lifetimes: self.lifetimes || other_assumptions.lifetimes, + safety: self.safety || other_assumptions.safety, + validity: self.validity || other_assumptions.validity, + } + } + + /// Assume `self`, excepting `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn but_not(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment && !other_assumptions.alignment, + lifetimes: self.lifetimes && !other_assumptions.lifetimes, + safety: self.safety && !other_assumptions.safety, + validity: self.validity && !other_assumptions.validity, + } + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Add for Assume { + type Output = Assume; + + fn add(self, other_assumptions: Assume) -> Assume { + self.and(other_assumptions) + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Sub for Assume { + type Output = Assume; + + fn sub(self, other_assumptions: Assume) -> Assume { + self.but_not(other_assumptions) + } } diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index fcfa95120..32b2afb72 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -26,17 +27,23 @@ impl ValidAlign { /// It must *not* be zero. #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - debug_assert!(align.is_power_of_two()); + // SAFETY: Precondition passed to the caller. + unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. unsafe { mem::transmute::(align) } } + #[inline] + pub(crate) const fn as_usize(self) -> usize { + self.0 as usize + } + #[inline] pub(crate) const fn as_nonzero(self) -> NonZeroUsize { // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.0 as usize) } + unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } } /// Returns the base 2 logarithm of the alignment. @@ -46,6 +53,13 @@ impl ValidAlign { pub(crate) fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() } + + /// Returns the alignment for a type. + #[inline] + pub(crate) fn of() -> Self { + // SAFETY: rustc ensures that type alignment is always a power of two. + unsafe { ValidAlign::new_unchecked(mem::align_of::()) } + } } impl fmt::Debug for ValidAlign { diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index de85fdd6e..d2a21b6b3 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -137,7 +137,7 @@ macro_rules! define_bignum { // Find the most significant non-zero digit. let msd = digits.iter().rposition(|&x| x != 0); match msd { - Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1, + Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1, // There are no non-zero digits, i.e., the number is zero. _ => 0, } diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index f8edc3625..2019f71e6 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -32,7 +32,7 @@ impl Default for Decimal { impl Decimal { /// The maximum number of digits required to unambiguously round a float. /// - /// For a double-precision IEEE-754 float, this required 767 digits, + /// For a double-precision IEEE 754 float, this required 767 digits, /// so we store the max digits + 1. /// /// We can exactly represent a float in radix `b` from radix 2 if diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 1a223016d..1f6b40e5d 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,8 @@ //! Error types for conversion to integral types. use crate::convert::Infallible; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -144,3 +146,21 @@ impl fmt::Display for ParseIntError { self.__description().fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 6548ad2e5..2c6a0ba64 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f32` single-precision floating point type. +//! Constants for the `f32` single-precision floating point type. //! //! *[See also the `f32` primitive type][f32].* //! @@ -394,7 +394,7 @@ impl f32 { /// Not a Number (NaN). /// - /// Note that IEEE-745 doesn't define just a single NaN value; + /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, @@ -632,7 +632,7 @@ impl f32 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. @@ -654,7 +654,7 @@ impl f32 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. @@ -678,6 +678,106 @@ impl f32 { unsafe { mem::transmute::(self) & 0x8000_0000 != 0 } } + /// Returns the least number greater than `self`. + /// + /// Let `TINY` be the smallest representable positive `f32`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`]; + /// - if `self` is `-TINY`, this returns -0.0; + /// - if `self` is -0.0 or +0.0, this returns `TINY`; + /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`]; + /// - otherwise the unique least value greater than `self` is returned. + /// + /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_up().next_down()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// // f32::EPSILON is the difference between 1.0 and the next number up. + /// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON); + /// // But not for most numbers. + /// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON); + /// assert_eq!(16777216f32.next_up(), 16777218.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_up(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const TINY_BITS: u32 = 0x1; // Smallest positive f32. + const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + TINY_BITS + } else if bits == abs { + bits + 1 + } else { + bits - 1 + }; + Self::from_bits(next_bits) + } + + /// Returns the greatest number less than `self`. + /// + /// Let `TINY` be the smallest representable positive `f32`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`INFINITY`], this returns [`MAX`]; + /// - if `self` is `TINY`, this returns 0.0; + /// - if `self` is -0.0 or +0.0, this returns `-TINY`; + /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`]; + /// - otherwise the unique greatest value less than `self` is returned. + /// + /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_down().next_up()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// let x = 1.0f32; + /// // Clamp value into range [0, 1). + /// let clamped = x.clamp(0.0, 1.0f32.next_down()); + /// assert!(clamped < 1.0); + /// assert_eq!(clamped.next_up(), 1.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_down(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const NEG_TINY_BITS: u32 = 0x8000_0001; // Smallest (in magnitude) negative f32. + const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + NEG_TINY_BITS + } else if bits == abs { + bits - 1 + } else { + bits + 1 + }; + Self::from_bits(next_bits) + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` @@ -733,7 +833,7 @@ impl f32 { /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. /// This also matches the behavior of libm’s fmax. /// @@ -753,7 +853,7 @@ impl f32 { /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. /// This also matches the behavior of libm’s fmin. /// @@ -933,10 +1033,14 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f32_to_u32 = |rt| unsafe { mem::transmute::(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f32_to_u32(x: f32) -> u32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } } @@ -947,9 +1051,9 @@ impl f32 { /// It turns out this is incredibly portable, for two reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. + /// * IEEE 754 very precisely specifies the bit layout of floats. /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most platforms /// (notably x86 and ARM) picked the interpretation that was ultimately /// standardized in 2008, but some didn't (notably MIPS). As a result, all @@ -1021,10 +1125,14 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u32_to_f32 = |rt| unsafe { mem::transmute::(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u32_to_f32(x: u32) -> f32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) } } @@ -1282,15 +1390,14 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] - pub fn clamp(self, min: f32, max: f32) -> f32 { + pub fn clamp(mut self, min: f32, max: f32) -> f32 { assert!(min <= max); - let mut x = self; - if x < min { - x = min; + if self < min { + self = min; } - if x > max { - x = max; + if self > max { + self = max; } - x + self } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 75c92c2f8..fd3c18ce2 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f64` double-precision floating point type. +//! Constants for the `f64` double-precision floating point type. //! //! *[See also the `f64` primitive type][f64].* //! @@ -393,7 +393,7 @@ impl f64 { /// Not a Number (NaN). /// - /// Note that IEEE-745 doesn't define just a single NaN value; + /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, @@ -624,7 +624,7 @@ impl f64 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. @@ -655,7 +655,7 @@ impl f64 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. @@ -688,6 +688,106 @@ impl f64 { self.is_sign_negative() } + /// Returns the least number greater than `self`. + /// + /// Let `TINY` be the smallest representable positive `f64`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`]; + /// - if `self` is `-TINY`, this returns -0.0; + /// - if `self` is -0.0 or +0.0, this returns `TINY`; + /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`]; + /// - otherwise the unique least value greater than `self` is returned. + /// + /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_up().next_down()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// // f64::EPSILON is the difference between 1.0 and the next number up. + /// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON); + /// // But not for most numbers. + /// assert!(0.1f64.next_up() < 0.1 + f64::EPSILON); + /// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_up(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const TINY_BITS: u64 = 0x1; // Smallest positive f64. + const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + TINY_BITS + } else if bits == abs { + bits + 1 + } else { + bits - 1 + }; + Self::from_bits(next_bits) + } + + /// Returns the greatest number less than `self`. + /// + /// Let `TINY` be the smallest representable positive `f64`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`INFINITY`], this returns [`MAX`]; + /// - if `self` is `TINY`, this returns 0.0; + /// - if `self` is -0.0 or +0.0, this returns `-TINY`; + /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`]; + /// - otherwise the unique greatest value less than `self` is returned. + /// + /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_down().next_up()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// let x = 1.0f64; + /// // Clamp value into range [0, 1). + /// let clamped = x.clamp(0.0, 1.0f64.next_down()); + /// assert!(clamped < 1.0); + /// assert_eq!(clamped.next_up(), 1.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_down(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64. + const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + NEG_TINY_BITS + } else if bits == abs { + bits - 1 + } else { + bits + 1 + }; + Self::from_bits(next_bits) + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` @@ -744,7 +844,7 @@ impl f64 { /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. /// This also matches the behavior of libm’s fmax. /// @@ -764,7 +864,7 @@ impl f64 { /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. /// This also matches the behavior of libm’s fmin. /// @@ -926,10 +1026,14 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f64_to_u64 = |rt| unsafe { mem::transmute::(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f64_to_u64(rt: f64) -> u64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } } @@ -940,9 +1044,9 @@ impl f64 { /// It turns out this is incredibly portable, for two reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. + /// * IEEE 754 very precisely specifies the bit layout of floats. /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most platforms /// (notably x86 and ARM) picked the interpretation that was ultimately /// standardized in 2008, but some didn't (notably MIPS). As a result, all @@ -1019,10 +1123,14 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u64_to_f64 = |rt| unsafe { mem::transmute::(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u64_to_f64(rt: u64) -> f64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) } } @@ -1280,15 +1388,14 @@ impl f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] - pub fn clamp(self, min: f64, max: f64) -> f64 { + pub fn clamp(mut self, min: f64, max: f64) -> f64 { assert!(min <= max); - let mut x = self; - if x < min { - x = min; + if self < min { + self = min; } - if x > max { - x = max; + if self > max { + self = max; } - x + self } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a66de19ba..e7deb728d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1518,6 +1518,51 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self + rhs + carry` without the ability to overflow. + /// + /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")] + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ", + "(-1, true));" + )] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + /// + /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add): + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as $SelfT); + (c, b != d) + } + /// Calculates `self` + `rhs` with an unsigned `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -1569,6 +1614,39 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self - rhs - borrow` without the ability to overflow. + /// + /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as $SelfT); + (c, b != d) + } + /// Calculates `self` - `rhs` with an unsigned `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating @@ -2204,7 +2282,7 @@ macro_rules! int_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics @@ -2217,7 +2295,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2226,8 +2304,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2250,7 +2328,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2259,8 +2337,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2283,7 +2361,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2292,8 +2370,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2311,20 +2389,20 @@ macro_rules! int_impl { /// Returns `None` if the number is negative or zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option { + pub const fn checked_ilog(self, base: Self) -> Option { if self <= 0 || base <= 1 { None } else { @@ -2333,7 +2411,7 @@ macro_rules! int_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -2354,13 +2432,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option { + pub const fn checked_ilog2(self) -> Option { if self <= 0 { None } else { @@ -2378,13 +2456,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option { + pub const fn checked_ilog10(self) -> Option { if self > 0 { Some(int_log10::$ActualT(self as $ActualT)) } else { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f481399fd..ab17aa0c8 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,6 +3,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -57,6 +59,16 @@ pub use wrapping::Wrapping; #[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; +#[cfg(not(bootstrap))] +#[cfg(not(no_fp_fmt_parse))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; @@ -623,7 +635,7 @@ impl u8 { /// /// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or /// - U+003A ..= U+0040 `: ; < = > ? @`, or - /// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+005B ..= U+0060 `` [ \ ] ^ _ ` ``, or /// - U+007B ..= U+007E `{ | } ~` /// /// # Examples diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 4de0a0cf5..532a09736 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -56,7 +56,7 @@ macro_rules! nonzero_integers { pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. unsafe { - core::intrinsics::assert_unsafe_precondition!(n != 0); + core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0); Self(n) } } @@ -309,8 +309,8 @@ macro_rules! nonzero_unsigned_operations { ( $( $Ty: ident($Int: ident); )+ ) => { $( impl $Ty { - /// Add an unsigned integer to a non-zero value. - /// Check for overflow and return [`None`] on overflow + /// Adds an unsigned integer to a non-zero value. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// @@ -346,7 +346,7 @@ macro_rules! nonzero_unsigned_operations { } } - /// Add an unsigned integer to a non-zero value. + /// Adds an unsigned integer to a non-zero value. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -377,7 +377,7 @@ macro_rules! nonzero_unsigned_operations { unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } } - /// Add an unsigned integer to a non-zero value, + /// Adds an unsigned integer to a non-zero value, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -409,7 +409,7 @@ macro_rules! nonzero_unsigned_operations { } /// Returns the smallest power of two greater than or equal to n. - /// Check for overflow and return [`None`] + /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. /// @@ -450,7 +450,7 @@ macro_rules! nonzero_unsigned_operations { /// Returns the base 2 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log2`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog2`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -460,22 +460,22 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log2(self) -> u32 { + pub const fn ilog2(self) -> u32 { Self::BITS - 1 - self.leading_zeros() } /// Returns the base 10 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log10`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog10`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -485,15 +485,15 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log10(self) -> u32 { + pub const fn ilog10(self) -> u32 { super::int_log10::$Int(self.0) } } @@ -545,7 +545,7 @@ macro_rules! nonzero_signed_operations { } /// Checked absolute value. - /// Check for overflow and returns [`None`] if + /// Checks for overflow and returns [`None`] if #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] /// The result cannot be zero. /// @@ -740,8 +740,8 @@ macro_rules! nonzero_unsigned_signed_operations { ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { $( impl $Ty { - /// Multiply two non-zero integers together. - /// Check for overflow and return [`None`] on overflow. + /// Multiplies two non-zero integers together. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples @@ -777,7 +777,7 @@ macro_rules! nonzero_unsigned_signed_operations { } } - /// Multiply two non-zero integers together. + /// Multiplies two non-zero integers together. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -809,7 +809,7 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } } - /// Multiply two non-zero integers together, + /// Multiplies two non-zero integers together, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -849,8 +849,8 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } } - /// Raise non-zero value to an integer power. - /// Check for overflow and return [`None`] on overflow. + /// Raises non-zero value to an integer power. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 733655442..46fd7f2d0 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -688,7 +688,7 @@ macro_rules! uint_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics @@ -700,7 +700,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -709,8 +709,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -733,7 +733,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -742,8 +742,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -766,7 +766,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -775,8 +775,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -794,20 +794,20 @@ macro_rules! uint_impl { /// Returns `None` if the number is zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option { + pub const fn checked_ilog(self, base: Self) -> Option { if self <= 0 || base <= 1 { None } else { @@ -816,7 +816,7 @@ macro_rules! uint_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -837,15 +837,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option { + pub const fn checked_ilog2(self) -> Option { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log2()) + Some(x.ilog2()) } else { None } @@ -859,15 +859,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option { + pub const fn checked_ilog10(self) -> Option { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log10()) + Some(x.ilog10()) } else { None } diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index aa654aa55..de9ddb852 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -156,7 +156,7 @@ pub trait Drop { /// handled by the compiler, but when using unsafe code, can sometimes occur /// unintentionally, particularly when using [`ptr::drop_in_place`]. /// - /// [E0040]: ../../error-index.html#E0040 + /// [E0040]: ../../error_codes/E0040.html /// [`panic!`]: crate::panic! /// [`mem::drop`]: drop /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index c5a194b7d..8fdf22cf6 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -250,9 +250,10 @@ pub trait FnOnce { mod impls { #[stable(feature = "rust1", since = "1.0.0")] - impl Fn for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const Fn for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -260,9 +261,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -270,9 +272,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &F where - F: Fn, + F: ~const Fn, { type Output = F::Output; @@ -282,9 +285,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &mut F where - F: FnMut, + F: ~const FnMut, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -292,9 +296,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &mut F where - F: FnMut, + F: ~const FnMut, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs index b651b7b23..3ebd6f8cd 100644 --- a/library/core/src/ops/generator.rs +++ b/library/core/src/ops/generator.rs @@ -83,7 +83,7 @@ pub trait Generator { /// `return` statement or implicitly as the last expression of a generator /// literal. For example futures would use this as `Result` as it /// represents a completed future. - #[lang = "generator_return"] + #[cfg_attr(bootstrap, lang = "generator_return")] type Return; /// Resumes the execution of this generator. diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index a3b148473..d29ae3561 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -677,7 +677,7 @@ pub enum Bound { impl Bound { /// Converts from `&Bound` to `Bound<&T>`. #[inline] - #[unstable(feature = "bound_as_ref", issue = "80996")] + #[stable(feature = "bound_as_ref_shared", since = "1.65.0")] pub fn as_ref(&self) -> Bound<&T> { match *self { Included(ref x) => Included(x), diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 02f7f62bf..10f041344 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -222,7 +222,87 @@ pub trait Try: FromResidual { /// Every `Try` type needs to be recreatable from its own associated /// `Residual` type, but can also have additional `FromResidual` implementations /// to support interconversion with other `Try` types. -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + R = "std::option::Option" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + R = "std::result::Result", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + R = "std::ops::ControlFlow", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ + can only be used on other `ControlFlow`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + parent_label = "this function should return `Result` or `Option` to accept `?`" + ), +))] +#[cfg_attr(bootstrap, rustc_on_unimplemented( on( all( from_desugaring = "QuestionMark", @@ -301,7 +381,7 @@ pub trait Try: FromResidual { label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), -)] +))] #[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual::Residual> { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index bca73cb77..934175863 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1189,6 +1189,12 @@ impl Option { /// Returns [`None`] if the option is [`None`], otherwise returns `optb`. /// + /// Arguments passed to `and` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`and_then`], which is + /// lazily evaluated. + /// + /// [`and_then`]: Option::and_then + /// /// # Examples /// /// ``` diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7a575a88e..d4afe0f53 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -190,11 +190,11 @@ pub fn assert_matches_failed( right: &str, args: Option>, ) -> ! { - // Use the Display implementation to display the pattern. + // The pattern is a string so it can be displayed directly. struct Pattern<'a>(&'a str); impl fmt::Debug for Pattern<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.0, f) + f.write_str(self.0) } } assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args); diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index b8e546164..242f44ade 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -801,11 +801,53 @@ mod prim_array {} /// assert_eq!(2 * pointer_size, std::mem::size_of::>()); /// assert_eq!(2 * pointer_size, std::mem::size_of::>()); /// ``` +/// +/// ## Trait Implementations +/// +/// Some traits are implemented for slices if the element type implements +/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`]. +/// +/// ## Iteration +/// +/// The slices implement `IntoIterator`. The iterator yields references to the +/// slice elements. +/// +/// ``` +/// let numbers: &[i32] = &[0, 1, 2]; +/// for n in numbers { +/// println!("{n} is a number!"); +/// } +/// ``` +/// +/// The mutable slice yields mutable references to the elements: +/// +/// ``` +/// let mut scores: &mut [i32] = &mut [7, 8, 9]; +/// for score in scores { +/// *score += 1; +/// } +/// ``` +/// +/// This iterator yields mutable references to the slice's elements, so while +/// the element type of the slice is `i32`, the element type of the iterator is +/// `&mut i32`. +/// +/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default +/// iterators. +/// * Further methods that return iterators are [`.split`], [`.splitn`], +/// [`.chunks`], [`.windows`] and more. +/// +/// [`Hash`]: core::hash::Hash +/// [`.iter`]: slice::iter +/// [`.iter_mut`]: slice::iter_mut +/// [`.split`]: slice::split +/// [`.splitn`]: slice::splitn +/// [`.chunks`]: slice::chunks +/// [`.windows`]: slice::windows #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice {} #[doc(primitive = "str")] -// /// String slices. /// /// *[See also the `std::str` module](crate::str).* @@ -816,19 +858,22 @@ mod prim_slice {} /// /// String slices are always valid UTF-8. /// -/// # Examples +/// # Basic Usage /// /// String literals are string slices: /// /// ``` -/// let hello = "Hello, world!"; -/// -/// // with an explicit type annotation -/// let hello: &'static str = "Hello, world!"; +/// let hello_world = "Hello, World!"; /// ``` /// -/// They are `'static` because they're stored directly in the final binary, and -/// so will be valid for the `'static` duration. +/// Here we have declared a string slice initialized with a string literal. +/// String literals have a static lifetime, which means the string `hello_world` +/// is guaranteed to be valid for the duration of the entire program. +/// We can explicitly specify `hello_world`'s lifetime as well: +/// +/// ``` +/// let hello_world: &'static str = "Hello, world!"; +/// ``` /// /// # Representation /// @@ -996,7 +1041,7 @@ impl (T,) {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl Clone for (T,) { fn clone(&self) -> Self { @@ -1007,7 +1052,7 @@ impl Clone for (T,) { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl Copy for (T,) { // empty @@ -1178,7 +1223,7 @@ mod prim_usize {} #[doc(alias = "&")] #[doc(alias = "&mut")] // -/// References, both shared and mutable. +/// References, `&T` and `&mut T`. /// /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` /// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or @@ -1484,13 +1529,12 @@ mod prim_fn {} // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls #[doc(hidden)] -#[cfg(not(bootstrap))] impl fn(T) -> Ret {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl Clone for fn(T) -> Ret { fn clone(&self) -> Self { @@ -1501,7 +1545,7 @@ impl Clone for fn(T) -> Ret { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl Copy for fn(T) -> Ret { // empty diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e0655d68d..43e883b8b 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -36,7 +36,10 @@ impl *const T { pub const fn is_null(self) -> bool { // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. - (self as *const u8).guaranteed_eq(null()) + match (self as *const u8).guaranteed_eq(null()) { + None => false, + Some(res) => res, + } } /// Casts to a pointer of another type. @@ -95,8 +98,8 @@ impl *const T { /// /// This is a bit safer than `as` because it wouldn't silently change the type if the code is /// refactored. - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_mut(self) -> *mut T { self as _ } @@ -154,7 +157,7 @@ impl *const T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the @@ -249,7 +252,7 @@ impl *const T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::().wrapping_offset(offset).cast::() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. @@ -559,6 +562,21 @@ impl *const T { from_raw_parts::(self.cast::().wrapping_offset(count).cast::<()>(), metadata(self)) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "98290")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *const T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask); + from_raw_parts::(this, metadata(self)) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::()`. /// @@ -641,7 +659,7 @@ impl *const T { /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -740,9 +758,12 @@ impl *const T { where T: Sized, { + let this = self; // SAFETY: The comparison has no side-effects, and the intrinsic // does this check internally in the CTFE implementation. - unsafe { assert_unsafe_precondition!(self >= origin) }; + unsafe { + assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin) + }; let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); @@ -752,20 +773,16 @@ impl *const T { /// Returns whether two pointers are guaranteed to be equal. /// - /// At runtime this function behaves like `self == other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), /// it is not always possible to determine equality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be equal. - /// But when it returns `true`, the pointers are guaranteed to be equal. + /// spuriously return `None` for pointers that later actually turn out to have its equality known. + /// But when it returns `Some`, the pointers' equality is guaranteed to be known. /// - /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_ne`]: #method.guaranteed_ne - /// - /// The return value may change depending on the compiler version and unsafe code must not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -774,29 +791,28 @@ impl *const T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_eq(self, other: *const T) -> bool + pub const fn guaranteed_eq(self, other: *const T) -> Option where T: Sized, { - intrinsics::ptr_guaranteed_eq(self, other) + match intrinsics::ptr_guaranteed_cmp(self as _, other as _) { + 2 => None, + other => Some(other == 1), + } } - /// Returns whether two pointers are guaranteed to be unequal. + /// Returns whether two pointers are guaranteed to be inequal. /// - /// At runtime this function behaves like `self != other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), - /// it is not always possible to determine the inequality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be unequal. - /// But when it returns `true`, the pointers are guaranteed to be unequal. - /// - /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_eq`]: #method.guaranteed_eq + /// it is not always possible to determine inequality of two pointers, so this function may + /// spuriously return `None` for pointers that later actually turn out to have its inequality known. + /// But when it returns `Some`, the pointers' inequality is guaranteed to be known. /// - /// The return value may change depending on the compiler version and unsafe code must not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -805,11 +821,14 @@ impl *const T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_ne(self, other: *const T) -> bool + pub const fn guaranteed_ne(self, other: *const T) -> Option where T: Sized, { - intrinsics::ptr_guaranteed_ne(self, other) + match self.guaranteed_eq(other) { + None => None, + Some(eq) => Some(!eq), + } } /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). @@ -1267,20 +1286,21 @@ impl *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7])); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] @@ -1336,11 +1356,8 @@ impl *const T { panic!("is_aligned_to: align is not a power-of-two"); } - // SAFETY: `is_power_of_two()` will return `false` for zero. - unsafe { core::intrinsics::assume(align != 0) }; - // Cast is needed for `T: !Sized` - self.cast::().addr() % align == 0 + self.cast::().addr() & align - 1 == 0 } } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index cd5edee04..8865c834c 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -180,7 +180,6 @@ pub struct DynMetadata { phantom: crate::marker::PhantomData, } -#[cfg(not(bootstrap))] extern "C" { /// Opaque type for accessing vtables. /// @@ -189,17 +188,6 @@ extern "C" { type VTable; } -/// The common prefix of all vtables. It is followed by function pointers for trait methods. -/// -/// Private implementation detail of `DynMetadata::size_of` etc. -#[repr(C)] -#[cfg(bootstrap)] -struct VTable { - drop_in_place: fn(*mut ()), - size_of: usize, - align_of: usize, -} - impl DynMetadata { /// Returns the size of the type associated with this vtable. #[inline] @@ -207,9 +195,6 @@ impl DynMetadata { // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw". // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the // `Send` part! - #[cfg(bootstrap)] - return self.vtable_ptr.size_of; - #[cfg(not(bootstrap))] // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) @@ -219,9 +204,6 @@ impl DynMetadata { /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { - #[cfg(bootstrap)] - return self.vtable_ptr.align_of; - #[cfg(not(bootstrap))] // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 40e28e636..e976abed7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -90,7 +90,7 @@ //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue //! to conflate these notions). This would potentially make it possible to more efficiently //! target platforms where pointers are larger than offsets, such as CHERI and maybe some -//! segmented architecures. +//! segmented architectures. //! //! ## Provenance //! @@ -172,7 +172,7 @@ //! a pointer to a usize is generally an operation which *only* extracts the address. It is //! therefore *impossible* to construct a valid pointer from a usize because there is no way //! to restore the address-space and provenance. In other words, pointer-integer-pointer -//! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable). +//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable). //! //! The key insight to making this model *at all* viable is the [`with_addr`][] method: //! @@ -272,7 +272,7 @@ //! //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can //! be used for sentinel values like `null` *or* to represent a tagged pointer that will -//! never be dereferencable. In general, it is always sound for an integer to pretend +//! never be dereferenceable. In general, it is always sound for an integer to pretend //! to be a pointer "for fun" as long as you don't use operations on it which require //! it to be valid (offset, read, write, etc). //! @@ -603,6 +603,7 @@ pub const fn invalid_mut(addr: usize) -> *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn from_exposed_addr(addr: usize) -> *const T where T: Sized, @@ -639,6 +640,7 @@ where #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn from_exposed_addr_mut(addr: usize) -> *mut T where T: Sized, @@ -884,7 +886,7 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { // SAFETY: the caller must guarantee that `x` and `y` are // valid for writes and properly aligned. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) => is_aligned_and_not_null(x) && is_aligned_and_not_null(y) && is_nonoverlapping(x, y, count) @@ -981,7 +983,7 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { // and cannot overlap `src` since `dst` must point to a distinct // allocated object. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); mem::swap(&mut *dst, &mut src); // cannot overlap } src @@ -1468,7 +1470,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { pub unsafe fn read_volatile(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src)); + assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src)); intrinsics::volatile_load(src) } } @@ -1539,7 +1541,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { pub unsafe fn write_volatile(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); intrinsics::volatile_store(dst, src); } } @@ -1834,7 +1836,7 @@ macro_rules! maybe_fnptr_doc { $item }; ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for function pointers with up to twelve arguments."] #[$meta] $item diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index fc3dd2a9b..e277b8181 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -35,7 +35,10 @@ impl *mut T { pub const fn is_null(self) -> bool { // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. - (self as *mut u8).guaranteed_eq(null_mut()) + match (self as *mut u8).guaranteed_eq(null_mut()) { + None => false, + Some(res) => res, + } } /// Casts to a pointer of another type. @@ -100,8 +103,8 @@ impl *mut T { /// coercion. /// /// [`cast_mut`]: #method.cast_mut - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_const(self) -> *const T { self as _ } @@ -160,7 +163,7 @@ impl *mut T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the @@ -255,7 +258,7 @@ impl *mut T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::().wrapping_offset(offset).cast::() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. @@ -575,6 +578,21 @@ impl *mut T { ) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "98290")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *mut T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut (); + from_raw_parts_mut::(this, metadata(self)) + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] /// must be used instead. @@ -682,20 +700,16 @@ impl *mut T { /// Returns whether two pointers are guaranteed to be equal. /// - /// At runtime this function behaves like `self == other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), /// it is not always possible to determine equality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be equal. - /// But when it returns `true`, the pointers are guaranteed to be equal. + /// spuriously return `None` for pointers that later actually turn out to have its equality known. + /// But when it returns `Some`, the pointers' equality is guaranteed to be known. /// - /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_ne`]: #method.guaranteed_ne - /// - /// The return value may change depending on the compiler version and unsafe code might not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -704,29 +718,25 @@ impl *mut T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_eq(self, other: *mut T) -> bool + pub const fn guaranteed_eq(self, other: *mut T) -> Option where T: Sized, { - intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _) + (self as *const T).guaranteed_eq(other as _) } - /// Returns whether two pointers are guaranteed to be unequal. + /// Returns whether two pointers are guaranteed to be inequal. /// - /// At runtime this function behaves like `self != other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), - /// it is not always possible to determine the inequality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be unequal. - /// But when it returns `true`, the pointers are guaranteed to be unequal. - /// - /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. + /// it is not always possible to determine inequality of two pointers, so this function may + /// spuriously return `None` for pointers that later actually turn out to have its inequality known. + /// But when it returns `Some`, the pointers' inequality is guaranteed to be known. /// - /// [`guaranteed_eq`]: #method.guaranteed_eq - /// - /// The return value may change depending on the compiler version and unsafe code might not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -735,11 +745,11 @@ impl *mut T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool + pub const fn guaranteed_ne(self, other: *mut T) -> Option where T: Sized, { - intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _) + (self as *const T).guaranteed_ne(other as _) } /// Calculates the distance between two pointers. The returned value is in @@ -824,7 +834,7 @@ impl *mut T { /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -1545,20 +1555,23 @@ impl *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let mut x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// *u16_ptr = 0; + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] @@ -1614,11 +1627,8 @@ impl *mut T { panic!("is_aligned_to: align is not a power-of-two"); } - // SAFETY: `is_power_of_two()` will return `false` for zero. - unsafe { core::intrinsics::assume(align != 0) }; - // Cast is needed for `T: !Sized` - self.cast::().addr() % align == 0 + self.cast::().addr() & align - 1 == 0 } } diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 45b052c82..76eaa191f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1285,6 +1285,11 @@ impl Result { /// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`. /// + /// Arguments passed to `and` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`and_then`], which is + /// lazily evaluated. + /// + /// [`and_then`]: Result::and_then /// /// # Examples /// @@ -1771,40 +1776,6 @@ impl Result, E> { } } -impl Result { - /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if - /// `self` is `Err`. - /// - /// In other words, this function returns the value (the `T`) of a - /// `Result`, regardless of whether or not that result is `Ok` or - /// `Err`. - /// - /// This can be useful in conjunction with APIs such as - /// [`Atomic*::compare_exchange`], or [`slice::binary_search`], but only in - /// cases where you don't care if the result was `Ok` or not. - /// - /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange - /// - /// # Examples - /// - /// ``` - /// #![feature(result_into_ok_or_err)] - /// let ok: Result = Ok(3); - /// let err: Result = Err(4); - /// - /// assert_eq!(ok.into_ok_or_err(), 3); - /// assert_eq!(err.into_ok_or_err(), 4); - /// ``` - #[inline] - #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")] - pub const fn into_ok_or_err(self) -> T { - match self { - Ok(v) => v, - Err(v) => v, - } - } -} - // This is a separate function to reduce the code size of the methods #[cfg(not(feature = "panic_immediate_abort"))] #[inline(never)] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 63715a6b8..5e5399acc 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -215,8 +215,6 @@ impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> { } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] -impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {} -#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index fd7ecf3da..3403a5a86 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -48,10 +48,12 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range start index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice start index is out of range for slice"); } @@ -69,10 +71,12 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range end index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice end index is out of range for slice"); } @@ -88,10 +92,12 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { panic!("slice index starts at {index} but ends at {end}"); } +#[track_caller] const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { panic!("slice index start is larger than end"); } @@ -217,21 +223,23 @@ unsafe impl const SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + let this = self; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len()); slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + let this = self; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len()); slice.as_mut_ptr().add(self) } } @@ -276,22 +284,26 @@ unsafe impl const SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range, slice: *const [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range, slice: *mut [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index f1e659309..395c56784 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(slice.len()) as *const T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -2754,10 +2754,10 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { None => 0, }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (head, tail) = unsafe { self.v.split_at_mut(start) }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (nth, _) = unsafe { tail.split_at_mut(end - start) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c05242222..6c9e7574e 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -64,7 +64,7 @@ macro_rules! iterator { // backwards by `n`. `n` must not exceed `self.len()`. macro_rules! zst_shrink { ($self: ident, $n: ident) => { - $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + $self.end = $self.end.wrapping_byte_sub($n); } } @@ -82,7 +82,7 @@ macro_rules! iterator { // returning the old start. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -90,7 +90,7 @@ macro_rules! iterator { let old = self.ptr.as_ptr(); // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) }; old } } @@ -99,7 +99,7 @@ macro_rules! iterator { // returning the new end. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -107,7 +107,7 @@ macro_rules! iterator { // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // which is guaranteed to not overflow an `isize`. Also, the resulting pointer // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; + self.end = unsafe { self.end.sub(offset) }; self.end } } @@ -180,7 +180,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { - self.post_inc_start(n as isize); + self.post_inc_start(n); Some(next_unchecked!(self)) } } @@ -189,7 +189,7 @@ macro_rules! iterator { fn advance_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.post_inc_start(advance as isize) }; + unsafe { self.post_inc_start(advance) }; if advance == n { Ok(()) } else { Err(advance) } } @@ -375,7 +375,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. unsafe { - self.pre_dec_end(n as isize); + self.pre_dec_end(n); Some(next_back_unchecked!(self)) } } @@ -384,7 +384,7 @@ macro_rules! iterator { fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.pre_dec_end(advance as isize) }; + unsafe { self.pre_dec_end(advance) }; if advance == n { Ok(()) } else { Err(advance) } } } diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index dffeaf6a8..7de1f48e6 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -16,35 +16,51 @@ const USIZE_BYTES: usize = mem::size_of::(); /// bytes where the borrow propagated all the way to the most significant /// bit." #[inline] -fn contains_zero_byte(x: usize) -> bool { +const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } #[cfg(target_pointer_width = "16")] #[inline] -fn repeat_byte(b: u8) -> usize { +const fn repeat_byte(b: u8) -> usize { (b as usize) << 8 | b as usize } #[cfg(not(target_pointer_width = "16"))] #[inline] -fn repeat_byte(b: u8) -> usize { +const fn repeat_byte(b: u8) -> usize { (b as usize) * (usize::MAX / 255) } /// Returns the first index matching the byte `x` in `text`. #[must_use] #[inline] -pub fn memchr(x: u8, text: &[u8]) -> Option { - // Fast path for small slices +pub const fn memchr(x: u8, text: &[u8]) -> Option { + // Fast path for small slices. if text.len() < 2 * USIZE_BYTES { - return text.iter().position(|elt| *elt == x); + return memchr_naive(x, text); } - memchr_general_case(x, text) + memchr_aligned(x, text) } -fn memchr_general_case(x: u8, text: &[u8]) -> Option { +#[inline] +const fn memchr_naive(x: u8, text: &[u8]) -> Option { + let mut i = 0; + + // FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`. + while i < text.len() { + if text[i] == x { + return Some(i); + } + + i += 1; + } + + None +} + +const fn memchr_aligned(x: u8, text: &[u8]) -> Option { // Scan for a single byte value by reading two `usize` words at a time. // // Split `text` in three parts @@ -59,7 +75,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option { if offset > 0 { offset = cmp::min(offset, len); - if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { + if let Some(index) = memchr_naive(x, &text[..offset]) { return Some(index); } } @@ -84,7 +100,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option { } // Find the byte after the point the body loop stopped. - text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) + // FIXME(const-hack): Use `?` instead. + if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None } } /// Returns the last index matching the byte `x` in `text`. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e6ca6ef82..6a7150d29 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -656,10 +656,11 @@ impl [T] { #[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { - let ptr = self.as_mut_ptr(); + let this = self; + let ptr = this.as_mut_ptr(); // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - assert_unsafe_precondition!(a < self.len() && b < self.len()); + assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len()); ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -674,8 +675,9 @@ impl [T] { /// assert!(v == [3, 2, 1]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_reverse", issue = "100784")] #[inline] - pub fn reverse(&mut self) { + pub const fn reverse(&mut self) { let half_len = self.len() / 2; let Range { start, end } = self.as_mut_ptr_range(); @@ -698,9 +700,9 @@ impl [T] { revswap(front_half, back_half, half_len); #[inline] - fn revswap(a: &mut [T], b: &mut [T], n: usize) { - debug_assert_eq!(a.len(), n); - debug_assert_eq!(b.len(), n); + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); // Because this function is first compiled in isolation, // this check tells LLVM that the indexing below is @@ -708,8 +710,10 @@ impl [T] { // lengths of the slices are known -- it's removed. let (a, b) = (&mut a[..n], &mut b[..n]); - for i in 0..n { + let mut i = 0; + while i < n { mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; } } } @@ -969,9 +973,10 @@ impl [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { + let this = self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into @@ -1108,10 +1113,11 @@ impl [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { + let this = &*self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); - exact_div(self.len(), N) + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); + exact_div(this.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. @@ -1538,13 +1544,14 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")] #[inline] #[track_caller] #[must_use] - pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { + pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. + // fulfills the requirements of `split_at_unchecked`. unsafe { self.split_at_unchecked(mid) } } @@ -1623,11 +1630,19 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] #[inline] #[must_use] - pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // HACK: the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } } /// Divides one mutable slice into two at an index, without doing bounds checking. @@ -1675,7 +1690,7 @@ impl [T] { // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. unsafe { - assert_unsafe_precondition!(mid <= len); + assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len); (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } @@ -2309,7 +2324,7 @@ impl [T] { } /// Binary searches this slice for a given element. - /// This behaves similary to [`contains`] if this slice is sorted. + /// This behaves similarly to [`contains`] if this slice is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2921,7 +2936,7 @@ impl [T] { let prev_ptr_write = ptr.add(next_write - 1); if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) { if next_read != next_write { - let ptr_write = prev_ptr_write.offset(1); + let ptr_write = prev_ptr_write.add(1); mem::swap(&mut *ptr_read, &mut *ptr_write); } next_write += 1; @@ -3518,7 +3533,7 @@ impl [T] { // alignment targeted for U. // `crate::ptr::align_offset` is called with a correctly aligned and // valid pointer `ptr` (it comes from a reference to `self`) and with - // a size that is a power of two (since it comes from the alignement for U), + // a size that is a power of two (since it comes from the alignment for U), // satisfying its safety constraints. let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; if offset > self.len() { @@ -4101,7 +4116,6 @@ impl [[T; N]] { } } -#[cfg(not(bootstrap))] #[cfg(not(test))] impl [f32] { /// Sorts the slice of floats. @@ -4131,7 +4145,6 @@ impl [f32] { } } -#[cfg(not(bootstrap))] #[cfg(not(test))] impl [f64] { /// Sorts the slice of floats. diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 107e71ab6..f1e8bc79b 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -90,7 +90,7 @@ use crate::ptr; pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *const T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize ); @@ -134,7 +134,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *mut T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize ); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 6a201834b..c6c03c0b0 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -326,8 +326,8 @@ where unsafe { // Branchless comparison. *end_l = i as u8; - end_l = end_l.offset(!is_less(&*elem, pivot) as isize); - elem = elem.offset(1); + end_l = end_l.add(!is_less(&*elem, pivot) as usize); + elem = elem.add(1); } } } @@ -352,9 +352,9 @@ where // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice. unsafe { // Branchless comparison. - elem = elem.offset(-1); + elem = elem.sub(1); *end_r = i as u8; - end_r = end_r.offset(is_less(&*elem, pivot) as isize); + end_r = end_r.add(is_less(&*elem, pivot) as usize); } } } @@ -365,12 +365,12 @@ where if count > 0 { macro_rules! left { () => { - l.offset(*start_l as isize) + l.add(usize::from(*start_l)) }; } macro_rules! right { () => { - r.offset(-(*start_r as isize) - 1) + r.sub(usize::from(*start_r) + 1) }; } @@ -398,16 +398,16 @@ where ptr::copy_nonoverlapping(right!(), left!(), 1); for _ in 1..count { - start_l = start_l.offset(1); + start_l = start_l.add(1); ptr::copy_nonoverlapping(left!(), right!(), 1); - start_r = start_r.offset(1); + start_r = start_r.add(1); ptr::copy_nonoverlapping(right!(), left!(), 1); } ptr::copy_nonoverlapping(&tmp, right!(), 1); mem::forget(tmp); - start_l = start_l.offset(1); - start_r = start_r.offset(1); + start_l = start_l.add(1); + start_r = start_r.add(1); } } @@ -420,7 +420,7 @@ where // safe. Otherwise, the debug assertions in the `is_done` case guarantee that // `width(l, r) == block_l + block_r`, namely, that the block sizes have been adjusted to account // for the smaller number of remaining elements. - l = unsafe { l.offset(block_l as isize) }; + l = unsafe { l.add(block_l) }; } if start_r == end_r { @@ -428,7 +428,7 @@ where // SAFETY: Same argument as [block-width-guarantee]. Either this is a full block `2*BLOCK`-wide, // or `block_r` has been adjusted for the last handful of elements. - r = unsafe { r.offset(-(block_r as isize)) }; + r = unsafe { r.sub(block_r) }; } if is_done { @@ -457,9 +457,9 @@ where // - `offsets_l` contains valid offsets into `v` collected during the partitioning of // the last block, so the `l.offset` calls are valid. unsafe { - end_l = end_l.offset(-1); - ptr::swap(l.offset(*end_l as isize), r.offset(-1)); - r = r.offset(-1); + end_l = end_l.sub(1); + ptr::swap(l.add(usize::from(*end_l)), r.sub(1)); + r = r.sub(1); } } width(v.as_mut_ptr(), r) @@ -470,9 +470,9 @@ where while start_r < end_r { // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { - end_r = end_r.offset(-1); - ptr::swap(l, r.offset(-(*end_r as isize) - 1)); - l = l.offset(1); + end_r = end_r.sub(1); + ptr::swap(l, r.sub(usize::from(*end_r) + 1)); + l = l.add(1); } } width(v.as_mut_ptr(), l) diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4e569fcc8..343889b69 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -1,5 +1,7 @@ //! Defines utf8 error type. +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// Errors which can occur when attempting to interpret a sequence of [`u8`] @@ -122,6 +124,15 @@ impl fmt::Display for Utf8Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for Utf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8: corrupt contents" + } +} + /// An error returned when parsing a `bool` using [`from_str`] fails /// /// [`from_str`]: super::FromStr::from_str @@ -136,3 +147,12 @@ impl fmt::Display for ParseBoolError { "provided string was not `true` or `false`".fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseBoolError { + #[allow(deprecated)] + fn description(&self) -> &str { + "failed to parse bool" + } +} diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 6ec1c9390..59f873d12 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,51 +1,170 @@ -use crate::char; -use crate::fmt::{self, Write}; -use crate::mem; +use crate::fmt; +use crate::fmt::Formatter; +use crate::fmt::Write; +use crate::iter::FusedIterator; use super::from_utf8_unchecked; use super::validations::utf8_char_width; -/// Lossy UTF-8 string. -#[unstable(feature = "str_internals", issue = "none")] -pub struct Utf8Lossy { - bytes: [u8], +/// An item returned by the [`Utf8Chunks`] iterator. +/// +/// A `Utf8Chunk` stores a sequence of [`u8`] up to the first broken character +/// when decoding a UTF-8 string. +/// +/// # Examples +/// +/// ``` +/// #![feature(utf8_chunks)] +/// +/// use std::str::Utf8Chunks; +/// +/// // An invalid UTF-8 string +/// let bytes = b"foo\xF1\x80bar"; +/// +/// // Decode the first `Utf8Chunk` +/// let chunk = Utf8Chunks::new(bytes).next().unwrap(); +/// +/// // The first three characters are valid UTF-8 +/// assert_eq!("foo", chunk.valid()); +/// +/// // The fourth character is broken +/// assert_eq!(b"\xF1\x80", chunk.invalid()); +/// ``` +#[unstable(feature = "utf8_chunks", issue = "99543")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Utf8Chunk<'a> { + valid: &'a str, + invalid: &'a [u8], } -impl Utf8Lossy { +impl<'a> Utf8Chunk<'a> { + /// Returns the next validated UTF-8 substring. + /// + /// This substring can be empty at the start of the string or between + /// broken UTF-8 characters. #[must_use] - pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { - // SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required. - unsafe { mem::transmute(bytes) } + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn valid(&self) -> &'a str { + self.valid } - pub fn chunks(&self) -> Utf8LossyChunksIter<'_> { - Utf8LossyChunksIter { source: &self.bytes } + /// Returns the invalid sequence that caused a failure. + /// + /// The returned slice will have a maximum length of 3 and starts after the + /// substring given by [`valid`]. Decoding will resume after this sequence. + /// + /// If empty, this is the last chunk in the string. If non-empty, an + /// unexpected byte was encountered or the end of the input was reached + /// unexpectedly. + /// + /// Lossy decoding would replace this sequence with [`U+FFFD REPLACEMENT + /// CHARACTER`]. + /// + /// [`valid`]: Self::valid + /// [`U+FFFD REPLACEMENT CHARACTER`]: crate::char::REPLACEMENT_CHARACTER + #[must_use] + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn invalid(&self) -> &'a [u8] { + self.invalid } } -/// Iterator over lossy UTF-8 string -#[must_use = "iterators are lazy and do nothing unless consumed"] +#[must_use] +#[unstable(feature = "str_internals", issue = "none")] +pub struct Debug<'a>(&'a [u8]); + #[unstable(feature = "str_internals", issue = "none")] -#[allow(missing_debug_implementations)] -pub struct Utf8LossyChunksIter<'a> { +impl fmt::Debug for Debug<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_char('"')?; + + for chunk in Utf8Chunks::new(self.0) { + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let valid = chunk.valid(); + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in chunk.invalid() { + write!(f, "\\x{:02X}", b)?; + } + } + + f.write_char('"') + } +} + +/// An iterator used to decode a slice of mostly UTF-8 bytes to string slices +/// ([`&str`]) and byte slices ([`&[u8]`][byteslice]). +/// +/// If you want a simple conversion from UTF-8 byte slices to string slices, +/// [`from_utf8`] is easier to use. +/// +/// [byteslice]: slice +/// [`from_utf8`]: super::from_utf8 +/// +/// # Examples +/// +/// This can be used to create functionality similar to +/// [`String::from_utf8_lossy`] without allocating heap memory: +/// +/// ``` +/// #![feature(utf8_chunks)] +/// +/// use std::str::Utf8Chunks; +/// +/// fn from_utf8_lossy(input: &[u8], mut push: F) where F: FnMut(&str) { +/// for chunk in Utf8Chunks::new(input) { +/// push(chunk.valid()); +/// +/// if !chunk.invalid().is_empty() { +/// push("\u{FFFD}"); +/// } +/// } +/// } +/// ``` +/// +/// [`String::from_utf8_lossy`]: ../../std/string/struct.String.html#method.from_utf8_lossy +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "utf8_chunks", issue = "99543")] +#[derive(Clone)] +pub struct Utf8Chunks<'a> { source: &'a [u8], } -#[unstable(feature = "str_internals", issue = "none")] -#[derive(PartialEq, Eq, Debug)] -pub struct Utf8LossyChunk<'a> { - /// Sequence of valid chars. - /// Can be empty between broken UTF-8 chars. - pub valid: &'a str, - /// Single broken char, empty if none. - /// Empty iff iterator item is last. - pub broken: &'a [u8], +impl<'a> Utf8Chunks<'a> { + /// Creates a new iterator to decode the bytes. + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn new(bytes: &'a [u8]) -> Self { + Self { source: bytes } + } + + #[doc(hidden)] + #[unstable(feature = "str_internals", issue = "none")] + pub fn debug(&self) -> Debug<'_> { + Debug(self.source) + } } -impl<'a> Iterator for Utf8LossyChunksIter<'a> { - type Item = Utf8LossyChunk<'a>; +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl<'a> Iterator for Utf8Chunks<'a> { + type Item = Utf8Chunk<'a>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if self.source.is_empty() { return None; } @@ -130,71 +249,22 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { // SAFETY: `valid_up_to <= i` because it is only ever assigned via // `valid_up_to = i` and `i` only increases. - let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) }; + let (valid, invalid) = unsafe { inspected.split_at_unchecked(valid_up_to) }; - Some(Utf8LossyChunk { + Some(Utf8Chunk { // SAFETY: All bytes up to `valid_up_to` are valid UTF-8. valid: unsafe { from_utf8_unchecked(valid) }, - broken, + invalid, }) } } -impl fmt::Display for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // If we're the empty string then our iterator won't actually yield - // anything, so perform the formatting manually - if self.bytes.is_empty() { - return "".fmt(f); - } - - for Utf8LossyChunk { valid, broken } in self.chunks() { - // If we successfully decoded the whole chunk as a valid string then - // we can return a direct formatting of the string which will also - // respect various formatting flags if possible. - if valid.len() == self.bytes.len() { - assert!(broken.is_empty()); - return valid.fmt(f); - } - - f.write_str(valid)?; - if !broken.is_empty() { - f.write_char(char::REPLACEMENT_CHARACTER)?; - } - } - Ok(()) - } -} - -impl fmt::Debug for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_char('"')?; +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl FusedIterator for Utf8Chunks<'_> {} - for Utf8LossyChunk { valid, broken } in self.chunks() { - // Valid part. - // Here we partially parse UTF-8 again which is suboptimal. - { - let mut from = 0; - for (i, c) in valid.char_indices() { - let esc = c.escape_debug(); - // If char needs escaping, flush backlog so far and write, else skip - if esc.len() != 1 { - f.write_str(&valid[from..i])?; - for c in esc { - f.write_char(c)?; - } - from = i + c.len_utf8(); - } - } - f.write_str(&valid[from..])?; - } - - // Broken parts of string as hex escape. - for &b in broken { - write!(f, "\\x{:02x}", b)?; - } - } - - f.write_char('"') +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl fmt::Debug for Utf8Chunks<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish() } } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c4f2e283e..f673aa2a4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -22,9 +22,9 @@ use crate::slice::{self, SliceIndex}; pub mod pattern; -#[unstable(feature = "str_internals", issue = "none")] -#[allow(missing_docs)] -pub mod lossy; +mod lossy; +#[unstable(feature = "utf8_chunks", issue = "99543")] +pub use lossy::{Utf8Chunk, Utf8Chunks}; #[stable(feature = "rust1", since = "1.0.0")] pub use converts::{from_utf8, from_utf8_unchecked}; @@ -91,10 +91,12 @@ const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { } } +#[track_caller] const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! { panic!("failed to slice string"); } +#[track_caller] fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { const MAX_DISPLAY_LENGTH: usize = 256; let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH); @@ -2353,7 +2355,7 @@ impl str { #[inline] pub fn is_ascii(&self) -> bool { // We can treat each byte as character here: all multibyte characters - // start with a byte that is not in the ascii range, so we will stop + // start with a byte that is not in the ASCII range, so we will stop // there already. self.as_bytes().is_ascii() } @@ -2638,3 +2640,7 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +impl !crate::error::Error for &str {} diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 04bc66523..2acef432f 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -216,12 +216,12 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // SAFETY: since `align - index` and `ascii_block_size` are // multiples of `usize_bytes`, `block = ptr.add(index)` is // always aligned with a `usize` so it's safe to dereference - // both `block` and `block.offset(1)`. + // both `block` and `block.add(1)`. unsafe { let block = ptr.add(index) as *const usize; // break if there is a nonascii byte let zu = contains_nonascii(*block); - let zv = contains_nonascii(*block.offset(1)); + let zv = contains_nonascii(*block.add(1)); if zu || zv { break; } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 5e2e0c4d8..3c96290fc 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1554,8 +1554,8 @@ impl AtomicPtr { /// Offsets the pointer's address by adding `val` *bytes*, returning the /// previous pointer. /// - /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically - /// perform `ptr = ptr.cast::().wrapping_add(val).cast::()`. + /// This is equivalent to using [`wrapping_byte_add`] to atomically + /// perform `ptr = ptr.wrapping_byte_add(val)`. /// /// `fetch_byte_add` takes an [`Ordering`] argument which describes the /// memory ordering of this operation. All ordering modes are possible. Note @@ -1565,8 +1565,7 @@ impl AtomicPtr { /// **Note**: This method is only available on platforms that support atomic /// operations on [`AtomicPtr`]. /// - /// [`wrapping_add`]: pointer::wrapping_add - /// [`cast`]: pointer::cast + /// [`wrapping_byte_add`]: pointer::wrapping_byte_add /// /// # Examples /// @@ -1584,23 +1583,15 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_add(self.p.get().cast::(), val, order) as *mut T - } + unsafe { atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Offsets the pointer's address by subtracting `val` *bytes*, returning the /// previous pointer. /// - /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically - /// perform `ptr = ptr.cast::().wrapping_sub(val).cast::()`. + /// This is equivalent to using [`wrapping_byte_sub`] to atomically + /// perform `ptr = ptr.wrapping_byte_sub(val)`. /// /// `fetch_byte_sub` takes an [`Ordering`] argument which describes the /// memory ordering of this operation. All ordering modes are possible. Note @@ -1610,8 +1601,7 @@ impl AtomicPtr { /// **Note**: This method is only available on platforms that support atomic /// operations on [`AtomicPtr`]. /// - /// [`wrapping_sub`]: pointer::wrapping_sub - /// [`cast`]: pointer::cast + /// [`wrapping_byte_sub`]: pointer::wrapping_byte_sub /// /// # Examples /// @@ -1628,16 +1618,8 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_sub(self.p.get().cast::(), val, order) as *mut T - } + unsafe { atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "or" operation on the address of the current pointer, @@ -1687,16 +1669,8 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_or(self.p.get().cast::(), val, order) as *mut T - } + unsafe { atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "and" operation on the address of the current @@ -1745,16 +1719,8 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_and(self.p.get().cast::(), val, order) as *mut T - } + unsafe { atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "xor" operation on the address of the current @@ -1801,16 +1767,8 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_xor(self.p.get().cast::(), val, order) as *mut T - } + unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } } @@ -3073,30 +3031,22 @@ unsafe fn atomic_compare_exchange( let (val, ok) = unsafe { match (success, failure) { (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), - #[cfg(not(bootstrap))] (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), - #[cfg(bootstrap)] - _ => panic!("a failure ordering can't be stronger than a success ordering"), } }; if ok { Ok(val) } else { Err(val) } @@ -3116,30 +3066,22 @@ unsafe fn atomic_compare_exchange_weak( let (val, ok) = unsafe { match (success, failure) { (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new), (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new), (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new), (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new), - #[cfg(not(bootstrap))] (AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new), (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), - #[cfg(bootstrap)] - _ => panic!("a failure ordering can't be stronger than a success ordering"), } }; if ok { Ok(val) } else { Err(val) } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 87d4a25af..60ecc9c0b 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -71,6 +71,12 @@ impl RawWaker { /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. +/// +/// These functions must all be thread-safe (even though [`RawWaker`] is +/// \![Send] + \![Sync]) +/// because [`Waker`] is [Send] + [Sync], and thus wakers may be moved to +/// arbitrary threads or invoked by `&` reference. For example, this means that if the +/// `clone` and `drop` functions manage a reference count, they must do so atomically. #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -110,6 +116,12 @@ impl RawWakerVTable { /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, /// `wake_by_ref`, and `drop` functions. /// + /// These functions must all be thread-safe (even though [`RawWaker`] is + /// \![Send] + \![Sync]) + /// because [`Waker`] is [Send] + [Sync], and thus wakers may be moved to + /// arbitrary threads or invoked by `&` reference. For example, this means that if the + /// `clone` and `drop` functions manage a reference count, they must do so atomically. + /// /// # `clone` /// /// This function will be called when the [`RawWaker`] gets cloned, e.g. when @@ -157,9 +169,9 @@ impl RawWakerVTable { } } -/// The `Context` of an asynchronous task. +/// The context of an asynchronous task. /// -/// Currently, `Context` only serves to provide access to a `&Waker` +/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) /// which can be used to wake the current task. #[stable(feature = "futures_api", since = "1.36.0")] pub struct Context<'a> { @@ -172,7 +184,7 @@ pub struct Context<'a> { } impl<'a> Context<'a> { - /// Create a new `Context` from a `&Waker`. + /// Create a new `Context` from a [`&Waker`](Waker). #[stable(feature = "futures_api", since = "1.36.0")] #[must_use] #[inline] @@ -180,7 +192,7 @@ impl<'a> Context<'a> { Context { waker, _marker: PhantomData } } - /// Returns a reference to the `Waker` for the current task. + /// Returns a reference to the [`Waker`] for the current task. #[stable(feature = "futures_api", since = "1.36.0")] #[must_use] #[inline] @@ -202,7 +214,18 @@ impl fmt::Debug for Context<'_> { /// This handle encapsulates a [`RawWaker`] instance, which defines the /// executor-specific wakeup behavior. /// -/// Implements [`Clone`], [`Send`], and [`Sync`]. +/// The typical life of a `Waker` is that it is constructed by an executor, wrapped in a +/// [`Context`], then passed to [`Future::poll()`]. Then, if the future chooses to return +/// [`Poll::Pending`], it must also store the waker somehow and call [`Waker::wake()`] when +/// the future should be polled again. +/// +/// Implements [`Clone`], [`Send`], and [`Sync`]; therefore, a waker may be invoked +/// from any thread, including ones not in any way managed by the executor. For example, +/// this might be done to wake a future when a blocking function call completes on another +/// thread. +/// +/// [`Future::poll()`]: core::future::Future::poll +/// [`Poll::Pending`]: core::task::Poll::Pending #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -219,18 +242,21 @@ unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. /// - /// As long as the runtime keeps running and the task is not finished, it is - /// guaranteed that each invocation of `wake` (or `wake_by_ref`) will be followed - /// by at least one `poll` of the task to which this `Waker` belongs. This makes + /// As long as the executor keeps running and the task is not finished, it is + /// guaranteed that each invocation of [`wake()`](Self::wake) (or + /// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one + /// [`poll()`] of the task to which this `Waker` belongs. This makes /// it possible to temporarily yield to other tasks while running potentially /// unbounded processing loops. /// /// Note that the above implies that multiple wake-ups may be coalesced into a - /// single `poll` invocation by the runtime. + /// single [`poll()`] invocation by the runtime. /// /// Also note that yielding to competing tasks is not guaranteed: it is the /// executor’s choice which task to run and the executor may choose to run the /// current task again. + /// + /// [`poll()`]: crate::future::Future::poll #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub fn wake(self) { @@ -250,8 +276,8 @@ impl Waker { /// Wake up the task associated with this `Waker` without consuming the `Waker`. /// - /// This is similar to `wake`, but may be slightly less efficient in the case - /// where an owned `Waker` is available. This method should be preferred to + /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in + /// the case where an owned `Waker` is available. This method should be preferred to /// calling `waker.clone().wake()`. #[inline] #[stable(feature = "futures_api", since = "1.36.0")] @@ -263,7 +289,7 @@ impl Waker { unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } } - /// Returns `true` if this `Waker` and another `Waker` have awoken the same task. + /// Returns `true` if this `Waker` and another `Waker` would awake the same task. /// /// This function works on a best-effort basis, and may return false even /// when the `Waker`s would awaken the same task. However, if this function diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 756f1a166..4f29ecc0f 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -318,19 +318,11 @@ impl Duration { /// assert_eq!(duration.as_secs(), 5); /// ``` /// - /// To determine the total number of seconds represented by the `Duration`, - /// use `as_secs` in combination with [`subsec_nanos`]: - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// - /// assert_eq!(5.730023852, - /// duration.as_secs() as f64 - /// + duration.subsec_nanos() as f64 * 1e-9); - /// ``` + /// To determine the total number of seconds represented by the `Duration` + /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`] /// + /// [`as_secs_f64`]: Duration::as_secs_f64 + /// [`as_secs_f32`]: Duration::as_secs_f32 /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] @@ -1143,7 +1135,7 @@ impl fmt::Debug for Duration { // 2. The postfix: can be "µs" so we have to count UTF8 characters. let mut actual_w = prefix.len() + postfix.chars().count(); // 3. The integer part: - if let Some(log) = integer_part.checked_log10() { + if let Some(log) = integer_part.checked_ilog10() { // integer_part is > 0, so has length log10(x)+1 actual_w += 1 + log as usize; } else { @@ -1288,7 +1280,7 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch + // f32 does not have enough precision to trigger the second branch // since it can not represent numbers between 0.999_999_940_395 and 1.0. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) } @@ -1307,9 +1299,9 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch. + // f32 does not have enough precision to trigger the second branch. // For example, it can not represent numbers between 1.999_999_880... - // and 2.0. Bigger values result in even smaller presicion of the + // and 2.0. Bigger values result in even smaller precision of the // fractional part. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index d189e6400..aa8a2425b 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -107,7 +107,7 @@ macro_rules! tuple_impls { // Otherwise, it hides the docs entirely. macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index d2073f86c..7301da2af 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -1,7 +1,8 @@ ///! This file is generated by src/tools/unicode-table-generator; do not edit manually! +#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline(always)] -fn bitset_search< +const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, const N1: usize, @@ -17,14 +18,18 @@ fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; - let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) { - v + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. + let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { + chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; - let word = if let Some(word) = bitset_canonical.get(idx) { - *word + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. + let word = if idx < bitset_canonical.len() { + bitset_canonical[idx] } else { let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()]; let mut word = bitset_canonical[real_idx as usize]; @@ -318,14 +323,14 @@ pub mod grapheme_extend { #[rustfmt::skip] pub mod lowercase { - static BITSET_CHUNKS_MAP: [u8; 123] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[ 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 3, 0, 0, 7, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 19] = &[ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], @@ -346,7 +351,7 @@ pub mod lowercase { [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44], ]; - static BITSET_CANONICAL: [u64; 55] = [ + const BITSET_CANONICAL: &'static [u64; 55] = &[ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -403,13 +408,14 @@ pub mod lowercase { 0b1110011111111111111111111111111111111111111111110000000000000000, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - static BITSET_MAPPING: [(u8, u8); 20] = [ + const BITSET_MAPPING: &'static [(u8, u8); 20] = &[ (0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187), (6, 132), (7, 93), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, @@ -454,14 +460,14 @@ pub mod n { #[rustfmt::skip] pub mod uppercase { - static BITSET_CHUNKS_MAP: [u8; 125] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[ 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, 6, 6, 9, 6, 3, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[ [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], @@ -480,7 +486,7 @@ pub mod uppercase { [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], ]; - static BITSET_CANONICAL: [u64; 43] = [ + const BITSET_CANONICAL: &'static [u64; 43] = &[ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, @@ -525,13 +531,14 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - static BITSET_MAPPING: [(u8, u8); 25] = [ + const BITSET_MAPPING: &'static [(u8, u8); 25] = &[ (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, @@ -544,18 +551,26 @@ pub mod uppercase { #[rustfmt::skip] pub mod white_space { - static SHORT_OFFSET_RUNS: [u32; 4] = [ - 5760, 18882560, 23080960, 40972289, - ]; - static OFFSETS: [u8; 21] = [ - 9, 5, 18, 1, 100, 1, 26, 1, 0, 1, 0, 11, 29, 2, 5, 1, 47, 1, 0, 1, 0, + static WHITESPACE_MAP: [u8; 256] = [ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; + #[inline] pub fn lookup(c: char) -> bool { - super::skip_search( - c as u32, - &SHORT_OFFSET_RUNS, - &OFFSETS, - ) + match c as u32 >> 8 { + 0 => WHITESPACE_MAP[c as usize & 0xff] & 1 != 0, + 22 => c as u32 == 0x1680, + 32 => WHITESPACE_MAP[c as usize & 0xff] & 2 != 0, + 48 => c as u32 == 0x3000, + _ => false, + } } } diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs index 8a5a06b34..3ceaeadce 100644 --- a/library/core/tests/alloc.rs +++ b/library/core/tests/alloc.rs @@ -1,4 +1,5 @@ use core::alloc::Layout; +use core::mem::size_of; use core::ptr::{self, NonNull}; #[test] @@ -12,6 +13,49 @@ fn const_unchecked_layout() { assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN))); } +#[test] +fn layout_round_up_to_align_edge_cases() { + const MAX_SIZE: usize = isize::MAX as usize; + + for shift in 0..usize::BITS { + let align = 1_usize << shift; + let edge = (MAX_SIZE + 1) - align; + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::from_size_align(low, align).is_ok()); + assert!(Layout::from_size_align(high, align).is_err()); + for size in low..=high { + assert_eq!( + Layout::from_size_align(size, align).is_ok(), + size.next_multiple_of(align) <= MAX_SIZE, + ); + } + } +} + +#[test] +fn layout_array_edge_cases() { + for_type::(); + for_type::<[i32; 0b10101]>(); + for_type::<[u8; 0b1010101]>(); + + // Make sure ZSTs don't lead to divide-by-zero + assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap()); + + fn for_type() { + const MAX_SIZE: usize = isize::MAX as usize; + + let edge = (MAX_SIZE + 1) / size_of::(); + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::array::(low).is_ok()); + assert!(Layout::array::(high).is_err()); + for n in low..=high { + assert_eq!(Layout::array::(n).is_ok(), n * size_of::() <= MAX_SIZE); + } + } +} + #[test] fn layout_debug_shows_log2_of_alignment() { // `Debug` is not stable, but here's what it does right now diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs index 8ed0c8880..9538b8139 100644 --- a/library/core/tests/any.rs +++ b/library/core/tests/any.rs @@ -142,7 +142,7 @@ impl Provider for SomeConcreteType { demand .provide_ref::(&self.some_string) .provide_ref::(&self.some_string) - .provide_value::(|| "bye".to_owned()); + .provide_value_with::(|| "bye".to_owned()); } } diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 13b12db20..94b031060 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -155,7 +155,7 @@ fn ptr_add_data() { assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); assert_eq!(atom.load(SeqCst), n); - let bytes_from_n = |b| n.cast::().wrapping_add(b).cast::(); + let bytes_from_n = |b| n.wrapping_byte_add(b); assert_eq!(atom.fetch_byte_add(1, SeqCst), n); assert_eq!(atom.load(SeqCst), bytes_from_n(1)); diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803..d874f0831 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x const fn unaligned_ptr() -> *const u16 { // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } + unsafe { DATA.as_ptr().byte_add(1) } } #[test] @@ -67,7 +67,7 @@ fn write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); } two_aligned @@ -91,7 +91,7 @@ fn mut_ptr_write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); } two_aligned diff --git a/library/core/tests/iter/adapters/array_chunks.rs b/library/core/tests/iter/adapters/array_chunks.rs new file mode 100644 index 000000000..4e9d89e1e --- /dev/null +++ b/library/core/tests/iter/adapters/array_chunks.rs @@ -0,0 +1,179 @@ +use core::cell::Cell; +use core::iter::{self, Iterator}; + +use super::*; + +#[test] +fn test_iterator_array_chunks_infer() { + let xs = [1, 1, 2, -2, 6, 0, 3, 1]; + for [a, b, c] in xs.iter().copied().array_chunks() { + assert_eq!(a + b + c, 4); + } +} + +#[test] +fn test_iterator_array_chunks_clone_and_drop() { + let count = Cell::new(0); + let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + assert_eq!(it.by_ref().count(), 1); + assert_eq!(count.get(), 3); + let mut it2 = it.clone(); + assert_eq!(count.get(), 3); + assert_eq!(it.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 5); + assert!(it2.next().is_none()); + assert_eq!(it2.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 7); +} + +#[test] +fn test_iterator_array_chunks_remainder() { + let mut it = (0..11).array_chunks::<4>(); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_size_hint() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.size_hint(), (6, Some(6))); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.size_hint(), (2, Some(2))); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.size_hint(), (1, Some(1))); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.size_hint(), (0, Some(0))); + + let it = (1..).array_chunks::<2>(); + assert_eq!(it.size_hint(), (usize::MAX / 2, None)); + + let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>(); + assert_eq!(it.size_hint(), (0, None)); +} + +#[test] +fn test_iterator_array_chunks_count() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.count(), 6); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.count(), 2); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.count(), 1); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.count(), 0); + + let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>(); + assert_eq!(it.count(), 1); + + let it = iter::empty::().array_chunks::<2>(); + assert_eq!(it.count(), 0); + + let it = [(); usize::MAX].iter().array_chunks::<2>(); + assert_eq!(it.count(), usize::MAX / 2); +} + +#[test] +fn test_iterator_array_chunks_next_and_next_back() { + let mut it = (0..11).array_chunks::<3>(); + assert_eq!(it.next(), Some([0, 1, 2])); + assert_eq!(it.next_back(), Some([6, 7, 8])); + assert_eq!(it.next(), Some([3, 4, 5])); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]); +} + +#[test] +fn test_iterator_array_chunks_rev_remainder() { + let mut it = (0..11).array_chunks::<4>(); + { + let mut it = it.by_ref().rev(); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + } + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_try_fold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 9); +} + +#[test] +fn test_iterator_array_chunks_fold() { + let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| { + assert_eq!(acc + 1, a); + assert_eq!(acc + 2, b); + assert_eq!(acc + 3, c); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + assert_eq!(count.get(), 10); +} + +#[test] +fn test_iterator_array_chunks_try_rfold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); +} + +#[test] +fn test_iterator_array_chunks_rfold() { + let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| { + assert_eq!(10 - (acc + 1), c); + assert_eq!(10 - (acc + 2), b); + assert_eq!(10 - (acc + 3), a); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + assert_eq!(count.get(), 10); +} diff --git a/library/core/tests/iter/adapters/by_ref_sized.rs b/library/core/tests/iter/adapters/by_ref_sized.rs new file mode 100644 index 000000000..a9c066f0e --- /dev/null +++ b/library/core/tests/iter/adapters/by_ref_sized.rs @@ -0,0 +1,20 @@ +use core::iter::*; + +#[test] +fn test_iterator_by_ref_sized() { + let a = ['a', 'b', 'c', 'd']; + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zab"); + ByRefSized(&mut it).fold((), |(), x| s.push(x)); + assert_eq!(s, "Zabcd"); + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).rev().take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zdc"); + ByRefSized(&mut it).rfold((), |(), x| s.push(x)); + assert_eq!(s, "Zdcba"); +} diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index f8ab8c9d4..690fd0c21 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -168,3 +168,45 @@ fn test_trusted_len_flatten() { assert_trusted_len(&iter); assert_eq!(iter.size_hint(), (20, Some(20))); } + +#[test] +fn test_flatten_count() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().count(), 40); + it.advance_by(5).unwrap(); + assert_eq!(it.clone().count(), 35); + it.advance_back_by(5).unwrap(); + assert_eq!(it.clone().count(), 30); + it.advance_by(10).unwrap(); + assert_eq!(it.clone().count(), 20); + it.advance_back_by(8).unwrap(); + assert_eq!(it.clone().count(), 12); + it.advance_by(4).unwrap(); + assert_eq!(it.clone().count(), 8); + it.advance_back_by(5).unwrap(); + assert_eq!(it.clone().count(), 3); + it.advance_by(3).unwrap(); + assert_eq!(it.clone().count(), 0); +} + +#[test] +fn test_flatten_last() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().last(), Some(39)); + it.advance_by(5).unwrap(); // 5..40 + assert_eq!(it.clone().last(), Some(39)); + it.advance_back_by(5).unwrap(); // 5..35 + assert_eq!(it.clone().last(), Some(34)); + it.advance_by(10).unwrap(); // 15..35 + assert_eq!(it.clone().last(), Some(34)); + it.advance_back_by(8).unwrap(); // 15..27 + assert_eq!(it.clone().last(), Some(26)); + it.advance_by(4).unwrap(); // 19..27 + assert_eq!(it.clone().last(), Some(26)); + it.advance_back_by(5).unwrap(); // 19..22 + assert_eq!(it.clone().last(), Some(21)); + it.advance_by(3).unwrap(); // 22..22 + assert_eq!(it.clone().last(), None); +} diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs index 567d9fe49..ffd5f3857 100644 --- a/library/core/tests/iter/adapters/mod.rs +++ b/library/core/tests/iter/adapters/mod.rs @@ -1,3 +1,5 @@ +mod array_chunks; +mod by_ref_sized; mod chain; mod cloned; mod copied; @@ -183,3 +185,25 @@ impl Clone for CountClone { ret } } + +#[derive(Debug, Clone)] +struct CountDrop<'a> { + dropped: bool, + count: &'a Cell, +} + +impl<'a> CountDrop<'a> { + pub fn new(count: &'a Cell) -> Self { + Self { dropped: false, count } + } +} + +impl Drop for CountDrop<'_> { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + self.count.set(self.count.get() + 1); + } +} diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs index 65f235e86..754641834 100644 --- a/library/core/tests/iter/adapters/skip.rs +++ b/library/core/tests/iter/adapters/skip.rs @@ -201,3 +201,34 @@ fn test_skip_non_fused() { // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario. let _ = non_fused.skip(20).next(); } + +#[test] +fn test_skip_non_fused_nth_overflow() { + let non_fused = Unfuse::new(0..10); + + // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused + // iterators. + let _ = non_fused.skip(20).nth(usize::MAX); +} + +#[test] +fn test_skip_overflow_wrapping() { + // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded. + struct WrappingIterator(usize); + + impl Iterator for WrappingIterator { + type Item = usize; + + fn next(&mut self) -> core::option::Option { + ::nth(self, 0) + } + + fn nth(&mut self, nth: usize) -> core::option::Option { + self.0 = self.0.wrapping_add(nth.wrapping_add(1)); + Some(self.0) + } + } + + let wrap = WrappingIterator(0); + assert_eq!(wrap.skip(20).nth(usize::MAX), Some(20)); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db94368f6..4a0e162bc 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(array_methods)] #![feature(array_windows)] #![feature(bench_black_box)] +#![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_assume)] #![feature(const_black_box)] @@ -14,6 +15,7 @@ #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_pointer_byte_offsets)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] @@ -61,6 +63,7 @@ #![feature(slice_partition_dedup)] #![feature(int_log)] #![feature(iter_advance_by)] +#![feature(iter_array_chunks)] #![feature(iter_collect_into)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] @@ -73,7 +76,7 @@ #![feature(const_pin)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(result_into_ok_or_err)] +#![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] @@ -96,6 +99,7 @@ #![feature(waker_getters)] #![feature(slice_flatten)] #![feature(provide_any)] +#![feature(utf8_chunks)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs index dc3092e14..be203fb5c 100644 --- a/library/core/tests/num/int_log.rs +++ b/library/core/tests/num/int_log.rs @@ -1,166 +1,166 @@ -//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a +//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a //! separate file because there's both a large number of them, and not all tests -//! can be run on Android. This is because in Android `log2` uses an imprecise +//! can be run on Android. This is because in Android `ilog2` uses an imprecise //! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53 #[test] -fn checked_log() { - assert_eq!(999u32.checked_log(10), Some(2)); - assert_eq!(1000u32.checked_log(10), Some(3)); - assert_eq!(555u32.checked_log(13), Some(2)); - assert_eq!(63u32.checked_log(4), Some(2)); - assert_eq!(64u32.checked_log(4), Some(3)); - assert_eq!(10460353203u64.checked_log(3), Some(21)); - assert_eq!(10460353202u64.checked_log(3), Some(20)); - assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80)); - assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79)); - assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8)); - assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7)); - - assert_eq!(0u8.checked_log(4), None); - assert_eq!(0u16.checked_log(4), None); - assert_eq!(0i8.checked_log(4), None); - assert_eq!(0i16.checked_log(4), None); +fn checked_ilog() { + assert_eq!(999u32.checked_ilog(10), Some(2)); + assert_eq!(1000u32.checked_ilog(10), Some(3)); + assert_eq!(555u32.checked_ilog(13), Some(2)); + assert_eq!(63u32.checked_ilog(4), Some(2)); + assert_eq!(64u32.checked_ilog(4), Some(3)); + assert_eq!(10460353203u64.checked_ilog(3), Some(21)); + assert_eq!(10460353202u64.checked_ilog(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7)); + + assert_eq!(0u8.checked_ilog(4), None); + assert_eq!(0u16.checked_ilog(4), None); + assert_eq!(0i8.checked_ilog(4), None); + assert_eq!(0i16.checked_ilog(4), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log(4), None); + assert_eq!(i.checked_ilog(4), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } } #[test] -fn checked_log2() { - assert_eq!(5u32.checked_log2(), Some(2)); - assert_eq!(0u64.checked_log2(), None); - assert_eq!(128i32.checked_log2(), Some(7)); - assert_eq!((-55i16).checked_log2(), None); +fn checked_ilog2() { + assert_eq!(5u32.checked_ilog2(), Some(2)); + assert_eq!(0u64.checked_ilog2(), None); + assert_eq!(128i32.checked_ilog2(), Some(7)); + assert_eq!((-55i16).checked_ilog2(), None); - assert_eq!(0u8.checked_log2(), None); - assert_eq!(0u16.checked_log2(), None); - assert_eq!(0i8.checked_log2(), None); - assert_eq!(0i16.checked_log2(), None); + assert_eq!(0u8.checked_ilog2(), None); + assert_eq!(0u16.checked_ilog2(), None); + assert_eq!(0i8.checked_ilog2(), None); + assert_eq!(0i16.checked_ilog2(), None); for i in 1..=u8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 && i != 32768 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } for i in i8::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } for i in 1..=i8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } } -// Validate cases that fail on Android's imprecise float log2 implementation. +// Validate cases that fail on Android's imprecise float ilog2 implementation. #[test] #[cfg(not(target_os = "android"))] -fn checked_log2_not_android() { - assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32)); - assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32)); - assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32)); +fn checked_ilog2_not_android() { + assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); + assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); + assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); } #[test] -fn checked_log10() { - assert_eq!(0u8.checked_log10(), None); - assert_eq!(0u16.checked_log10(), None); - assert_eq!(0i8.checked_log10(), None); - assert_eq!(0i16.checked_log10(), None); +fn checked_ilog10() { + assert_eq!(0u8.checked_ilog10(), None); + assert_eq!(0u16.checked_ilog10(), None); + assert_eq!(0i8.checked_ilog10(), None); + assert_eq!(0i16.checked_ilog10(), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log10(), None); + assert_eq!(i.checked_ilog10(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=100_000u32 { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } } -macro_rules! log10_loop { - ($T:ty, $log10_max:expr) => { - assert_eq!(<$T>::MAX.log10(), $log10_max); - for i in 0..=$log10_max { +macro_rules! ilog10_loop { + ($T:ty, $ilog10_max:expr) => { + assert_eq!(<$T>::MAX.ilog10(), $ilog10_max); + for i in 0..=$ilog10_max { let p = (10 as $T).pow(i as u32); if p >= 10 { - assert_eq!((p - 9).log10(), i - 1); - assert_eq!((p - 1).log10(), i - 1); + assert_eq!((p - 9).ilog10(), i - 1); + assert_eq!((p - 1).ilog10(), i - 1); } - assert_eq!(p.log10(), i); - assert_eq!((p + 1).log10(), i); + assert_eq!(p.ilog10(), i); + assert_eq!((p + 1).ilog10(), i); if p >= 10 { - assert_eq!((p + 9).log10(), i); + assert_eq!((p + 9).ilog10(), i); } - // also check `x.log(10)` + // also check `x.ilog(10)` if p >= 10 { - assert_eq!((p - 9).log(10), i - 1); - assert_eq!((p - 1).log(10), i - 1); + assert_eq!((p - 9).ilog(10), i - 1); + assert_eq!((p - 1).ilog(10), i - 1); } - assert_eq!(p.log(10), i); - assert_eq!((p + 1).log(10), i); + assert_eq!(p.ilog(10), i); + assert_eq!((p + 1).ilog(10), i); if p >= 10 { - assert_eq!((p + 9).log(10), i); + assert_eq!((p + 9).ilog(10), i); } } }; } #[test] -fn log10_u8() { - log10_loop! { u8, 2 } +fn ilog10_u8() { + ilog10_loop! { u8, 2 } } #[test] -fn log10_u16() { - log10_loop! { u16, 4 } +fn ilog10_u16() { + ilog10_loop! { u16, 4 } } #[test] -fn log10_u32() { - log10_loop! { u32, 9 } +fn ilog10_u32() { + ilog10_loop! { u32, 9 } } #[test] -fn log10_u64() { - log10_loop! { u64, 19 } +fn ilog10_u64() { + ilog10_loop! { u64, 19 } } #[test] -fn log10_u128() { - log10_loop! { u128, 38 } +fn ilog10_u128() { + ilog10_loop! { u128, 38 } } diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 8b84a78e6..18c55e43a 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -338,6 +338,32 @@ macro_rules! int_module { assert_eq!(MIN.checked_next_multiple_of(-3), None); assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true)); + assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false)); + assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true)); + assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true)); + assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false)); + assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true)); + assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); + assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); + } } }; } diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 93ae620c2..15ae9f232 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -230,6 +230,28 @@ macro_rules! uint_module { assert_eq!((1 as $T).checked_next_multiple_of(0), None); assert_eq!(MAX.checked_next_multiple_of(2), None); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq!($T::MAX.carrying_add(1, true), (1, true)); + + assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + + assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } } }; } diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 12861794c..97a369810 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -650,7 +650,7 @@ fn thin_box() { .unwrap_or_else(|| handle_alloc_error(layout)) .cast::>(); ptr.as_ptr().write(meta); - ptr.cast::().as_ptr().add(offset).cast::().write(value); + ptr.as_ptr().byte_add(offset).cast::().write(value); Self { ptr, phantom: PhantomData } } } diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 103e8cc3a..50926da3c 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -95,15 +95,6 @@ fn test_unwrap_or() { assert_eq!(ok_err.unwrap_or(50), 50); } -#[test] -fn test_ok_or_err() { - let ok: Result = Ok(100); - let err: Result = Err(200); - - assert_eq!(ok.into_ok_or_err(), 100); - assert_eq!(err.into_ok_or_err(), 200); -} - #[test] fn test_unwrap_or_else() { fn handler(msg: &'static str) -> isize { diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 0656109e9..b8f6fe696 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1197,7 +1197,6 @@ fn chunks_mut_are_send_and_sync() { use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut}; use std::sync::MutexGuard; - #[allow(unused)] fn assert_send_and_sync() where ChunksMut<'static, Cell>: Send, @@ -1210,6 +1209,8 @@ fn chunks_mut_are_send_and_sync() { RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, { } + + assert_send_and_sync(); } #[test] diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs index d4b47a470..9d3f0b65f 100644 --- a/library/core/tests/str_lossy.rs +++ b/library/core/tests/str_lossy.rs @@ -1,85 +1,85 @@ -use core::str::lossy::*; +use core::str::Utf8Chunks; #[test] fn chunks() { - let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); + macro_rules! assert_chunks { + ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{ + let mut iter = Utf8Chunks::new($string); + $( + let chunk = iter.next().expect("missing chunk"); + assert_eq!($valid, chunk.valid()); + assert_eq!($invalid, chunk.invalid()); + )* + assert_eq!(None, iter.next()); + }}; + } - let mut iter = Utf8Lossy::from_bytes("ศไทย中åŽViệt Nam".as_bytes()).chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中åŽViệt Nam", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); + assert_chunks!(b"hello", ("hello", b"")); + assert_chunks!("ศไทย中åŽViệt Nam".as_bytes(), ("ศไทย中åŽViệt Nam", b"")); + assert_chunks!( + b"Hello\xC2 There\xFF Goodbye", + ("Hello", b"\xC2"), + (" There", b"\xFF"), + (" Goodbye", b""), + ); + assert_chunks!( + b"Hello\xC0\x80 There\xE6\x83 Goodbye", + ("Hello", b"\xC0"), + ("", b"\x80"), + (" There", b"\xE6\x83"), + (" Goodbye", b""), + ); + assert_chunks!( + b"\xF5foo\xF5\x80bar", + ("", b"\xF5"), + ("foo", b"\xF5"), + ("", b"\x80"), + ("bar", b""), + ); + assert_chunks!( + b"\xF1foo\xF1\x80bar\xF1\x80\x80baz", + ("", b"\xF1"), + ("foo", b"\xF1\x80"), + ("bar", b"\xF1\x80\x80"), + ("baz", b""), + ); + assert_chunks!( + b"\xF4foo\xF4\x80bar\xF4\xBFbaz", + ("", b"\xF4"), + ("foo", b"\xF4\x80"), + ("bar", b"\xF4"), + ("", b"\xBF"), + ("baz", b""), + ); + assert_chunks!( + b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar", + ("", b"\xF0"), + ("", b"\x80"), + ("", b"\x80"), + ("", b"\x80"), + ("foo\u{10000}bar", b""), + ); // surrogates - let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + assert_chunks!( + b"\xED\xA0\x80foo\xED\xBF\xBFbar", + ("", b"\xED"), + ("", b"\xA0"), + ("", b"\x80"), + ("foo", b"\xED"), + ("", b"\xBF"), + ("", b"\xBF"), + ("bar", b""), ); } #[test] fn debug() { assert_eq!( - "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", + "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"", &format!( "{:?}", - Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa") - ) + Utf8Chunks::new(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa").debug(), + ), ); } diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs index 18bb932f1..0fd824f8a 100644 --- a/library/panic_abort/src/android.rs +++ b/library/panic_abort/src/android.rs @@ -42,7 +42,7 @@ pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) { return; // allocation failure } copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len()); - buf.offset(msg.len() as isize).write(0); + buf.add(msg.len()).write(0); let func = transmute::(func_addr); func(buf); diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 8801c670b..cba8ef25d 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -113,27 +113,11 @@ pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { // binaries, but it should never be called as we don't link in an unwinding // runtime at all. pub mod personalities { - #[rustc_std_internal_symbol] - #[cfg(not(any( - all(target_family = "wasm", not(target_os = "emscripten")), - all(target_os = "windows", target_env = "gnu", target_arch = "x86_64",), - )))] - pub extern "C" fn rust_eh_personality() {} - - // On x86_64-pc-windows-gnu we use our own personality function that needs - // to return `ExceptionContinueSearch` as we're passing on all our frames. - #[rustc_std_internal_symbol] - #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86_64"))] - pub extern "C" fn rust_eh_personality( - _record: usize, - _frame: usize, - _context: usize, - _dispatcher: usize, - ) -> u32 { - 1 // `ExceptionContinueSearch` - } + // In the past this module used to contain stubs for the personality + // functions of various platforms, but these where removed when personality + // functions were moved to std. - // Similar to above, this corresponds to the `eh_catch_typeinfo` lang item + // This corresponds to the `eh_catch_typeinfo` lang item // that's only used on Emscripten currently. // // Since panics don't generate exceptions and foreign exceptions are @@ -143,13 +127,4 @@ pub mod personalities { #[allow(non_upper_case_globals)] #[cfg(target_os = "emscripten")] static rust_eh_catch_typeinfo: [usize; 2] = [0; 2]; - - // These two are called by our startup objects on i686-pc-windows-gnu, but - // they don't need to do anything so the bodies are nops. - #[rustc_std_internal_symbol] - #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))] - pub extern "C" fn rust_eh_register_frames() {} - #[rustc_std_internal_symbol] - #[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))] - pub extern "C" fn rust_eh_unregister_frames() {} } diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs deleted file mode 100644 index 7394feab8..000000000 --- a/library/panic_unwind/src/dwarf/eh.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Parsing of GCC-style Language-Specific Data Area (LSDA) -//! For details see: -//! * -//! * -//! * -//! * -//! -//! A reference implementation may be found in the GCC source tree -//! (`/libgcc/unwind-c.c` as of this writing). - -#![allow(non_upper_case_globals)] -#![allow(unused)] - -use crate::dwarf::DwarfReader; -use core::mem; - -pub const DW_EH_PE_omit: u8 = 0xFF; -pub const DW_EH_PE_absptr: u8 = 0x00; - -pub const DW_EH_PE_uleb128: u8 = 0x01; -pub const DW_EH_PE_udata2: u8 = 0x02; -pub const DW_EH_PE_udata4: u8 = 0x03; -pub const DW_EH_PE_udata8: u8 = 0x04; -pub const DW_EH_PE_sleb128: u8 = 0x09; -pub const DW_EH_PE_sdata2: u8 = 0x0A; -pub const DW_EH_PE_sdata4: u8 = 0x0B; -pub const DW_EH_PE_sdata8: u8 = 0x0C; - -pub const DW_EH_PE_pcrel: u8 = 0x10; -pub const DW_EH_PE_textrel: u8 = 0x20; -pub const DW_EH_PE_datarel: u8 = 0x30; -pub const DW_EH_PE_funcrel: u8 = 0x40; -pub const DW_EH_PE_aligned: u8 = 0x50; - -pub const DW_EH_PE_indirect: u8 = 0x80; - -#[derive(Copy, Clone)] -pub struct EHContext<'a> { - pub ip: usize, // Current instruction pointer - pub func_start: usize, // Address of the current function - pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section - pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section -} - -pub enum EHAction { - None, - Cleanup(usize), - Catch(usize), - Terminate, -} - -pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); - -pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { - if lsda.is_null() { - return Ok(EHAction::None); - } - - let func_start = context.func_start; - let mut reader = DwarfReader::new(lsda); - - let start_encoding = reader.read::(); - // base address for landing pad offsets - let lpad_base = if start_encoding != DW_EH_PE_omit { - read_encoded_pointer(&mut reader, context, start_encoding)? - } else { - func_start - }; - - let ttype_encoding = reader.read::(); - if ttype_encoding != DW_EH_PE_omit { - // Rust doesn't analyze exception types, so we don't care about the type table - reader.read_uleb128(); - } - - let call_site_encoding = reader.read::(); - let call_site_table_length = reader.read_uleb128(); - let action_table = reader.ptr.offset(call_site_table_length as isize); - let ip = context.ip; - - if !USING_SJLJ_EXCEPTIONS { - while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?; - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?; - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?; - let cs_action = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start + cs_start { - break; - } - if ip < func_start + cs_start + cs_len { - if cs_lpad == 0 { - return Ok(EHAction::None); - } else { - let lpad = lpad_base + cs_lpad; - return Ok(interpret_cs_action(cs_action, lpad)); - } - } - } - // Ip is not present in the table. This should not happen... but it does: issue #35011. - // So rather than returning EHAction::Terminate, we do this. - Ok(EHAction::None) - } else { - // SjLj version: - // The "IP" is an index into the call-site table, with two exceptions: - // -1 means 'no-action', and 0 means 'terminate'. - match ip as isize { - -1 => return Ok(EHAction::None), - 0 => return Ok(EHAction::Terminate), - _ => (), - } - let mut idx = ip; - loop { - let cs_lpad = reader.read_uleb128(); - let cs_action = reader.read_uleb128(); - idx -= 1; - if idx == 0 { - // Can never have null landing pad for sjlj -- that would have - // been indicated by a -1 call site index. - let lpad = (cs_lpad + 1) as usize; - return Ok(interpret_cs_action(cs_action, lpad)); - } - } - } -} - -fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { - if cs_action == 0 { - // If cs_action is 0 then this is a cleanup (Drop::drop). We run these - // for both Rust panics and foreign exceptions. - EHAction::Cleanup(lpad) - } else { - // Stop unwinding Rust panics at catch_unwind. - EHAction::Catch(lpad) - } -} - -#[inline] -fn round_up(unrounded: usize, align: usize) -> Result { - if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) } -} - -unsafe fn read_encoded_pointer( - reader: &mut DwarfReader, - context: &EHContext<'_>, - encoding: u8, -) -> Result { - if encoding == DW_EH_PE_omit { - return Err(()); - } - - // DW_EH_PE_aligned implies it's an absolute pointer value - if encoding == DW_EH_PE_aligned { - reader.ptr = round_up(reader.ptr as usize, mem::size_of::())? as *const u8; - return Ok(reader.read::()); - } - - let mut result = match encoding & 0x0F { - DW_EH_PE_absptr => reader.read::(), - DW_EH_PE_uleb128 => reader.read_uleb128() as usize, - DW_EH_PE_udata2 => reader.read::() as usize, - DW_EH_PE_udata4 => reader.read::() as usize, - DW_EH_PE_udata8 => reader.read::() as usize, - DW_EH_PE_sleb128 => reader.read_sleb128() as usize, - DW_EH_PE_sdata2 => reader.read::() as usize, - DW_EH_PE_sdata4 => reader.read::() as usize, - DW_EH_PE_sdata8 => reader.read::() as usize, - _ => return Err(()), - }; - - result += match encoding & 0x70 { - DW_EH_PE_absptr => 0, - // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => reader.ptr as usize, - DW_EH_PE_funcrel => { - if context.func_start == 0 { - return Err(()); - } - context.func_start - } - DW_EH_PE_textrel => (*context.get_text_start)(), - DW_EH_PE_datarel => (*context.get_data_start)(), - _ => return Err(()), - }; - - if encoding & DW_EH_PE_indirect != 0 { - result = *(result as *const usize); - } - - Ok(result) -} diff --git a/library/panic_unwind/src/dwarf/mod.rs b/library/panic_unwind/src/dwarf/mod.rs deleted file mode 100644 index 652fbe95a..000000000 --- a/library/panic_unwind/src/dwarf/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Utilities for parsing DWARF-encoded data streams. -//! See , -//! DWARF-4 standard, Section 7 - "Data Representation" - -// This module is used only by x86_64-pc-windows-gnu for now, but we -// are compiling it everywhere to avoid regressions. -#![allow(unused)] - -#[cfg(test)] -mod tests; - -pub mod eh; - -use core::mem; - -pub struct DwarfReader { - pub ptr: *const u8, -} - -#[repr(C, packed)] -struct Unaligned(T); - -impl DwarfReader { - pub fn new(ptr: *const u8) -> DwarfReader { - DwarfReader { ptr } - } - - // DWARF streams are packed, so e.g., a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. - pub unsafe fn read(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned); - self.ptr = self.ptr.add(mem::size_of::()); - result - } - - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". - pub unsafe fn read_uleb128(&mut self) -> u64 { - let mut shift: usize = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - result - } - - pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: u32 = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < u64::BITS && (byte & 0x40) != 0 { - result |= (!0 as u64) << shift; - } - result as i64 - } -} diff --git a/library/panic_unwind/src/dwarf/tests.rs b/library/panic_unwind/src/dwarf/tests.rs deleted file mode 100644 index 1644f3708..000000000 --- a/library/panic_unwind/src/dwarf/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; - -#[test] -fn dwarf_reader() { - let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF]; - - let mut reader = DwarfReader::new(encoded.as_ptr()); - - unsafe { - assert!(reader.read::() == u8::to_be(1u8)); - assert!(reader.read::() == u16::to_be(0x0203)); - assert!(reader.read::() == u32::to_be(0x04050607)); - - assert!(reader.read_uleb128() == 624485); - assert!(reader.read_sleb128() == -624485); - - assert!(reader.read::() == i8::to_be(-1)); - } -} diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index 1ee69ff9c..7c233c7c3 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -12,7 +12,6 @@ use core::intrinsics; use core::mem; use core::ptr; use core::sync::atomic::{AtomicBool, Ordering}; -use libc::{self, c_int}; use unwind as uw; // This matches the layout of std::type_info in C++ @@ -105,21 +104,6 @@ extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void { } } -// This is required by the compiler to exist (e.g., it's a lang item), but it's -// never actually called by the compiler. Emscripten EH doesn't use a -// personality function at all, it instead uses __cxa_find_matching_catch. -// Wasm error handling would use __gxx_personality_wasm0. -#[lang = "eh_personality"] -unsafe extern "C" fn rust_eh_personality( - _version: c_int, - _actions: uw::_Unwind_Action, - _exception_class: uw::_Unwind_Exception_Class, - _exception_object: *mut uw::_Unwind_Exception, - _context: *mut uw::_Unwind_Context, -) -> uw::_Unwind_Reason_Code { - core::intrinsics::abort() -} - extern "C" { fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void; fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void; diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index a59659231..261404e87 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -39,8 +39,6 @@ use alloc::boxed::Box; use core::any::Any; -use crate::dwarf::eh::{self, EHAction, EHContext}; -use libc::{c_int, uintptr_t}; use unwind as uw; #[repr(C)] @@ -89,263 +87,3 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { // M O Z \0 R U S T -- vendor, language 0x4d4f5a_00_52555354 } - -// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() -// and TargetLowering::getExceptionSelectorRegister() for each architecture, -// then mapped to DWARF register numbers via register definition tables -// (typically RegisterInfo.td, search for "DwarfRegNum"). -// See also https://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. - -#[cfg(target_arch = "x86")] -const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX - -#[cfg(target_arch = "x86_64")] -const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX - -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 - -#[cfg(target_arch = "m68k")] -const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1 - -#[cfg(any(target_arch = "mips", target_arch = "mips64"))] -const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 - -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 - -#[cfg(target_arch = "s390x")] -const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 - -#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] -const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 - -#[cfg(target_arch = "hexagon")] -const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 - -#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] -const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 - -// The following code is based on GCC's C and C++ personality routines. For reference, see: -// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc -// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c - -cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { - // ARM EHABI personality routine. - // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf - // - // iOS uses the default routine instead since it uses SjLj unwinding. - #[lang = "eh_personality"] - unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, - exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - let state = state as c_int; - let action = state & uw::_US_ACTION_MASK as c_int; - let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { - // Backtraces on ARM will call the personality routine with - // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases - // we want to continue unwinding the stack, otherwise all our backtraces - // would end at __rust_try - if state & uw::_US_FORCE_UNWIND as c_int != 0 { - return continue_unwind(exception_object, context); - } - true - } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { - false - } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int { - return continue_unwind(exception_object, context); - } else { - return uw::_URC_FAILURE; - }; - - // The DWARF unwinder assumes that _Unwind_Context holds things like the function - // and LSDA pointers, however ARM EHABI places them into the exception object. - // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which - // take only the context pointer, GCC personality routines stash a pointer to - // exception_object in the context, using location reserved for ARM's - // "scratch register" (r12). - uw::_Unwind_SetGR(context, - uw::UNWIND_POINTER_REG, - exception_object as uw::_Unwind_Ptr); - // ...A more principled approach would be to provide the full definition of ARM's - // _Unwind_Context in our libunwind bindings and fetch the required data from there - // directly, bypassing DWARF compatibility functions. - - let eh_action = match find_eh_action(context) { - Ok(action) => action, - Err(_) => return uw::_URC_FAILURE, - }; - if search_phase { - match eh_action { - EHAction::None | - EHAction::Cleanup(_) => return continue_unwind(exception_object, context), - EHAction::Catch(_) => { - // EHABI requires the personality routine to update the - // SP value in the barrier cache of the exception object. - (*exception_object).private[5] = - uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG); - return uw::_URC_HANDLER_FOUND; - } - EHAction::Terminate => return uw::_URC_FAILURE, - } - } else { - match eh_action { - EHAction::None => return continue_unwind(exception_object, context), - EHAction::Cleanup(lpad) | - EHAction::Catch(lpad) => { - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, - exception_object as uintptr_t); - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); - uw::_Unwind_SetIP(context, lpad); - return uw::_URC_INSTALL_CONTEXT; - } - EHAction::Terminate => return uw::_URC_FAILURE, - } - } - - // On ARM EHABI the personality routine is responsible for actually - // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). - unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON { - uw::_URC_CONTINUE_UNWIND - } else { - uw::_URC_FAILURE - } - } - // defined in libgcc - extern "C" { - fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } - } - } else { - // Default personality routine, which is used directly on most targets - // and indirectly on Windows x86_64 via SEH. - unsafe extern "C" fn rust_eh_personality_impl(version: c_int, - actions: uw::_Unwind_Action, - _exception_class: uw::_Unwind_Exception_Class, - exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - if version != 1 { - return uw::_URC_FATAL_PHASE1_ERROR; - } - let eh_action = match find_eh_action(context) { - Ok(action) => action, - Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, - }; - if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { - match eh_action { - EHAction::None | - EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND, - EHAction::Catch(_) => uw::_URC_HANDLER_FOUND, - EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR, - } - } else { - match eh_action { - EHAction::None => uw::_URC_CONTINUE_UNWIND, - EHAction::Cleanup(lpad) | - EHAction::Catch(lpad) => { - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, - exception_object as uintptr_t); - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); - uw::_Unwind_SetIP(context, lpad); - uw::_URC_INSTALL_CONTEXT - } - EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR, - } - } - } - - cfg_if::cfg_if! { - if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] { - // On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind - // handler data (aka LSDA) uses GCC-compatible encoding. - #[lang = "eh_personality"] - #[allow(nonstandard_style)] - unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut uw::EXCEPTION_RECORD, - establisherFrame: uw::LPVOID, - contextRecord: *mut uw::CONTEXT, - dispatcherContext: *mut uw::DISPATCHER_CONTEXT) - -> uw::EXCEPTION_DISPOSITION { - uw::_GCC_specific_handler(exceptionRecord, - establisherFrame, - contextRecord, - dispatcherContext, - rust_eh_personality_impl) - } - } else { - // The personality routine for most of our targets. - #[lang = "eh_personality"] - unsafe extern "C" fn rust_eh_personality(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - rust_eh_personality_impl(version, - actions, - exception_class, - exception_object, - context) - } - } - } - } -} - -unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result { - let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; - let mut ip_before_instr: c_int = 0; - let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); - let eh_context = EHContext { - // The return address points 1 byte past the call instruction, - // which could be in the next IP range in LSDA range table. - // - // `ip = -1` has special meaning, so use wrapping sub to allow for that - ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) }, - func_start: uw::_Unwind_GetRegionStart(context), - get_text_start: &|| uw::_Unwind_GetTextRelBase(context), - get_data_start: &|| uw::_Unwind_GetDataRelBase(context), - }; - eh::find_eh_action(lsda, &eh_context) -} - -// Frame unwind info registration -// -// Each module's image contains a frame unwind info section (usually -// ".eh_frame"). When a module is loaded/unloaded into the process, the -// unwinder must be informed about the location of this section in memory. The -// methods of achieving that vary by the platform. On some (e.g., Linux), the -// unwinder can discover unwind info sections on its own (by dynamically -// enumerating currently loaded modules via the dl_iterate_phdr() API and -// finding their ".eh_frame" sections); Others, like Windows, require modules -// to actively register their unwind info sections via unwinder API. -// -// This module defines two symbols which are referenced and called from -// rsbegin.rs to register our information with the GCC runtime. The -// implementation of stack unwinding is (for now) deferred to libgcc_eh, however -// Rust crates use these Rust-specific entry points to avoid potential clashes -// with any GCC runtime. -#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] -pub mod eh_frame_registry { - extern "C" { - fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8); - fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8); - } - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8) { - __register_frame_info(eh_frame_begin, object); - } - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8) { - __deregister_frame_info(eh_frame_begin, object); - } -} diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index f9acb42c4..1eb4f3789 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -52,9 +52,6 @@ cfg_if::cfg_if! { all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { - // Rust runtime's startup objects depend on these symbols, so make them public. - #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] - pub use real_imp::eh_frame_registry::*; #[path = "gcc.rs"] mod real_imp; } else { @@ -92,8 +89,6 @@ extern "C" { fn __rust_foreign_exception() -> !; } -mod dwarf; - #[rustc_std_internal_symbol] #[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) { diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 9f1eb411f..6b8d06568 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -256,7 +256,7 @@ cfg_if::cfg_if! { } pub unsafe fn panic(data: Box) -> u32 { - use core::intrinsics::atomic_store; + use core::intrinsics::atomic_store_seqcst; // _CxxThrowException executes entirely on this stack frame, so there's no // need to otherwise transfer `data` to the heap. We just pass a stack @@ -288,20 +288,23 @@ pub unsafe fn panic(data: Box) -> u32 { // // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). - atomic_store(&mut THROW_INFO.pmfnUnwind as *mut _ as *mut u32, ptr!(exception_cleanup) as u32); - atomic_store( + atomic_store_seqcst( + &mut THROW_INFO.pmfnUnwind as *mut _ as *mut u32, + ptr!(exception_cleanup) as u32, + ); + atomic_store_seqcst( &mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32, ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32, ); - atomic_store( + atomic_store_seqcst( &mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32, ptr!(&CATCHABLE_TYPE as *const _) as u32, ); - atomic_store( + atomic_store_seqcst( &mut CATCHABLE_TYPE.pType as *mut _ as *mut u32, ptr!(&TYPE_DESCRIPTOR as *const _) as u32, ); - atomic_store( + atomic_store_seqcst( &mut CATCHABLE_TYPE.copyFunction as *mut _ as *mut u32, ptr!(exception_copy) as u32, ); @@ -323,13 +326,3 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box { exception.data.take().unwrap() } } - -// This is required by the compiler to exist (e.g., it's a lang item), but -// it's never actually called by the compiler because __C_specific_handler -// or _except_handler3 is the personality function that is always used. -// Hence this is just an aborting stub. -#[lang = "eh_personality"] -#[cfg(not(test))] -fn rust_eh_personality() { - core::intrinsics::abort() -} diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs index 65d3ce9be..2235f016c 100644 --- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs +++ b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs @@ -70,7 +70,7 @@ impl_integer_intrinsic! { impl ToBitMask for Mask<_, 64> } -/// Returns the minimum numnber of bytes in a bitmask with `lanes` lanes. +/// Returns the minimum number of bytes in a bitmask with `lanes` lanes. #[cfg(feature = "generic_const_exprs")] pub const fn bitmask_len(lanes: usize) -> usize { (lanes + 7) / 8 diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs index 4bd4d4c05..4ac60b10c 100644 --- a/library/portable-simd/crates/std_float/src/lib.rs +++ b/library/portable-simd/crates/std_float/src/lib.rs @@ -1,9 +1,5 @@ #![cfg_attr(feature = "as_crate", no_std)] // We are std! -#![cfg_attr( - feature = "as_crate", - feature(platform_intrinsics), - feature(portable_simd) -)] +#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))] #[cfg(not(feature = "as_crate"))] use core::simd; #[cfg(feature = "as_crate")] diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 1516f084a..4461b2180 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -176,8 +176,6 @@ define_handles! { FreeFunctions, TokenStream, SourceFile, - MultiSpan, - Diagnostic, 'interned: Span, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 5cde966bf..4c1e196b5 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -57,6 +57,7 @@ macro_rules! with_api { fn track_env_var(var: &str, value: Option<&str>); fn track_path(path: &str); fn literal_from_str(s: &str) -> Result, ()>; + fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); }, TokenStream { fn drop($self: $S::TokenStream); @@ -87,22 +88,6 @@ macro_rules! with_api { fn path($self: &$S::SourceFile) -> String; fn is_real($self: &$S::SourceFile) -> bool; }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, Span { fn debug($self: $S::Span) -> String; fn source_file($self: $S::Span) -> $S::SourceFile; @@ -510,6 +495,18 @@ compound_traits!( } ); +#[derive(Clone, Debug)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub spans: Vec, + pub children: Vec>, +} + +compound_traits!( + struct Diagnostic { level, message, spans, children } +); + /// Globals provided alongside the initial inputs for a macro expansion. /// Provides values such as spans which are used frequently to avoid RPC. #[derive(Clone)] diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index e068ec60b..8202c40d6 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -2,6 +2,7 @@ use super::*; +use std::cell::Cell; use std::marker::PhantomData; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. @@ -11,8 +12,6 @@ pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } @@ -145,6 +144,38 @@ pub trait ExecutionStrategy { ) -> Buffer; } +thread_local! { + /// While running a proc-macro with the same-thread executor, this flag will + /// be set, forcing nested proc-macro invocations (e.g. due to + /// `TokenStream::expand_expr`) to be run using a cross-thread executor. + /// + /// This is required as the thread-local state in the proc_macro client does + /// not handle being re-entered, and will invalidate all `Symbol`s when + /// entering a nested macro. + static ALREADY_RUNNING_SAME_THREAD: Cell = Cell::new(false); +} + +/// Keep `ALREADY_RUNNING_SAME_THREAD` (see also its documentation) +/// set to `true`, preventing same-thread reentrance. +struct RunningSameThreadGuard(()); + +impl RunningSameThreadGuard { + fn new() -> Self { + let already_running = ALREADY_RUNNING_SAME_THREAD.replace(true); + assert!( + !already_running, + "same-thread nesting (\"reentrance\") of proc macro executions is not supported" + ); + RunningSameThreadGuard(()) + } +} + +impl Drop for RunningSameThreadGuard { + fn drop(&mut self) { + ALREADY_RUNNING_SAME_THREAD.set(false); + } +} + pub struct MaybeCrossThread

- - - Borrowed({__0}) - Owned({__0}) - - __0 - - diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 5f5b48bc1..be7de3eba 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -10,7 +10,7 @@ set -Eeuo pipefail # https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570 unset GIT_DIR ROOT_DIR="$(git rev-parse --show-toplevel)" -COMMAND="$ROOT_DIR/x.py test tidy --bless" +COMMAND="$ROOT_DIR/x.py test tidy" if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then COMMAND="python $COMMAND" diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index bbc945a7d..bf512bc99 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -31,6 +31,7 @@ class RustType(object): STD_REF = "StdRef" STD_REF_MUT = "StdRefMut" STD_REF_CELL = "StdRefCell" + STD_NONZERO_NUMBER = "StdNonZeroNumber" STD_STRING_REGEX = re.compile(r"^(alloc::(\w+::)+)String$") @@ -49,6 +50,7 @@ STD_CELL_REGEX = re.compile(r"^(core::(\w+::)+)Cell<.+>$") STD_REF_REGEX = re.compile(r"^(core::(\w+::)+)Ref<.+>$") STD_REF_MUT_REGEX = re.compile(r"^(core::(\w+::)+)RefMut<.+>$") STD_REF_CELL_REGEX = re.compile(r"^(core::(\w+::)+)RefCell<.+>$") +STD_NONZERO_NUMBER_REGEX = re.compile(r"^core::num::([a-z_]+::)*NonZero.+$") TUPLE_ITEM_REGEX = re.compile(r"__\d+$") @@ -72,6 +74,7 @@ STD_TYPE_TO_REGEX = { RustType.STD_REF_MUT: STD_REF_MUT_REGEX, RustType.STD_REF_CELL: STD_REF_CELL_REGEX, RustType.STD_CELL: STD_CELL_REGEX, + RustType.STD_NONZERO_NUMBER: STD_NONZERO_NUMBER_REGEX, } def is_tuple_fields(fields): diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index ddaa7438e..7bc35c7d5 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,18 +10,19 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.11", default-features = false, features = ["config"] } atty = "0.2" +itertools = "0.10.1" +minifier = "0.2.2" +once_cell = "1.10.0" pulldown-cmark = { version = "0.9.2", default-features = false } -minifier = "0.2.1" -serde = { version = "1.0", features = ["derive"] } +regex = "1" +rustdoc-json-types = { path = "../rustdoc-json-types" } serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } smallvec = "1.8.1" tempfile = "3" -itertools = "0.10.1" -regex = "1" -rustdoc-json-types = { path = "../rustdoc-json-types" } +thin-vec = "0.2.8" tracing = "0.1" tracing-tree = "0.2.0" -once_cell = "1.10.0" [dependencies.tracing-subscriber] version = "0.3.3" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index af33c1a6a..175472797 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -123,7 +123,7 @@ where kind: Box::new(ImplItem(Box::new(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, - trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])), + trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())), for_: clean_middle_ty(ty, self.cx, None), items: Vec::new(), polarity, @@ -476,7 +476,7 @@ where let mut ty_to_fn: FxHashMap)> = Default::default(); for p in clean_where_predicates { - let (orig_p, p) = (p, p.clean(self.cx)); + let (orig_p, p) = (p, clean_predicate(p, self.cx)); if p.is_none() { continue; } @@ -525,8 +525,8 @@ where GenericBound::TraitBound(ref mut p, _) => { // Insert regions into the for_generics hash map first, to ensure // that we don't end up with duplicate bounds (e.g., for<'b, 'b>) - for_generics.extend(p.generic_params.clone()); - p.generic_params = for_generics.into_iter().collect(); + for_generics.extend(p.generic_params.drain(..)); + p.generic_params.extend(for_generics); self.is_fn_trait(&p.trait_) } _ => false, @@ -551,13 +551,15 @@ where } WherePredicate::EqPredicate { lhs, rhs } => { match lhs { - Type::QPath { ref assoc, ref self_type, ref trait_, .. } => { + Type::QPath(box QPathData { + ref assoc, ref self_type, ref trait_, .. + }) => { let ty = &*self_type; let mut new_trait = trait_.clone(); if self.is_fn_trait(trait_) && assoc.name == sym::Output { ty_to_fn - .entry(*ty.clone()) + .entry(ty.clone()) .and_modify(|e| { *e = (e.0.clone(), Some(rhs.ty().unwrap().clone())) }) @@ -582,7 +584,7 @@ where // to 'T: Iterator' GenericArgs::AngleBracketed { ref mut bindings, .. } => { bindings.push(TypeBinding { - assoc: *assoc.clone(), + assoc: assoc.clone(), kind: TypeBindingKind::Equality { term: rhs }, }); } @@ -596,7 +598,7 @@ where } } - let bounds = ty_to_bounds.entry(*ty.clone()).or_default(); + let bounds = ty_to_bounds.entry(ty.clone()).or_default(); bounds.insert(GenericBound::TraitBound( PolyTrait { trait_: new_trait, generic_params: Vec::new() }, @@ -613,7 +615,7 @@ where )); // Avoid creating any new duplicate bounds later in the outer // loop - ty_to_traits.entry(*ty.clone()).or_default().insert(trait_.clone()); + ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone()); } _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 01dd95e6e..cc734389e 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -115,12 +115,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])), + trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, ThinVec::new())), for_: clean_middle_ty(ty.0, cx, None), items: cx.tcx .associated_items(impl_def_id) .in_definition_order() - .map(|x| x.clean(cx)) + .map(|x| clean_middle_assoc_item(x, cx)) .collect::>(), polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 58d0aedb0..df0e9f7cc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -3,9 +3,10 @@ use std::iter::once; use std::sync::Arc; +use thin_vec::ThinVec; + use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -16,15 +17,14 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ - self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, - clean_trait_ref_with_bindings, clean_ty, clean_ty_generics, clean_variant_def, - clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility, + self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, + clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, + clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt, + ImplKind, ItemId, Type, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; -type Attrs<'hir> = &'hir [ast::Attribute]; - /// Attempt to inline a definition into this AST. /// /// This function will fetch the definition specified, and if it is @@ -45,7 +45,7 @@ pub(crate) fn try_inline( import_def_id: Option, res: Res, name: Symbol, - attrs: Option>, + attrs: Option<&[ast::Attribute]>, visited: &mut FxHashSet, ) -> Option> { let did = res.opt_def_id()?; @@ -61,7 +61,7 @@ pub(crate) fn try_inline( Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, ItemType::Trait); build_impls(cx, Some(parent_module), did, attrs, &mut ret); - clean::TraitItem(build_external_trait(cx, did)) + clean::TraitItem(Box::new(build_external_trait(cx, did))) } Res::Def(DefKind::Fn, did) => { record_extern_fqn(cx, did, ItemType::Function); @@ -171,7 +171,7 @@ pub(crate) fn try_inline_glob( } } -pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { +pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [ast::Attribute] { cx.tcx.get_attrs_unchecked(did) } @@ -217,7 +217,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean // which causes methods to have a `pub` prefix, which is invalid since items in traits // can not have a visibility prefix. Thus we override the visibility here manually. // See https://github.com/rust-lang/rust/issues/81274 - clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) } + clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) } }) .collect(); @@ -286,7 +286,7 @@ pub(crate) fn build_impls( cx: &mut DocContext<'_>, parent_module: Option, did: DefId, - attrs: Option>, + attrs: Option<&[ast::Attribute]>, ret: &mut Vec, ) { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); @@ -296,14 +296,29 @@ pub(crate) fn build_impls( for &did in tcx.inherent_impls(did).iter() { build_impl(cx, parent_module, did, attrs, ret); } + + // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate. + // See also: + // + // * https://github.com/rust-lang/rust/issues/103170 — where it didn't used to get documented + // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used + // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error + if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { + use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*; + let type_ = + if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; + for &did in tcx.incoherent_impls(type_) { + build_impl(cx, parent_module, did, attrs, ret); + } + } } /// `parent_module` refers to the parent of the re-export, not the original item -fn merge_attrs( +pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, parent_module: Option, - old_attrs: Attrs<'_>, - new_attrs: Option>, + old_attrs: &[ast::Attribute], + new_attrs: Option<&[ast::Attribute]>, ) -> (clean::Attributes, Option>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export @@ -330,7 +345,7 @@ pub(crate) fn build_impl( cx: &mut DocContext<'_>, parent_module: Option, did: DefId, - attrs: Option>, + attrs: Option<&[ast::Attribute]>, ret: &mut Vec, ) { if !cx.inlined.insert(did.into()) { @@ -426,9 +441,9 @@ pub(crate) fn build_impl( true } }) - .map(|item| item.clean(cx)) + .map(|item| clean_impl_item(item, cx)) .collect::>(), - impl_.generics.clean(cx), + clean_generics(impl_.generics, cx), ), None => ( tcx.associated_items(did) @@ -452,7 +467,7 @@ pub(crate) fn build_impl( item.visibility(tcx).is_public() } }) - .map(|item| item.clean(cx)) + .map(|item| clean_middle_assoc_item(item, cx)) .collect::>(), clean::enter_impl_trait(cx, |cx| { clean_ty_generics(cx, tcx.generics_of(did), predicates) @@ -460,7 +475,7 @@ pub(crate) fn build_impl( ), }; let polarity = tcx.impl_polarity(did); - let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[])); + let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, ThinVec::new())); if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { super::build_deref_target_impls(cx, &trait_items, ret); } @@ -671,7 +686,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: g.where_predicates.retain(|pred| match pred { clean::WherePredicate::BoundPredicate { - ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, .. }, + ty: clean::QPath(box clean::QPathData { self_type: clean::Generic(ref s), trait_, .. }), bounds, .. } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 929f5f89b..c8875c272 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -33,7 +33,8 @@ use std::collections::hash_map::Entry; use std::collections::BTreeMap; use std::default::Default; use std::hash::Hash; -use std::{mem, vec}; +use std::mem; +use thin_vec::ThinVec; use crate::core::{self, DocContext, ImplTraitParam}; use crate::formats::item_type::ItemType; @@ -44,128 +45,126 @@ use utils::*; pub(crate) use self::types::*; pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res}; -pub(crate) trait Clean<'tcx, T> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> T; -} +pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item { + let mut items: Vec = vec![]; + let mut inserted = FxHashSet::default(); + items.extend(doc.foreigns.iter().map(|(item, renamed)| { + let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); + if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { + inserted.insert((item.type_(), name)); + } + item + })); + items.extend(doc.mods.iter().filter_map(|x| { + if !inserted.insert((ItemType::Module, x.name)) { + return None; + } + let item = clean_doc_module(x, cx); + if item.attrs.lists(sym::doc).has_word(sym::hidden) { + // Hidden modules are stripped at a later stage. + // If a hidden module has the same name as a visible one, we want + // to keep both of them around. + inserted.remove(&(ItemType::Module, x.name)); + } + Some(item) + })); -impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let mut items: Vec = vec![]; - let mut inserted = FxHashSet::default(); - items.extend(self.foreigns.iter().map(|(item, renamed)| { - let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); - if let Some(name) = item.name { + // Split up imports from all other items. + // + // This covers the case where somebody does an import which should pull in an item, + // but there's already an item with the same namespace and same name. Rust gives + // priority to the not-imported one, so we should, too. + items.extend(doc.items.iter().flat_map(|(item, renamed)| { + // First, lower everything other than imports. + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + return Vec::new(); + } + let v = clean_maybe_renamed_item(cx, item, *renamed); + for item in &v { + if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { inserted.insert((item.type_(), name)); } - item - })); - items.extend(self.mods.iter().map(|x| { - inserted.insert((ItemType::Module, x.name)); - x.clean(cx) - })); - - // Split up imports from all other items. - // - // This covers the case where somebody does an import which should pull in an item, - // but there's already an item with the same namespace and same name. Rust gives - // priority to the not-imported one, so we should, too. - items.extend(self.items.iter().flat_map(|(item, renamed)| { - // First, lower everything other than imports. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - return Vec::new(); - } - let v = clean_maybe_renamed_item(cx, item, *renamed); - for item in &v { - if let Some(name) = item.name { - inserted.insert((item.type_(), name)); - } - } - v - })); - items.extend(self.items.iter().flat_map(|(item, renamed)| { - // Now we actually lower the imports, skipping everything else. - if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); - clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) - } else { - // skip everything else - Vec::new() - } - })); - - // determine if we should display the inner contents or - // the outer `mod` item for the source code. - - let span = Span::new({ - let where_outer = self.where_outer(cx.tcx); - let sm = cx.sess().source_map(); - let outer = sm.lookup_char_pos(where_outer.lo()); - let inner = sm.lookup_char_pos(self.where_inner.lo()); - if outer.file.start_pos == inner.file.start_pos { - // mod foo { ... } - where_outer - } else { - // mod foo; (and a separate SourceFile for the contents) - self.where_inner - } - }); + } + v + })); + items.extend(doc.items.iter().flat_map(|(item, renamed)| { + // Now we actually lower the imports, skipping everything else. + if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { + let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) + } else { + // skip everything else + Vec::new() + } + })); + + // determine if we should display the inner contents or + // the outer `mod` item for the source code. + + let span = Span::new({ + let where_outer = doc.where_outer(cx.tcx); + let sm = cx.sess().source_map(); + let outer = sm.lookup_char_pos(where_outer.lo()); + let inner = sm.lookup_char_pos(doc.where_inner.lo()); + if outer.file.start_pos == inner.file.start_pos { + // mod foo { ... } + where_outer + } else { + // mod foo; (and a separate SourceFile for the contents) + doc.where_inner + } + }); - Item::from_hir_id_and_parts( - self.id, - Some(self.name), - ModuleItem(Module { items, span }), - cx, - ) - } + Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx) } -impl<'tcx> Clean<'tcx, Option> for hir::GenericBound<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - Some(match *self { - hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), - hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { - let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - - let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); - - let generic_args = generic_args.clean(cx); - let GenericArgs::AngleBracketed { bindings, .. } = generic_args - else { - bug!("clean: parenthesized `GenericBound::LangItemTrait`"); - }; +fn clean_generic_bound<'tcx>( + bound: &hir::GenericBound<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + Some(match *bound { + hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), + hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { + let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); + + let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); + + let generic_args = clean_generic_args(generic_args, cx); + let GenericArgs::AngleBracketed { bindings, .. } = generic_args + else { + bug!("clean: parenthesized `GenericBound::LangItemTrait`"); + }; - let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings); - GenericBound::TraitBound( - PolyTrait { trait_, generic_params: vec![] }, - hir::TraitBoundModifier::None, - ) + let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings); + GenericBound::TraitBound( + PolyTrait { trait_, generic_params: vec![] }, + hir::TraitBoundModifier::None, + ) + } + hir::GenericBound::Trait(ref t, modifier) => { + // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. + if modifier == hir::TraitBoundModifier::MaybeConst + && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) + { + return None; } - hir::GenericBound::Trait(ref t, modifier) => { - // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if modifier == hir::TraitBoundModifier::MaybeConst - && cx.tcx.lang_items().destruct_trait() - == Some(t.trait_ref.trait_def_id().unwrap()) - { - return None; - } - GenericBound::TraitBound(t.clean(cx), modifier) - } - }) - } + GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) + } + }) } pub(crate) fn clean_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, trait_ref: ty::TraitRef<'tcx>, - bindings: &[TypeBinding], + bindings: ThinVec, ) -> Path { let kind = cx.tcx.def_kind(trait_ref.def_id).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind); } inline::record_extern_fqn(cx, trait_ref.def_id, kind); - let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs); + let path = external_path(cx, trait_ref.def_id, true, bindings, trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -175,7 +174,7 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( fn clean_poly_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - bindings: &[TypeBinding], + bindings: ThinVec, ) -> GenericBound { let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap(); @@ -200,16 +199,10 @@ fn clean_poly_trait_ref_with_bindings<'tcx>( ) } -impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound { - clean_poly_trait_ref_with_bindings(cx, *self, &[]) - } -} - -fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { +fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { let def = cx.tcx.named_region(lifetime.hir_id); if let Some( - rl::Region::EarlyBound(_, node_id) + rl::Region::EarlyBound(node_id) | rl::Region::LateBound(_, _, node_id) | rl::Region::Free(_, node_id), ) = def @@ -257,7 +250,6 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option { debug!("cannot clean region {:?}", region); None @@ -265,66 +257,68 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option Clean<'tcx, Option> for hir::WherePredicate<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - if !self.in_where_clause() { - return None; - } - Some(match *self { - hir::WherePredicate::BoundPredicate(ref wbp) => { - let bound_params = wbp - .bound_generic_params - .iter() - .map(|param| { - // Higher-ranked params must be lifetimes. - // Higher-ranked lifetimes can't have bounds. - assert_matches!( - param, - hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } - ); - Lifetime(param.name.ident().name) - }) - .collect(); - WherePredicate::BoundPredicate { - ty: clean_ty(wbp.bounded_ty, cx), - bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(), - bound_params, - } +fn clean_where_predicate<'tcx>( + predicate: &hir::WherePredicate<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + if !predicate.in_where_clause() { + return None; + } + Some(match *predicate { + hir::WherePredicate::BoundPredicate(ref wbp) => { + let bound_params = wbp + .bound_generic_params + .iter() + .map(|param| { + // Higher-ranked params must be lifetimes. + // Higher-ranked lifetimes can't have bounds. + assert_matches!( + param, + hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } + ); + Lifetime(param.name.ident().name) + }) + .collect(); + WherePredicate::BoundPredicate { + ty: clean_ty(wbp.bounded_ty, cx), + bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + bound_params, } + } - hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { - lifetime: clean_lifetime(wrp.lifetime, cx), - bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(), - }, + hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { + lifetime: clean_lifetime(wrp.lifetime, cx), + bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + }, - hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { - lhs: clean_ty(wrp.lhs_ty, cx), - rhs: clean_ty(wrp.rhs_ty, cx).into(), - }, - }) - } + hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { + lhs: clean_ty(wrp.lhs_ty, cx), + rhs: clean_ty(wrp.rhs_ty, cx).into(), + }, + }) } -impl<'tcx> Clean<'tcx, Option> for ty::Predicate<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - let bound_predicate = self.kind(); - match bound_predicate.skip_binder() { - ty::PredicateKind::Trait(pred) => { - clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) - } - ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred), - ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx), - ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)), - ty::PredicateKind::ConstEvaluatable(..) => None, - ty::PredicateKind::WellFormed(..) => None, - - ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), +pub(crate) fn clean_predicate<'tcx>( + predicate: ty::Predicate<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + let bound_predicate = predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(pred) => { + clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) } + ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred), + ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx), + ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)), + ty::PredicateKind::ConstEvaluatable(..) => None, + ty::PredicateKind::WellFormed(..) => None, + + ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } @@ -342,7 +336,7 @@ fn clean_poly_trait_predicate<'tcx>( let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref); Some(WherePredicate::BoundPredicate { ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None), - bounds: vec![poly_trait_ref.clean(cx)], + bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())], bound_params: Vec::new(), }) } @@ -352,10 +346,6 @@ fn clean_region_outlives_predicate<'tcx>( ) -> Option { let ty::OutlivesPredicate(a, b) = pred; - if a.is_empty() && b.is_empty() { - return None; - } - Some(WherePredicate::RegionPredicate { lifetime: clean_middle_region(a).expect("failed to clean lifetime"), bounds: vec![GenericBound::Outlives( @@ -370,10 +360,6 @@ fn clean_type_outlives_predicate<'tcx>( ) -> Option { let ty::OutlivesPredicate(ty, lt) = pred; - if lt.is_empty() { - return None; - } - Some(WherePredicate::BoundPredicate { ty: clean_middle_ty(ty, cx, None), bounds: vec![GenericBound::Outlives( @@ -384,9 +370,9 @@ fn clean_type_outlives_predicate<'tcx>( } fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { - match term { - ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), - ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)), + match term.unpack() { + ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), + ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)), } } @@ -417,7 +403,7 @@ fn clean_projection<'tcx>( def_id: Option, ) -> Type { let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]); + let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), ThinVec::new()); let self_type = clean_middle_ty(ty.self_ty(), cx, None); let self_def_id = if let Some(def_id) = def_id { cx.tcx.opt_parent(def_id).or(Some(def_id)) @@ -425,12 +411,12 @@ fn clean_projection<'tcx>( self_type.def_id(&cx.cache) }; let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); - Type::QPath { - assoc: Box::new(projection_to_path_segment(ty, cx)), + Type::QPath(Box::new(QPathData { + assoc: projection_to_path_segment(ty, cx), should_show_cast, - self_type: Box::new(self_type), + self_type, trait_, - } + })) } fn compute_should_show_cast(self_def_id: Option, trait_: &Path, self_type: &Type) -> bool { @@ -509,7 +495,7 @@ fn clean_generic_param<'tcx>( .filter(|bp| !bp.in_where_clause) .flat_map(|bp| bp.bounds) .map(|bound| match bound { - hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx), + hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx), _ => panic!(), }) .collect() @@ -524,7 +510,7 @@ fn clean_generic_param<'tcx>( .bounds_for_param(did) .filter(|bp| bp.origin != PredicateOrigin::WhereClause) .flat_map(|bp| bp.bounds) - .filter_map(|x| x.clean(cx)) + .filter_map(|x| clean_generic_bound(x, cx)) .collect() } else { Vec::new() @@ -572,65 +558,68 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }) } -impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics { - let impl_trait_params = self - .params - .iter() - .filter(|param| is_impl_trait(param)) - .map(|param| { - let param = clean_generic_param(cx, Some(self), param); - match param.kind { - GenericParamDefKind::Lifetime { .. } => unreachable!(), - GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.insert(did.into(), bounds.clone()); - } - GenericParamDefKind::Const { .. } => unreachable!(), +pub(crate) fn clean_generics<'tcx>( + gens: &hir::Generics<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Generics { + let impl_trait_params = gens + .params + .iter() + .filter(|param| is_impl_trait(param)) + .map(|param| { + let param = clean_generic_param(cx, Some(gens), param); + match param.kind { + GenericParamDefKind::Lifetime { .. } => unreachable!(), + GenericParamDefKind::Type { did, ref bounds, .. } => { + cx.impl_trait_bounds.insert(did.into(), bounds.clone()); } - param - }) - .collect::>(); + GenericParamDefKind::Const { .. } => unreachable!(), + } + param + }) + .collect::>(); - let mut params = Vec::with_capacity(self.params.len()); - for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let p = clean_generic_param(cx, Some(self), p); - params.push(p); - } - params.extend(impl_trait_params); + let mut params = Vec::with_capacity(gens.params.len()); + for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { + let p = clean_generic_param(cx, Some(gens), p); + params.push(p); + } + params.extend(impl_trait_params); - let mut generics = Generics { - params, - where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(), - }; + let mut generics = Generics { + params, + where_predicates: gens + .predicates + .iter() + .filter_map(|x| clean_where_predicate(x, cx)) + .collect(), + }; - // Some duplicates are generated for ?Sized bounds between type params and where - // predicates. The point in here is to move the bounds definitions from type params - // to where predicates when such cases occur. - for where_pred in &mut generics.where_predicates { - match *where_pred { - WherePredicate::BoundPredicate { - ty: Generic(ref name), ref mut bounds, .. - } => { - if bounds.is_empty() { - for param in &mut generics.params { - match param.kind { - GenericParamDefKind::Lifetime { .. } => {} - GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { - if ¶m.name == name { - mem::swap(bounds, ty_bounds); - break; - } + // Some duplicates are generated for ?Sized bounds between type params and where + // predicates. The point in here is to move the bounds definitions from type params + // to where predicates when such cases occur. + for where_pred in &mut generics.where_predicates { + match *where_pred { + WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => { + if bounds.is_empty() { + for param in &mut generics.params { + match param.kind { + GenericParamDefKind::Lifetime { .. } => {} + GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { + if ¶m.name == name { + mem::swap(bounds, ty_bounds); + break; } - GenericParamDefKind::Const { .. } => {} } + GenericParamDefKind::Const { .. } => {} } } } - _ => continue, } + _ => continue, } - generics } + generics } fn clean_ty_generics<'tcx>( @@ -701,7 +690,7 @@ fn clean_ty_generics<'tcx>( if let Some(param_idx) = param_idx { if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { - let p: WherePredicate = p.clean(cx)?; + let p: WherePredicate = clean_predicate(*p, cx)?; b.extend( p.get_bounds() @@ -758,7 +747,7 @@ fn clean_ty_generics<'tcx>( // Now that `cx.impl_trait_bounds` is populated, we can process // remaining predicates which could contain `impl Trait`. let mut where_predicates = - where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); + where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::>(); // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with @@ -896,9 +885,12 @@ fn clean_function<'tcx>( ) -> Box { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = generics.clean(cx); + let generics = clean_generics(generics, cx); let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id); - let decl = clean_fn_decl_with_args(cx, sig.decl, args); + let mut decl = clean_fn_decl_with_args(cx, sig.decl, args); + if sig.header.is_async() { + decl.output = decl.sugared_async_return_type(); + } (generics, decl) }); Box::new(Function { decl, generics }) @@ -994,305 +986,307 @@ fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'t path } -impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait { - PolyTrait { - trait_: clean_trait_ref(&self.trait_ref, cx), - generic_params: self - .bound_generic_params - .iter() - .filter(|p| !is_elided_lifetime(p)) - .map(|x| clean_generic_param(cx, None, x)) - .collect(), - } +fn clean_poly_trait_ref<'tcx>( + poly_trait_ref: &hir::PolyTraitRef<'tcx>, + cx: &mut DocContext<'tcx>, +) -> PolyTrait { + PolyTrait { + trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx), + generic_params: poly_trait_ref + .bound_generic_params + .iter() + .filter(|p| !is_elided_lifetime(p)) + .map(|x| clean_generic_param(cx, None, x)) + .collect(), } } -impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let local_did = self.def_id.to_def_id(); - cx.with_param_env(local_did, |cx| { - let inner = match self.kind { - hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( - clean_ty(ty, cx), - ConstantKind::Local { def_id: local_did, body: default }, - ), - hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, self.generics, body); - MethodItem(m, None) - } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { - let (generics, decl) = enter_impl_trait(cx, |cx| { - // NOTE: generics must be cleaned before args - let generics = self.generics.clean(cx); - let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names); - let decl = clean_fn_decl_with_args(cx, sig.decl, args); - (generics, decl) - }); - TyMethodItem(Box::new(Function { decl, generics })) - } - hir::TraitItemKind::Type(bounds, Some(default)) => { - let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); - let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); - let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None); - AssocTypeItem( - Box::new(Typedef { - type_: clean_ty(default, cx), - generics, - item_type: Some(item_type), - }), - bounds, - ) - } - hir::TraitItemKind::Type(bounds, None) => { - let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); - let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); - TyAssocTypeItem(Box::new(generics), bounds) - } - }; - let what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); - // Trait items always inherit the trait's visibility -- we don't want to show `pub`. - Item { visibility: Inherited, ..what_rustc_thinks } - }) - } +fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item { + let local_did = trait_item.def_id.to_def_id(); + cx.with_param_env(local_did, |cx| { + let inner = match trait_item.kind { + hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( + clean_ty(ty, cx), + ConstantKind::Local { def_id: local_did, body: default }, + ), + hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { + let m = clean_function(cx, sig, trait_item.generics, body); + MethodItem(m, None) + } + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { + let (generics, decl) = enter_impl_trait(cx, |cx| { + // NOTE: generics must be cleaned before args + let generics = clean_generics(trait_item.generics, cx); + let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names); + let decl = clean_fn_decl_with_args(cx, sig.decl, args); + (generics, decl) + }); + TyMethodItem(Box::new(Function { decl, generics })) + } + hir::TraitItemKind::Type(bounds, Some(default)) => { + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); + let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None); + AssocTypeItem( + Box::new(Typedef { + type_: clean_ty(default, cx), + generics, + item_type: Some(item_type), + }), + bounds, + ) + } + hir::TraitItemKind::Type(bounds, None) => { + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); + TyAssocTypeItem(Box::new(generics), bounds) + } + }; + let what_rustc_thinks = + Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx); + // Trait items always inherit the trait's visibility -- we don't want to show `pub`. + Item { visibility: Inherited, ..what_rustc_thinks } + }) } -impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let local_did = self.def_id.to_def_id(); - cx.with_param_env(local_did, |cx| { - let inner = match self.kind { - hir::ImplItemKind::Const(ty, expr) => { - let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(clean_ty(ty, cx), default) - } - hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, self.generics, body); - let defaultness = cx.tcx.impl_defaultness(self.def_id); - MethodItem(m, Some(defaultness)) - } - hir::ImplItemKind::TyAlias(hir_ty) => { - let type_ = clean_ty(hir_ty, cx); - let generics = self.generics.clean(cx); - let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); - AssocTypeItem( - Box::new(Typedef { type_, generics, item_type: Some(item_type) }), - Vec::new(), - ) - } - }; +pub(crate) fn clean_impl_item<'tcx>( + impl_: &hir::ImplItem<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let local_did = impl_.def_id.to_def_id(); + cx.with_param_env(local_did, |cx| { + let inner = match impl_.kind { + hir::ImplItemKind::Const(ty, expr) => { + let default = ConstantKind::Local { def_id: local_did, body: expr }; + AssocConstItem(clean_ty(ty, cx), default) + } + hir::ImplItemKind::Fn(ref sig, body) => { + let m = clean_function(cx, sig, impl_.generics, body); + let defaultness = cx.tcx.impl_defaultness(impl_.def_id); + MethodItem(m, Some(defaultness)) + } + hir::ImplItemKind::TyAlias(hir_ty) => { + let type_ = clean_ty(hir_ty, cx); + let generics = clean_generics(impl_.generics, cx); + let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); + AssocTypeItem( + Box::new(Typedef { type_, generics, item_type: Some(item_type) }), + Vec::new(), + ) + } + }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); + let mut what_rustc_thinks = + Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx); - let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id)); + let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id)); - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Inherited; - } + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + if impl_ref.is_some() { + what_rustc_thinks.visibility = Inherited; + } - what_rustc_thinks - }) - } + what_rustc_thinks + }) } -impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let tcx = cx.tcx; - let kind = match self.kind { - ty::AssocKind::Const => { - let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)); +pub(crate) fn clean_middle_assoc_item<'tcx>( + assoc_item: &ty::AssocItem, + cx: &mut DocContext<'tcx>, +) -> Item { + let tcx = cx.tcx; + let kind = match assoc_item.kind { + ty::AssocKind::Const => { + let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id)); - let provided = match self.container { - ty::ImplContainer => true, - ty::TraitContainer => tcx.impl_defaultness(self.def_id).has_value(), - }; - if provided { - AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id }) - } else { - TyAssocConstItem(ty) - } + let provided = match assoc_item.container { + ty::ImplContainer => true, + ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(), + }; + if provided { + AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id }) + } else { + TyAssocConstItem(ty) } - ty::AssocKind::Fn => { - let generics = clean_ty_generics( - cx, - tcx.generics_of(self.def_id), - tcx.explicit_predicates_of(self.def_id), - ); - let sig = tcx.fn_sig(self.def_id); - let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig); - - if self.fn_has_self_parameter { - let self_ty = match self.container { - ty::ImplContainer => tcx.type_of(self.container_id(tcx)), - ty::TraitContainer => tcx.types.self_param, - }; - let self_arg_ty = sig.input(0).skip_binder(); - if self_arg_ty == self_ty { - decl.inputs.values[0].type_ = Generic(kw::SelfUpper); - } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { - if ty == self_ty { - match decl.inputs.values[0].type_ { - BorrowedRef { ref mut type_, .. } => { - **type_ = Generic(kw::SelfUpper) - } - _ => unreachable!(), - } + } + ty::AssocKind::Fn => { + let generics = clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + tcx.explicit_predicates_of(assoc_item.def_id), + ); + let sig = tcx.fn_sig(assoc_item.def_id); + let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig); + + if assoc_item.fn_has_self_parameter { + let self_ty = match assoc_item.container { + ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)), + ty::TraitContainer => tcx.types.self_param, + }; + let self_arg_ty = sig.input(0).skip_binder(); + if self_arg_ty == self_ty { + decl.inputs.values[0].type_ = Generic(kw::SelfUpper); + } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { + if ty == self_ty { + match decl.inputs.values[0].type_ { + BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper), + _ => unreachable!(), } } } + } - let provided = match self.container { - ty::ImplContainer => true, - ty::TraitContainer => self.defaultness(tcx).has_value(), + let provided = match assoc_item.container { + ty::ImplContainer => true, + ty::TraitContainer => assoc_item.defaultness(tcx).has_value(), + }; + if provided { + let defaultness = match assoc_item.container { + ty::ImplContainer => Some(assoc_item.defaultness(tcx)), + ty::TraitContainer => None, }; - if provided { - let defaultness = match self.container { - ty::ImplContainer => Some(self.defaultness(tcx)), - ty::TraitContainer => None, - }; - MethodItem(Box::new(Function { generics, decl }), defaultness) - } else { - TyMethodItem(Box::new(Function { generics, decl })) - } + MethodItem(Box::new(Function { generics, decl }), defaultness) + } else { + TyMethodItem(Box::new(Function { generics, decl })) } - ty::AssocKind::Type => { - let my_name = self.name; - - fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { - match (¶m.kind, arg) { - (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty))) - if *ty == param.name => - { - true - } - ( - GenericParamDefKind::Lifetime { .. }, - GenericArg::Lifetime(Lifetime(lt)), - ) if *lt == param.name => true, - (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => { - match &c.kind { - ConstantKind::TyConst { expr } => expr == param.name.as_str(), - _ => false, - } - } - _ => false, + } + ty::AssocKind::Type => { + let my_name = assoc_item.name; + + fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { + match (¶m.kind, arg) { + (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty))) + if *ty == param.name => + { + true + } + (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt))) + if *lt == param.name => + { + true } + (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind { + ConstantKind::TyConst { expr } => expr == param.name.as_str(), + _ => false, + }, + _ => false, } + } - if let ty::TraitContainer = self.container { - let bounds = tcx.explicit_item_bounds(self.def_id); - let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; - let mut generics = - clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates); - // Filter out the bounds that are (likely?) directly attached to the associated type, - // as opposed to being located in the where clause. - let mut bounds = generics - .where_predicates - .drain_filter(|pred| match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref assoc, ref self_type, ref trait_, .. }, - .. - } => { - if assoc.name != my_name { - return false; - } - if trait_.def_id() != self.container_id(tcx) { - return false; - } - match **self_type { - Generic(ref s) if *s == kw::SelfUpper => {} - _ => return false, - } - match &assoc.args { - GenericArgs::AngleBracketed { args, bindings } => { - if !bindings.is_empty() - || generics - .params - .iter() - .zip(args.iter()) - .any(|(param, arg)| !param_eq_arg(param, arg)) - { - return false; - } - } - GenericArgs::Parenthesized { .. } => { - // The only time this happens is if we're inside the rustdoc for Fn(), - // which only has one associated type, which is not a GAT, so whatever. + if let ty::TraitContainer = assoc_item.container { + let bounds = tcx.explicit_item_bounds(assoc_item.def_id); + let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; + let mut generics = + clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates); + // Filter out the bounds that are (likely?) directly attached to the associated type, + // as opposed to being located in the where clause. + let mut bounds = generics + .where_predicates + .drain_filter(|pred| match *pred { + WherePredicate::BoundPredicate { + ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }), + .. + } => { + if assoc.name != my_name { + return false; + } + if trait_.def_id() != assoc_item.container_id(tcx) { + return false; + } + match *self_type { + Generic(ref s) if *s == kw::SelfUpper => {} + _ => return false, + } + match &assoc.args { + GenericArgs::AngleBracketed { args, bindings } => { + if !bindings.is_empty() + || generics + .params + .iter() + .zip(args.iter()) + .any(|(param, arg)| !param_eq_arg(param, arg)) + { + return false; } } - true - } - _ => false, - }) - .flat_map(|pred| { - if let WherePredicate::BoundPredicate { bounds, .. } = pred { - bounds - } else { - unreachable!() + GenericArgs::Parenthesized { .. } => { + // The only time this happens is if we're inside the rustdoc for Fn(), + // which only has one associated type, which is not a GAT, so whatever. + } } - }) - .collect::>(); - // Our Sized/?Sized bound didn't get handled when creating the generics - // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { - bounds.remove(i); + true } - None => bounds.push(GenericBound::maybe_sized(cx)), + _ => false, + }) + .flat_map(|pred| { + if let WherePredicate::BoundPredicate { bounds, .. } = pred { + bounds + } else { + unreachable!() + } + }) + .collect::>(); + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { + bounds.remove(i); } + None => bounds.push(GenericBound::maybe_sized(cx)), + } - if tcx.impl_defaultness(self.def_id).has_value() { - AssocTypeItem( - Box::new(Typedef { - type_: clean_middle_ty( - tcx.type_of(self.def_id), - cx, - Some(self.def_id), - ), - generics, - // FIXME: should we obtain the Type from HIR and pass it on here? - item_type: None, - }), - bounds, - ) - } else { - TyAssocTypeItem(Box::new(generics), bounds) - } - } else { - // FIXME: when could this happen? Associated items in inherent impls? + if tcx.impl_defaultness(assoc_item.def_id).has_value() { AssocTypeItem( Box::new(Typedef { - type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)), - generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, + type_: clean_middle_ty( + tcx.type_of(assoc_item.def_id), + cx, + Some(assoc_item.def_id), + ), + generics, + // FIXME: should we obtain the Type from HIR and pass it on here? item_type: None, }), - Vec::new(), + bounds, ) + } else { + TyAssocTypeItem(Box::new(generics), bounds) } + } else { + // FIXME: when could this happen? Associated items in inherent impls? + AssocTypeItem( + Box::new(Typedef { + type_: clean_middle_ty( + tcx.type_of(assoc_item.def_id), + cx, + Some(assoc_item.def_id), + ), + generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, + item_type: None, + }), + Vec::new(), + ) } - }; + } + }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx); + let mut what_rustc_thinks = + Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx); - let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id)); + let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)); - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Visibility::Inherited; - } - - what_rustc_thinks + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + if impl_ref.is_some() { + what_rustc_thinks.visibility = Visibility::Inherited; } + + what_rustc_thinks } fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { @@ -1328,18 +1322,18 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx); let trait_ = self::Path { res: Res::Def(DefKind::Trait, trait_def), - segments: trait_segments.iter().map(|x| x.clean(cx)).collect(), + segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(), }; register_res(cx, trait_.res); let self_def_id = DefId::local(qself.hir_id.owner.local_def_index); let self_type = clean_ty(qself, cx); let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type); - Type::QPath { - assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)), + Type::QPath(Box::new(QPathData { + assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx), should_show_cast, - self_type: Box::new(self_type), + self_type, trait_, - } + })) } hir::QPath::TypeRelative(qself, segment) => { let ty = hir_ty_to_ty(cx.tcx, hir_ty); @@ -1354,12 +1348,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let self_def_id = res.opt_def_id(); let self_type = clean_ty(qself, cx); let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); - Type::QPath { - assoc: Box::new(segment.clean(cx)), + Type::QPath(Box::new(QPathData { + assoc: clean_path_segment(segment, cx), should_show_cast, - self_type: Box::new(self_type), + self_type, trait_, - } + })) } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), } @@ -1398,7 +1392,7 @@ fn maybe_expand_private_type_alias<'tcx>( } _ => None, }); - if let Some(lt) = lifetime.cloned() { + if let Some(lt) = lifetime { let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id); let cleaned = if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() }; @@ -1498,22 +1492,22 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(item_id, _) => { + TyKind::OpaqueDef(item_id, _, _) => { let item = cx.tcx.hir().item(item_id); if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { - ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect()) + ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) } else { unreachable!() } } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect(); + let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect(); let lifetime = if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None }; DynTrait(bounds, lifetime) } - TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), + TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err => Infer, TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind), @@ -1598,21 +1592,22 @@ pub(crate) fn clean_middle_ty<'tcx>( AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, vec![], substs); + let path = external_path(cx, did, false, ThinVec::new(), substs); Type::Path { path } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); + let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty()); Type::Path { path } } - ty::Dynamic(obj, ref reg) => { + ty::Dynamic(obj, ref reg, _) => { // HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only // trait objects. - let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits()); - let did = dids - .next() + let mut dids = obj.auto_traits(); + let did = obj + .principal_def_id() + .or_else(|| dids.next()) .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this)); let substs = match obj.principal() { Some(principal) => principal.skip_binder().substs, @@ -1623,19 +1618,18 @@ pub(crate) fn clean_middle_ty<'tcx>( inline::record_extern_fqn(cx, did, ItemType::Trait); let lifetime = clean_middle_region(*reg); - let mut bounds = vec![]; - - for did in dids { - let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, false, vec![], empty); - inline::record_extern_fqn(cx, did, ItemType::Trait); - let bound = PolyTrait { trait_: path, generic_params: Vec::new() }; - bounds.push(bound); - } + let mut bounds = dids + .map(|did| { + let empty = cx.tcx.intern_substs(&[]); + let path = external_path(cx, did, false, ThinVec::new(), empty); + inline::record_extern_fqn(cx, did, ItemType::Trait); + PolyTrait { trait_: path, generic_params: Vec::new() } + }) + .collect::>(); - let mut bindings = vec![]; - for pb in obj.projection_bounds() { - bindings.push(TypeBinding { + let bindings = obj + .projection_bounds() + .map(|pb| TypeBinding { assoc: projection_to_path_segment( pb.skip_binder() .lift_to_tcx(cx.tcx) @@ -1649,8 +1643,8 @@ pub(crate) fn clean_middle_ty<'tcx>( kind: TypeBindingKind::Equality { term: clean_middle_term(pb.skip_binder().term, cx), }, - }); - } + }) + .collect(); let path = external_path(cx, did, false, bindings, substs); bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() }); @@ -1703,7 +1697,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } } - let bindings: Vec<_> = bounds + let bindings: ThinVec<_> = bounds .iter() .filter_map(|bound| { if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() @@ -1724,7 +1718,7 @@ pub(crate) fn clean_middle_ty<'tcx>( }) .collect(); - Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings)) + Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings)) }) .collect::>(); bounds.extend(regions); @@ -1783,21 +1777,19 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { +pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { match vis { ty::Visibility::Public => Visibility::Public, - // NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private', - // while rustdoc really does mean inherited. That means that for enum variants, such as - // `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc. - // Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured. - ty::Visibility::Invisible => Visibility::Inherited, ty::Visibility::Restricted(module) => Visibility::Restricted(module), } } pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item { let kind = match variant.ctor_kind { - CtorKind::Const => Variant::CLike, + CtorKind::Const => Variant::CLike(match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), + ty::VariantDiscr::Relative(_) => None, + }), CtorKind::Fn => Variant::Tuple( variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(), ), @@ -1814,6 +1806,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, + disr_expr: &Option, cx: &mut DocContext<'tcx>, ) -> Variant { match variant { @@ -1824,66 +1817,75 @@ fn clean_variant_data<'tcx>( hir::VariantData::Tuple(..) => { Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect()) } - hir::VariantData::Unit(..) => Variant::CLike, + hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant { + expr: Some(disr.body), + value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(), + })), } } fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { - Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() } + Path { + res: path.res, + segments: path.segments.iter().map(|x| clean_path_segment(x, cx)).collect(), + } } -impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs { - if self.parenthesized { - let output = clean_ty(self.bindings[0].ty(), cx); - let output = - if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; - let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::>().into(); - GenericArgs::Parenthesized { inputs, output } - } else { - let args = self - .args - .iter() - .map(|arg| match arg { - hir::GenericArg::Lifetime(lt) if !lt.is_elided() => { - GenericArg::Lifetime(clean_lifetime(*lt, cx)) - } - hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), - hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), - hir::GenericArg::Infer(_inf) => GenericArg::Infer, - }) - .collect::>() - .into(); - let bindings = - self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::>().into(); - GenericArgs::AngleBracketed { args, bindings } - } +fn clean_generic_args<'tcx>( + generic_args: &hir::GenericArgs<'tcx>, + cx: &mut DocContext<'tcx>, +) -> GenericArgs { + if generic_args.parenthesized { + let output = clean_ty(generic_args.bindings[0].ty(), cx); + let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; + let inputs = + generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::>().into(); + GenericArgs::Parenthesized { inputs, output } + } else { + let args = generic_args + .args + .iter() + .map(|arg| match arg { + hir::GenericArg::Lifetime(lt) if !lt.is_elided() => { + GenericArg::Lifetime(clean_lifetime(*lt, cx)) + } + hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), + hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), + hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), + hir::GenericArg::Infer(_inf) => GenericArg::Infer, + }) + .collect::>() + .into(); + let bindings = + generic_args.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::>(); + GenericArgs::AngleBracketed { args, bindings } } } -impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment { - PathSegment { name: self.ident.name, args: self.args().clean(cx) } - } +fn clean_path_segment<'tcx>( + path: &hir::PathSegment<'tcx>, + cx: &mut DocContext<'tcx>, +) -> PathSegment { + PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) } } -impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl { - let (generic_params, decl) = enter_impl_trait(cx, |cx| { - // NOTE: generics must be cleaned before args - let generic_params = self - .generic_params - .iter() - .filter(|p| !is_elided_lifetime(p)) - .map(|x| clean_generic_param(cx, None, x)) - .collect(); - let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names); - let decl = clean_fn_decl_with_args(cx, self.decl, args); - (generic_params, decl) - }); - BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params } - } +fn clean_bare_fn_ty<'tcx>( + bare_fn: &hir::BareFnTy<'tcx>, + cx: &mut DocContext<'tcx>, +) -> BareFunctionDecl { + let (generic_params, decl) = enter_impl_trait(cx, |cx| { + // NOTE: generics must be cleaned before args + let generic_params = bare_fn + .generic_params + .iter() + .filter(|p| !is_elided_lifetime(p)) + .map(|x| clean_generic_param(cx, None, x)) + .collect(); + let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names); + let decl = clean_fn_decl_with_args(cx, bare_fn.decl, args); + (generic_params, decl) + }); + BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params } } fn clean_maybe_renamed_item<'tcx>( @@ -1905,33 +1907,33 @@ fn clean_maybe_renamed_item<'tcx>( kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { - bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(), - generics: ty.generics.clean(cx), + bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + generics: clean_generics(ty.generics, cx), }), ItemKind::TyAlias(hir_ty, generics) => { let rustdoc_ty = clean_ty(hir_ty, cx); let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); TypedefItem(Box::new(Typedef { type_: rustdoc_ty, - generics: generics.clean(cx), + generics: clean_generics(generics, cx), item_type: Some(ty), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { - variants: def.variants.iter().map(|v| v.clean(cx)).collect(), - generics: generics.clean(cx), + variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), + generics: clean_generics(generics, cx), }), ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias { - generics: generics.clean(cx), - bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(), + generics: clean_generics(generics, cx), + bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), ItemKind::Union(ref variant_data, generics) => UnionItem(Union { - generics: generics.clean(cx), + generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Struct(ref variant_data, generics) => StructItem(Struct { struct_type: CtorKind::from_hir(variant_data), - generics: generics.clean(cx), + generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx), @@ -1946,15 +1948,17 @@ fn clean_maybe_renamed_item<'tcx>( }) } ItemKind::Trait(_, _, generics, bounds, item_ids) => { - let items = - item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect(); + let items = item_ids + .iter() + .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx)) + .collect(); - TraitItem(Trait { + TraitItem(Box::new(Trait { def_id, items, - generics: generics.clean(cx), - bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(), - }) + generics: clean_generics(generics, cx), + bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + })) } ItemKind::ExternCrate(orig_name) => { return clean_extern_crate(item, name, orig_name, cx); @@ -1969,14 +1973,12 @@ fn clean_maybe_renamed_item<'tcx>( }) } -impl<'tcx> Clean<'tcx, Item> for hir::Variant<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let kind = VariantItem(clean_variant_data(&self.data, cx)); - let what_rustc_thinks = - Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx); - // don't show `pub` for variants, which are always public - Item { visibility: Inherited, ..what_rustc_thinks } - } +fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item { + let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx)); + let what_rustc_thinks = + Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx); + // don't show `pub` for variants, which are always public + Item { visibility: Inherited, ..what_rustc_thinks } } fn clean_impl<'tcx>( @@ -1987,8 +1989,11 @@ fn clean_impl<'tcx>( let tcx = cx.tcx; let mut ret = Vec::new(); let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx)); - let items = - impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::>(); + let items = impl_ + .items + .iter() + .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx)) + .collect::>(); let def_id = tcx.hir().local_def_id(hir_id); // If this impl block is an implementation of the Deref trait, then we @@ -2005,7 +2010,7 @@ fn clean_impl<'tcx>( let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Box::new(Impl { unsafety: impl_.unsafety, - generics: impl_.generics.clean(cx), + generics: clean_generics(impl_.generics, cx), trait_, for_, items, @@ -2106,8 +2111,8 @@ fn clean_use_statement<'tcx>( // `pub(super)` or higher. If the current module is the top level // module, there isn't really a parent module, which makes the results // meaningless. In this case, we make sure the answer is `false`. - let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx) - && !current_mod.is_top_level_module(); + let is_visible_from_parent_mod = + visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module(); if pub_underscore { if let Some(ref inline) = inline_attr { @@ -2202,7 +2207,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( hir::ForeignItemKind::Fn(decl, names, generics) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = generics.clean(cx); + let generics = clean_generics(generics, cx); let args = clean_args_from_types_and_names(cx, decl.inputs, names); let decl = clean_fn_decl_with_args(cx, decl, args); (generics, decl) @@ -2229,13 +2234,16 @@ fn clean_type_binding<'tcx>( cx: &mut DocContext<'tcx>, ) -> TypeBinding { TypeBinding { - assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) }, + assoc: PathSegment { + name: type_binding.ident.name, + args: clean_generic_args(type_binding.gen_args, cx), + }, kind: match type_binding.kind { hir::TypeBindingKind::Equality { ref term } => { TypeBindingKind::Equality { term: clean_hir_term(term, cx) } } hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint { - bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(), + bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(), }, }, } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0e6de842c..f973fd088 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -8,6 +8,7 @@ use std::sync::OnceLock as OnceCell; use std::{cmp, fmt, iter}; use arrayvec::ArrayVec; +use thin_vec::ThinVec; use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; @@ -15,7 +16,6 @@ use rustc_ast::{self as ast, AttrStyle}; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -415,29 +415,28 @@ impl Item { .unwrap_or(false) } - pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Span { + pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option { let kind = match &*self.kind { ItemKind::StrippedItem(k) => k, _ => &*self.kind, }; match kind { - ItemKind::ModuleItem(Module { span, .. }) => *span, - ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => Span::dummy(), + ItemKind::ModuleItem(Module { span, .. }) => Some(*span), + ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None, ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => { if let ItemId::Blanket { impl_id, .. } = self.item_id { - rustc_span(impl_id, tcx) + Some(rustc_span(impl_id, tcx)) } else { panic!("blanket impl item has non-blanket ID") } } - _ => { - self.item_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy) - } + _ => self.item_id.as_def_id().map(|did| rustc_span(did, tcx)), } } pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span { - crate::passes::span_of_attrs(&self.attrs).unwrap_or_else(|| self.span(tcx).inner()) + crate::passes::span_of_attrs(&self.attrs) + .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner())) } /// Finds the `doc` attribute as a NameValue and returns the corresponding @@ -483,7 +482,7 @@ impl Item { cx: &mut DocContext<'_>, cfg: Option>, ) -> Item { - trace!("name={:?}, def_id={:?}", name, def_id); + trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg); // Primitives and Keywords are written in the source code as private modules. // The modules need to be private so that nobody actually uses them, but the @@ -511,7 +510,7 @@ impl Item { .get(&self.item_id) .map_or(&[][..], |v| v.as_slice()) .iter() - .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| { + .filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| { debug!(?did); if let Ok((mut href, ..)) = href(*did, cx) { debug!(?href); @@ -728,7 +727,7 @@ pub(crate) enum ItemKind { OpaqueTyItem(OpaqueTy), StaticItem(Static), ConstantItem(Constant), - TraitItem(Trait), + TraitItem(Box), TraitAliasItem(TraitAlias), ImplItem(Box), /// A required method in a trait declaration meaning it's only a function signature. @@ -802,6 +801,31 @@ impl ItemKind { | KeywordItem => [].iter(), } } + + /// Returns `true` if this item does not appear inside an impl block. + pub(crate) fn is_non_assoc(&self) -> bool { + matches!( + self, + StructItem(_) + | UnionItem(_) + | EnumItem(_) + | TraitItem(_) + | ModuleItem(_) + | ExternCrateItem { .. } + | FunctionItem(_) + | TypedefItem(_) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + ) + } } #[derive(Clone, Debug)] @@ -821,8 +845,6 @@ pub(crate) trait AttributesExt { fn inner_docs(&self) -> bool; - fn other_attrs(&self) -> Vec; - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option>; } @@ -849,10 +871,6 @@ impl AttributesExt for [ast::Attribute] { self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner) } - fn other_attrs(&self) -> Vec { - self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() - } - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { let sess = tcx.sess; let doc_cfg_active = tcx.features().doc_cfg; @@ -1116,7 +1134,10 @@ pub(crate) struct ItemLink { /// This may not be the same as `link` if there was a disambiguator /// in an intra-doc link (e.g. \[`fn@f`\]) pub(crate) link_text: String, - pub(crate) did: DefId, + /// The `DefId` of the Item whose **HTML Page** contains the item being + /// linked to. This will be different to `item_id` on item's that don't + /// have their own page, such as struct fields and enum variants. + pub(crate) page_id: DefId, /// The url fragment to append to the link pub(crate) fragment: Option, } @@ -1137,7 +1158,7 @@ pub struct RenderedLink { #[derive(Clone, Debug, Default)] pub(crate) struct Attributes { pub(crate) doc_strings: Vec, - pub(crate) other_attrs: Vec, + pub(crate) other_attrs: ast::AttrVec, } impl Attributes { @@ -1180,7 +1201,7 @@ impl Attributes { doc_only: bool, ) -> Attributes { let mut doc_strings = Vec::new(); - let mut other_attrs = Vec::new(); + let mut other_attrs = ast::AttrVec::new(); for (attr, parent_module) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { trace!("got doc_str={doc_str:?}"); @@ -1285,7 +1306,7 @@ impl GenericBound { pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, false, vec![], empty); + let path = external_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( PolyTrait { trait_: path, generic_params: Vec::new() }, @@ -1557,13 +1578,7 @@ pub(crate) enum Type { BorrowedRef { lifetime: Option, mutability: Mutability, type_: Box }, /// A qualified path to an associated item: `::Name` - QPath { - assoc: Box, - self_type: Box, - /// FIXME: compute this field on demand. - should_show_cast: bool, - trait_: Path, - }, + QPath(Box), /// A type that is inferred: `_` Infer, @@ -1661,8 +1676,8 @@ impl Type { } pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { - if let QPath { self_type, trait_, assoc, .. } = self { - Some((self_type, trait_.def_id(), *assoc.clone())) + if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { + Some((self_type, trait_.def_id(), assoc.clone())) } else { None } @@ -1686,7 +1701,7 @@ impl Type { Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, RawPointer(..) => PrimitiveType::RawPointer, - QPath { ref self_type, .. } => return self_type.inner_def_id(cache), + QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache), Generic(_) | Infer | ImplTrait(_) => return None, }; cache.and_then(|c| Primitive(t).def_id(c)) @@ -1700,6 +1715,15 @@ impl Type { } } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub(crate) struct QPathData { + pub assoc: PathSegment, + pub self_type: Type, + /// FIXME: compute this field on demand. + pub should_show_cast: bool, + pub trait_: Path, +} + /// A primitive (aka, builtin) type. /// /// This represents things like `i32`, `str`, etc. @@ -2077,7 +2101,7 @@ impl Enum { #[derive(Clone, Debug)] pub(crate) enum Variant { - CLike, + CLike(Option), Tuple(Vec), Struct(VariantStruct), } @@ -2086,11 +2110,31 @@ impl Variant { pub(crate) fn has_stripped_entries(&self) -> Option { match *self { Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()), - Self::CLike | Self::Tuple(_) => None, + Self::CLike(..) | Self::Tuple(_) => None, } } } +#[derive(Clone, Debug)] +pub(crate) struct Discriminant { + // In the case of cross crate re-exports, we don't have the nessesary information + // to reconstruct the expression of the discriminant, only the value. + pub(super) expr: Option, + pub(super) value: DefId, +} + +impl Discriminant { + /// Will be `None` in the case of cross-crate reexports, and may be + /// simplified + pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option { + self.expr.map(|body| print_const_expr(tcx, body)) + } + /// Will always be a machine readable number, without underscores or suffixes. + pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String { + print_evaluated_const(tcx, self.value, false).unwrap() + } +} + /// Small wrapper around [`rustc_span::Span`] that adds helper methods /// and enforces calling [`rustc_span::Span::source_callsite()`]. #[derive(Copy, Clone, Debug)] @@ -2109,14 +2153,6 @@ impl Span { self.0 } - pub(crate) fn dummy() -> Self { - Self(rustc_span::DUMMY_SP) - } - - pub(crate) fn is_dummy(&self) -> bool { - self.0.is_dummy() - } - pub(crate) fn filename(&self, sess: &Session) -> FileName { sess.source_map().span_to_filename(self.0) } @@ -2325,7 +2361,7 @@ impl ConstantKind { match *self { ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None, ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => { - print_evaluated_const(tcx, def_id) + print_evaluated_const(tcx, def_id, true) } } } @@ -2495,14 +2531,16 @@ impl SubstParam { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Crate, 72); // frequently moved by-value - rustc_data_structures::static_assert_size!(DocFragment, 32); - rustc_data_structures::static_assert_size!(GenericArg, 80); - rustc_data_structures::static_assert_size!(GenericArgs, 32); - rustc_data_structures::static_assert_size!(GenericParamDef, 56); - rustc_data_structures::static_assert_size!(Item, 56); - rustc_data_structures::static_assert_size!(ItemKind, 112); - rustc_data_structures::static_assert_size!(PathSegment, 40); - rustc_data_structures::static_assert_size!(Type, 72); + static_assert_size!(Crate, 72); // frequently moved by-value + static_assert_size!(DocFragment, 32); + #[cfg(not(bootstrap))] + static_assert_size!(GenericArg, 56); + static_assert_size!(GenericArgs, 32); + static_assert_size!(GenericParamDef, 56); + static_assert_size!(Item, 56); + static_assert_size!(ItemKind, 96); + static_assert_size!(PathSegment, 40); + static_assert_size!(Type, 56); } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 43e71e90a..3eaedaf10 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,9 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ - clean_middle_const, clean_middle_region, clean_middle_ty, inline, Clean, Crate, ExternalCrate, - Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, - Primitive, PrimitiveType, Type, TypeBinding, Visibility, + clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate, + ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, + PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -12,7 +12,6 @@ use crate::visit_lib::LibEmbargoVisitor; use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -23,6 +22,7 @@ use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; +use thin_vec::ThinVec; #[cfg(test)] mod tests; @@ -37,7 +37,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. - let mut module = module.clean(cx); + let mut module = clean_doc_module(&module, cx); match *module.kind { ItemKind::ModuleItem(ref module) => { @@ -102,7 +102,7 @@ fn external_generic_args<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, - bindings: Vec, + bindings: ThinVec, substs: SubstsRef<'tcx>, ) -> GenericArgs { let args = substs_to_args(cx, substs, has_self); @@ -112,7 +112,7 @@ fn external_generic_args<'tcx>( // The trait's first substitution is the one after self, if there is one. match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() { ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::>().into(), - _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() }, + _ => return GenericArgs::AngleBracketed { args: args.into(), bindings }, }; let output = None; // FIXME(#20299) return type comes from a projection now @@ -130,7 +130,7 @@ pub(super) fn external_path<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, - bindings: Vec, + bindings: ThinVec, substs: SubstsRef<'tcx>, ) -> Path { let def_kind = cx.tcx.def_kind(did); @@ -235,14 +235,13 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { match n.kind() { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => { - let mut s = if let Some(def) = def.as_local() { + assert_eq!(promoted, ()); + let s = if let Some(def) = def.as_local() { print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def.did)) } else { inline::print_inlined_const(cx.tcx, def.did) }; - if let Some(promoted) = promoted { - s.push_str(&format!("::{:?}", promoted)) - } + s } _ => { @@ -261,7 +260,11 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { } } -pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option { +pub(crate) fn print_evaluated_const( + tcx: TyCtxt<'_>, + def_id: DefId, + underscores_and_type: bool, +) -> Option { tcx.const_eval_poly(def_id).ok().and_then(|val| { let ty = tcx.type_of(def_id); match (val, ty.kind()) { @@ -269,7 +272,7 @@ pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option None, (ConstValue::Scalar(_), _) => { let const_ = mir::ConstantKind::from_value(val, ty); - Some(print_const_with_custom_print_scalar(tcx, const_)) + Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type)) } _ => None, } @@ -302,23 +305,35 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String { +fn print_const_with_custom_print_scalar( + tcx: TyCtxt<'_>, + ct: mir::ConstantKind<'_>, + underscores_and_type: bool, +) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct, ct.ty().kind()) { (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => { - format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) + if underscores_and_type { + format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) + } else { + int.to_string() + } } (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = tcx.lift(ct.ty()).unwrap(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); let sign_extended_data = size.sign_extend(data) as i128; - format!( - "{}{}", - format_integer_with_underscore_sep(&sign_extended_data.to_string()), - i.name_str() - ) + if underscores_and_type { + format!( + "{}{}", + format_integer_with_underscore_sep(&sign_extended_data.to_string()), + i.name_str() + ) + } else { + sign_extended_data.to_string() + } } _ => ct.to_string(), } @@ -475,30 +490,14 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { use DefKind::*; debug!("register_res({:?})", res); - let (did, kind) = match res { - // These should be added to the cache using `record_extern_fqn`. + let (kind, did) = match res { Res::Def( kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static(_) | Macro(..) | TraitAlias), - i, - ) => (i, kind.into()), - // This is part of a trait definition or trait impl; document the trait. - Res::SelfTy { trait_: Some(trait_def_id), alias_to: _ } => (trait_def_id, ItemType::Trait), - // This is an inherent impl or a type definition; it doesn't have its own page. - Res::SelfTy { trait_: None, alias_to: Some((item_def_id, _)) } => return item_def_id, - Res::SelfTy { trait_: None, alias_to: None } - | Res::PrimTy(_) - | Res::ToolMod - | Res::SelfCtor(_) - | Res::Local(_) - | Res::NonMacroAttr(_) - | Res::Err => return res.def_id(), - Res::Def( - TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst - | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure - | Generator, - id, - ) => return id, + did, + ) => (kind.into(), did), + + _ => panic!("register_res: unexpected {:?}", res), }; if did.is_local() { return did; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 8a8cc272e..932533db0 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -412,7 +412,13 @@ impl Options { let to_check = matches.opt_strs("check-theme"); if !to_check.is_empty() { - let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); + let paths = match theme::load_css_paths(static_files::themes::LIGHT) { + Ok(p) => p, + Err(e) => { + diag.struct_err(&e.to_string()).emit(); + return Err(1); + } + }; let mut errors = 0; println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)"); @@ -547,7 +553,13 @@ impl Options { let mut themes = Vec::new(); if matches.opt_present("theme") { - let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); + let paths = match theme::load_css_paths(static_files::themes::LIGHT) { + Ok(p) => p, + Err(e) => { + diag.struct_err(&e.to_string()).emit(); + return Err(1); + } + }; for (theme_file, theme_s) in matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 35964e3ba..20ae102bc 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1289,14 +1289,9 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> }); } - fn visit_variant( - &mut self, - v: &'hir hir::Variant<'_>, - g: &'hir hir::Generics<'_>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) { self.visit_testable(v.ident.to_string(), v.id, v.span, |this| { - intravisit::walk_variant(this, v, g, item_id); + intravisit::walk_variant(this, v); }); } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 6b7e67e2c..ed702f5c4 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -46,7 +46,7 @@ pub(crate) trait DocFolder: Sized { let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); VariantItem(Variant::Tuple(fields)) } - Variant::CLike => VariantItem(Variant::CLike), + Variant::CLike(disr) => VariantItem(Variant::CLike(disr)), }, ExternCrateItem { src: _ } | ImportItem(_) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 2b2691e53..86392610d 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { if let clean::TraitItem(ref t) = *item.kind { self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| { clean::TraitWithExtraInfo { - trait_: t.clone(), + trait_: *t.clone(), is_notable: item.attrs.has_doc_flag(sym::notable_trait), } }); diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 0a7ee2005..f21e60a64 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -135,6 +135,7 @@ impl From for ItemType { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 36a47b05c..b499e186c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -152,7 +152,7 @@ impl Buffer { } } -fn comma_sep( +pub(crate) fn comma_sep( items: impl Iterator, space_after_comma: bool, ) -> impl fmt::Display { @@ -349,8 +349,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let where_preds = comma_sep(where_predicates, false); let clause = if f.alternate() { if ending == Ending::Newline { - // add a space so stripping
tags and breaking spaces still renders properly - format!(" where{where_preds}, ") + format!(" where{where_preds},") } else { format!(" where{where_preds}") } @@ -364,20 +363,16 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( if ending == Ending::Newline { let mut clause = " ".repeat(indent.saturating_sub(1)); - // add a space so stripping
tags and breaking spaces still renders properly - write!( - clause, - " where{where_preds}, " - )?; + write!(clause, "where{where_preds},")?; clause } else { // insert a
tag after a single space but before multiple spaces at the start if indent == 0 { - format!("
where{where_preds}") + format!("
where{where_preds}") } else { let mut clause = br_with_padding; - clause.truncate(clause.len() - 5 * " ".len()); - write!(clause, " where{where_preds}")?; + clause.truncate(clause.len() - 4 * " ".len()); + write!(clause, "where{where_preds}")?; clause } } @@ -592,7 +587,7 @@ fn generate_macro_def_id_path( } }) .collect(); - let relative = fqp.iter().map(|elem| elem.to_string()); + let mut relative = fqp.iter().map(|elem| elem.to_string()); let cstore = CStore::from_tcx(tcx); // We need this to prevent a `panic` when this function is used from intra doc links... if !cstore.has_crate_data(def_id.krate) { @@ -612,7 +607,7 @@ fn generate_macro_def_id_path( let mut path = if is_macro_2 { once(crate_name.clone()).chain(relative).collect() } else { - vec![crate_name.clone(), relative.last().unwrap()] + vec![crate_name.clone(), relative.next_back().unwrap()] }; if path.len() < 2 { // The minimum we can have is the crate name followed by the macro name. If shorter, then @@ -1079,7 +1074,12 @@ fn fmt_type<'cx>( write!(f, "impl {}", print_generic_bounds(bounds, cx)) } } - clean::QPath { ref assoc, ref self_type, ref trait_, should_show_cast } => { + clean::QPath(box clean::QPathData { + ref assoc, + ref self_type, + ref trait_, + should_show_cast, + }) => { if f.alternate() { if should_show_cast { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? @@ -1305,22 +1305,19 @@ impl clean::FnDecl { ///
Used to determine line-wrapping. /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is /// necessary. - /// * `asyncness`: Whether the function is async or not. pub(crate) fn full_print<'a, 'tcx: 'a>( &'a self, header_len: usize, indent: usize, - asyncness: hir::IsAsync, cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| self.inner_full_print(header_len, indent, asyncness, f, cx)) + display_fn(move |f| self.inner_full_print(header_len, indent, f, cx)) } fn inner_full_print( &self, header_len: usize, indent: usize, - asyncness: hir::IsAsync, f: &mut fmt::Formatter<'_>, cx: &Context<'_>, ) -> fmt::Result { @@ -1385,15 +1382,9 @@ impl clean::FnDecl { args_plain.push_str(", ..."); } - let arrow_plain; - let arrow = if let hir::IsAsync::Async = asyncness { - let output = self.sugared_async_return_type(); - arrow_plain = format!("{:#}", output.print(cx)); - if f.alternate() { arrow_plain.clone() } else { format!("{}", output.print(cx)) } - } else { - arrow_plain = format!("{:#}", self.output.print(cx)); - if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) } - }; + let arrow_plain = format!("{:#}", self.output.print(cx)); + let arrow = + if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }; let declaration_len = header_len + args_plain.len() + arrow_plain.len(); let output = if declaration_len > 80 { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 05547ea15..8922bf377 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -29,31 +29,74 @@ pub(crate) struct HrefContext<'a, 'b, 'c> { /// This field is used to know "how far" from the top of the directory we are to link to either /// documentation pages or other source pages. pub(crate) root_path: &'c str, + /// This field is used to calculate precise local URLs. + pub(crate) current_href: &'c str, } /// Decorations are represented as a map from CSS class to vector of character ranges. /// Each range will be wrapped in a span with that class. +#[derive(Default)] pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>); -/// Highlights `src`, returning the HTML output. -pub(crate) fn render_with_highlighting( +#[derive(Eq, PartialEq, Clone, Copy)] +pub(crate) enum Tooltip { + Ignore, + CompileFail, + ShouldPanic, + Edition(Edition), + None, +} + +/// Highlights `src` as an inline example, returning the HTML output. +pub(crate) fn render_example_with_highlighting( src: &str, out: &mut Buffer, - class: Option<&str>, + tooltip: Tooltip, playground_button: Option<&str>, - tooltip: Option<(Option, &str)>, - edition: Edition, - extra_content: Option, - href_context: Option>, - decoration_info: Option, ) { - debug!("highlighting: ================\n{}\n==============", src); - if let Some((edition_info, class)) = tooltip { + write_header(out, "rust-example-rendered", None, tooltip); + write_code(out, src, None, None); + write_footer(out, playground_button); +} + +/// Highlights `src` as a macro, returning the HTML output. +pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) { + write_header(out, "macro", None, Tooltip::None); + write_code(out, src, None, None); + write_footer(out, None); +} + +/// Highlights `src` as a source code page, returning the HTML output. +pub(crate) fn render_source_with_highlighting( + src: &str, + out: &mut Buffer, + line_numbers: Buffer, + href_context: HrefContext<'_, '_, '_>, + decoration_info: DecorationInfo, +) { + write_header(out, "", Some(line_numbers), Tooltip::None); + write_code(out, src, Some(href_context), Some(decoration_info)); + write_footer(out, None); +} + +fn write_header(out: &mut Buffer, class: &str, extra_content: Option, tooltip: Tooltip) { + write!( + out, + "
", + match tooltip { + Tooltip::Ignore => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + Tooltip::None => "", + }, + ); + + if tooltip != Tooltip::None { write!( out, - "
ⓘ
", - class, - if let Some(edition_info) = edition_info { + "
ⓘ
", + if let Tooltip::Edition(edition_info) = tooltip { format!(" data-edition=\"{}\"", edition_info) } else { String::new() @@ -61,24 +104,115 @@ pub(crate) fn render_with_highlighting( ); } - write_header(out, class, extra_content); - write_code(out, src, edition, href_context, decoration_info); - write_footer(out, playground_button); -} - -fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option) { - write!(out, "
"); if let Some(extra) = extra_content { out.push_buffer(extra); } - if let Some(class) = class { - write!(out, "
", class);
-    } else {
+    if class.is_empty() {
         write!(out, "
");
+    } else {
+        write!(out, "
");
     }
     write!(out, "");
 }
 
+/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
+/// basically (since it's `Option`). The following rules apply:
+///
+/// * If two `Class` have the same variant, then they can be merged.
+/// * If the other `Class` is unclassified and only contains white characters (backline,
+///   whitespace, etc), it can be merged.
+/// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated
+///    CSS class).
+fn can_merge(class1: Option, class2: Option, text: &str) -> bool {
+    match (class1, class2) {
+        (Some(c1), Some(c2)) => c1.is_equal_to(c2),
+        (Some(Class::Ident(_)), None) | (None, Some(Class::Ident(_))) => true,
+        (Some(_), None) | (None, Some(_)) => text.trim().is_empty(),
+        (None, None) => true,
+    }
+}
+
+/// This type is used as a conveniency to prevent having to pass all its fields as arguments into
+/// the various functions (which became its methods).
+struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
+    out: &'a mut Buffer,
+    /// It contains the closing tag and the associated `Class`.
+    closing_tags: Vec<(&'static str, Class)>,
+    /// This is used because we don't automatically generate the closing tag on `ExitSpan` in
+    /// case an `EnterSpan` event with the same class follows.
+    pending_exit_span: Option,
+    /// `current_class` and `pending_elems` are used to group HTML elements with same `class`
+    /// attributes to reduce the DOM size.
+    current_class: Option,
+    /// We need to keep the `Class` for each element because it could contain a `Span` which is
+    /// used to generate links.
+    pending_elems: Vec<(&'b str, Option)>,
+    href_context: Option>,
+}
+
+impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> {
+    fn handle_exit_span(&mut self) {
+        // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
+        // being used in `write_pending_elems`.
+        let class = self.closing_tags.last().expect("ExitSpan without EnterSpan").1;
+        // We flush everything just in case...
+        self.write_pending_elems(Some(class));
+
+        exit_span(self.out, self.closing_tags.pop().expect("ExitSpan without EnterSpan").0);
+        self.pending_exit_span = None;
+    }
+
+    /// Write all the pending elements sharing a same (or at mergeable) `Class`.
+    ///
+    /// If there is a "parent" (if a `EnterSpan` event was encountered) and the parent can be merged
+    /// with the elements' class, then we simply write the elements since the `ExitSpan` event will
+    /// close the tag.
+    ///
+    /// Otherwise, if there is only one pending element, we let the `string` function handle both
+    /// opening and closing the tag, otherwise we do it into this function.
+    ///
+    /// It returns `true` if `current_class` must be set to `None` afterwards.
+    fn write_pending_elems(&mut self, current_class: Option) -> bool {
+        if self.pending_elems.is_empty() {
+            return false;
+        }
+        if let Some((_, parent_class)) = self.closing_tags.last() &&
+            can_merge(current_class, Some(*parent_class), "")
+        {
+            for (text, class) in self.pending_elems.iter() {
+                string(self.out, Escape(text), *class, &self.href_context, false);
+            }
+        } else {
+            // We only want to "open" the tag ourselves if we have more than one pending and if the
+            // current parent tag is not the same as our pending content.
+            let close_tag = if self.pending_elems.len() > 1 && current_class.is_some() {
+                Some(enter_span(self.out, current_class.unwrap(), &self.href_context))
+            } else {
+                None
+            };
+            for (text, class) in self.pending_elems.iter() {
+                string(self.out, Escape(text), *class, &self.href_context, close_tag.is_none());
+            }
+            if let Some(close_tag) = close_tag {
+                exit_span(self.out, close_tag);
+            }
+        }
+        self.pending_elems.clear();
+        true
+    }
+}
+
+impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> {
+    /// When leaving, we need to flush all pending data to not have missing content.
+    fn drop(&mut self) {
+        if self.pending_exit_span.is_some() {
+            self.handle_exit_span();
+        } else {
+            self.write_pending_elems(self.current_class);
+        }
+    }
+}
+
 /// Convert the given `src` source code into HTML by adding classes for highlighting.
 ///
 /// This code is used to render code blocks (in the documentation) as well as the source code pages.
@@ -93,27 +227,74 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option>,
     decoration_info: Option,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    let mut closing_tags: Vec<&'static str> = Vec::new();
+    let mut token_handler = TokenHandler {
+        out,
+        closing_tags: Vec::new(),
+        pending_exit_span: None,
+        current_class: None,
+        pending_elems: Vec::new(),
+        href_context,
+    };
+
     Classifier::new(
         &src,
-        edition,
-        href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+        token_handler.href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
         decoration_info,
     )
     .highlight(&mut |highlight| {
         match highlight {
-            Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
+            Highlight::Token { text, class } => {
+                // If we received a `ExitSpan` event and then have a non-compatible `Class`, we
+                // need to close the ``.
+                let need_current_class_update = if let Some(pending) = token_handler.pending_exit_span &&
+                    !can_merge(Some(pending), class, text) {
+                        token_handler.handle_exit_span();
+                        true
+                // If the two `Class` are different, time to flush the current content and start
+                // a new one.
+                } else if !can_merge(token_handler.current_class, class, text) {
+                    token_handler.write_pending_elems(token_handler.current_class);
+                    true
+                } else {
+                    token_handler.current_class.is_none()
+                };
+
+                if need_current_class_update {
+                    token_handler.current_class = class.map(Class::dummy);
+                }
+                token_handler.pending_elems.push((text, class));
+            }
             Highlight::EnterSpan { class } => {
-                closing_tags.push(enter_span(out, class, &href_context))
+                let mut should_add = true;
+                if let Some(pending_exit_span) = token_handler.pending_exit_span {
+                    if class.is_equal_to(pending_exit_span) {
+                        should_add = false;
+                    } else {
+                        token_handler.handle_exit_span();
+                    }
+                } else {
+                    // We flush everything just in case...
+                    if token_handler.write_pending_elems(token_handler.current_class) {
+                        token_handler.current_class = None;
+                    }
+                }
+                if should_add {
+                    let closing_tag = enter_span(token_handler.out, class, &token_handler.href_context);
+                    token_handler.closing_tags.push((closing_tag, class));
+                }
+
+                token_handler.current_class = None;
+                token_handler.pending_exit_span = None;
             }
             Highlight::ExitSpan => {
-                exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
+                token_handler.current_class = None;
+                token_handler.pending_exit_span =
+                    Some(token_handler.closing_tags.last().as_ref().expect("ExitSpan without EnterSpan").1);
             }
         };
     });
@@ -130,15 +311,15 @@ enum Class {
     DocComment,
     Attribute,
     KeyWord,
-    // Keywords that do pointer/reference stuff.
+    /// Keywords that do pointer/reference stuff.
     RefKeyWord,
     Self_(Span),
-    Op,
     Macro(Span),
     MacroNonTerminal,
     String,
     Number,
     Bool,
+    /// `Ident` isn't rendered in the HTML but we still need it for the `Span` it contains.
     Ident(Span),
     Lifetime,
     PreludeTy,
@@ -148,6 +329,31 @@ enum Class {
 }
 
 impl Class {
+    /// It is only looking at the variant, not the variant content.
+    ///
+    /// It is used mostly to group multiple similar HTML elements into one `` instead of
+    /// multiple ones.
+    fn is_equal_to(self, other: Self) -> bool {
+        match (self, other) {
+            (Self::Self_(_), Self::Self_(_))
+            | (Self::Macro(_), Self::Macro(_))
+            | (Self::Ident(_), Self::Ident(_)) => true,
+            (Self::Decoration(c1), Self::Decoration(c2)) => c1 == c2,
+            (x, y) => x == y,
+        }
+    }
+
+    /// If `self` contains a `Span`, it'll be replaced with `DUMMY_SP` to prevent creating links
+    /// on "empty content" (because of the attributes merge).
+    fn dummy(self) -> Self {
+        match self {
+            Self::Self_(_) => Self::Self_(DUMMY_SP),
+            Self::Macro(_) => Self::Macro(DUMMY_SP),
+            Self::Ident(_) => Self::Ident(DUMMY_SP),
+            s => s,
+        }
+    }
+
     /// Returns the css class expected by rustdoc for each `Class`.
     fn as_html(self) -> &'static str {
         match self {
@@ -157,13 +363,12 @@ impl Class {
             Class::KeyWord => "kw",
             Class::RefKeyWord => "kw-2",
             Class::Self_(_) => "self",
-            Class::Op => "op",
             Class::Macro(_) => "macro",
             Class::MacroNonTerminal => "macro-nonterminal",
             Class::String => "string",
             Class::Number => "number",
             Class::Bool => "bool-val",
-            Class::Ident(_) => "ident",
+            Class::Ident(_) => "",
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
@@ -182,7 +387,6 @@ impl Class {
             | Self::Attribute
             | Self::KeyWord
             | Self::RefKeyWord
-            | Self::Op
             | Self::MacroNonTerminal
             | Self::String
             | Self::Number
@@ -220,7 +424,7 @@ impl<'a> Iterator for TokenIter<'a> {
 }
 
 /// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
-fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option {
+fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option {
     let ignore: &[&str] =
         if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
     if ignore.iter().any(|k| *k == text) {
@@ -229,7 +433,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
     Some(match text {
         "ref" | "mut" => Class::RefKeyWord,
         "false" | "true" => Class::Bool,
-        _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+        _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
         _ => return None,
     })
 }
@@ -250,7 +454,7 @@ impl<'a> PeekIter<'a> {
     fn new(iter: TokenIter<'a>) -> Self {
         Self { stored: VecDeque::new(), peek_pos: 0, iter }
     }
-    /// Returns the next item after the current one. It doesn't interfer with `peek_next` output.
+    /// Returns the next item after the current one. It doesn't interfere with `peek_next` output.
     fn peek(&mut self) -> Option<&(TokenKind, &'a str)> {
         if self.stored.is_empty() {
             if let Some(next) = self.iter.next() {
@@ -259,7 +463,7 @@ impl<'a> PeekIter<'a> {
         }
         self.stored.front()
     }
-    /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output.
+    /// Returns the next item after the last one peeked. It doesn't interfere with `peek` output.
     fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> {
         self.peek_pos += 1;
         if self.peek_pos - 1 < self.stored.len() {
@@ -311,7 +515,6 @@ struct Classifier<'a> {
     in_attribute: bool,
     in_macro: bool,
     in_macro_nonterminal: bool,
-    edition: Edition,
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
@@ -321,12 +524,7 @@ struct Classifier<'a> {
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(
-        src: &str,
-        edition: Edition,
-        file_span: Span,
-        decoration_info: Option,
-    ) -> Classifier<'_> {
+    fn new(src: &str, file_span: Span, decoration_info: Option) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
@@ -334,7 +532,6 @@ impl<'a> Classifier<'a> {
             in_attribute: false,
             in_macro: false,
             in_macro_nonterminal: false,
-            edition,
             byte_pos: 0,
             file_span,
             src,
@@ -354,7 +551,6 @@ impl<'a> Classifier<'a> {
         let start = self.byte_pos as usize;
         let mut pos = start;
         let mut has_ident = false;
-        let edition = self.edition;
 
         loop {
             let mut nb = 0;
@@ -376,7 +572,7 @@ impl<'a> Classifier<'a> {
 
             if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
                 if *token == TokenKind::Ident {
-                    let class = get_real_ident_class(text, edition, true);
+                    let class = get_real_ident_class(text, true);
                     (class, text)
                 } else {
                     // Doesn't matter which Class we put in here...
@@ -494,7 +690,7 @@ impl<'a> Classifier<'a> {
             // or a reference or pointer type. Unless, of course, it looks like
             // a logical and or a multiplication operator: `&&` or `* `.
             TokenKind::Star => match self.tokens.peek() {
-                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
                 Some((TokenKind::Ident, "mut")) => {
                     self.next();
                     sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
@@ -510,15 +706,15 @@ impl<'a> Classifier<'a> {
             TokenKind::And => match self.tokens.peek() {
                 Some((TokenKind::And, _)) => {
                     self.next();
-                    sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
+                    sink(Highlight::Token { text: "&&", class: None });
                     return;
                 }
                 Some((TokenKind::Eq, _)) => {
                     self.next();
-                    sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
+                    sink(Highlight::Token { text: "&=", class: None });
                     return;
                 }
-                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
                 Some((TokenKind::Ident, "mut")) => {
                     self.next();
                     sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
@@ -531,7 +727,7 @@ impl<'a> Classifier<'a> {
             TokenKind::Eq => match lookahead {
                 Some(TokenKind::Eq) => {
                     self.next();
-                    sink(Highlight::Token { text: "==", class: Some(Class::Op) });
+                    sink(Highlight::Token { text: "==", class: None });
                     return;
                 }
                 Some(TokenKind::Gt) => {
@@ -539,7 +735,7 @@ impl<'a> Classifier<'a> {
                     sink(Highlight::Token { text: "=>", class: None });
                     return;
                 }
-                _ => Class::Op,
+                _ => return no_highlight(sink),
             },
             TokenKind::Minus if lookahead == Some(TokenKind::Gt) => {
                 self.next();
@@ -556,7 +752,7 @@ impl<'a> Classifier<'a> {
             | TokenKind::Percent
             | TokenKind::Bang
             | TokenKind::Lt
-            | TokenKind::Gt => Class::Op,
+            | TokenKind::Gt => return no_highlight(sink),
 
             // Miscellaneous, no highlighting.
             TokenKind::Dot
@@ -634,7 +830,7 @@ impl<'a> Classifier<'a> {
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+            TokenKind::Ident => match get_real_ident_class(text, false) {
                 None => match text {
                     "Option" | "Result" => Class::PreludeTy,
                     "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
@@ -682,7 +878,7 @@ fn enter_span(
     klass: Class,
     href_context: &Option>,
 ) -> &'static str {
-    string_without_closing_tag(out, "", Some(klass), href_context).expect(
+    string_without_closing_tag(out, "", Some(klass), href_context, true).expect(
         "internal error: enter_span was called with Some(klass) but did not return a \
             closing HTML tag",
     )
@@ -714,8 +910,10 @@ fn string(
     text: T,
     klass: Option,
     href_context: &Option>,
+    open_tag: bool,
 ) {
-    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
+    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
+    {
         out.write_str(closing_tag);
     }
 }
@@ -734,6 +932,7 @@ fn string_without_closing_tag(
     text: T,
     klass: Option,
     href_context: &Option>,
+    open_tag: bool,
 ) -> Option<&'static str> {
     let Some(klass) = klass
     else {
@@ -742,6 +941,10 @@ fn string_without_closing_tag(
     };
     let Some(def_span) = klass.get_span()
     else {
+        if !open_tag {
+            write!(out, "{}", text);
+            return None;
+        }
         write!(out, "{}", klass.as_html(), text);
         return Some("");
     };
@@ -765,6 +968,7 @@ fn string_without_closing_tag(
             path
         });
     }
+
     if let Some(href_context) = href_context {
         if let Some(href) =
             href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
@@ -775,9 +979,9 @@ fn string_without_closing_tag(
                 // a link to their definition can be generated using this:
                 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
                 match href {
-                    LinkFromSrc::Local(span) => context
-                        .href_from_span(*span, true)
-                        .map(|s| format!("{}{}", href_context.root_path, s)),
+                    LinkFromSrc::Local(span) => {
+                        context.href_from_span_relative(*span, href_context.current_href)
+                    }
                     LinkFromSrc::External(def_id) => {
                         format::href_with_root_path(*def_id, context, Some(href_context.root_path))
                             .ok()
@@ -793,12 +997,33 @@ fn string_without_closing_tag(
                 }
             })
         {
-            write!(out, "{}", klass.as_html(), href, text_s);
+            if !open_tag {
+                // We're already inside an element which has the same klass, no need to give it
+                // again.
+                write!(out, "{}", href, text_s);
+            } else {
+                let klass_s = klass.as_html();
+                if klass_s.is_empty() {
+                    write!(out, "{}", href, text_s);
+                } else {
+                    write!(out, "{}", klass_s, href, text_s);
+                }
+            }
             return Some("");
         }
     }
-    write!(out, "{}", klass.as_html(), text_s);
-    Some("")
+    if !open_tag {
+        write!(out, "{}", text_s);
+        return None;
+    }
+    let klass_s = klass.as_html();
+    if klass_s.is_empty() {
+        write!(out, "{}", text_s);
+        Some("")
+    } else {
+        write!(out, "{}", klass_s, text_s);
+        Some("")
+    }
 }
 
 #[cfg(test)]
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
index 45f567880..ebf29f9cb 100644
--- a/src/librustdoc/html/highlight/fixtures/decorations.html
+++ b/src/librustdoc/html/highlight/fixtures/decorations.html
@@ -1,2 +1,4 @@
-let x = 1;
-let y = 2;
\ No newline at end of file
+let x = 1;
+let y = 2;
+let z = 3;
+let a = 4;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html
index 1c8dbffe7..30b50ca7c 100644
--- a/src/librustdoc/html/highlight/fixtures/dos_line.html
+++ b/src/librustdoc/html/highlight/fixtures/dos_line.html
@@ -1,3 +1,3 @@
-pub fn foo() {
+pub fn foo() {
 println!("foo");
 }
diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html
index abc2db179..9f73e03f9 100644
--- a/src/librustdoc/html/highlight/fixtures/highlight.html
+++ b/src/librustdoc/html/highlight/fixtures/highlight.html
@@ -1,4 +1,4 @@
-use crate::a::foo;
-use self::whatever;
-let x = super::b::foo;
-let y = Self::whatever;
\ No newline at end of file
+use crate::a::foo;
+use self::whatever;
+let x = super::b::foo;
+let y = Self::whatever;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index b117a12e3..4a5a3cf60 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -8,30 +8,31 @@
 .lifetime { color: #B76514; }
 .question-mark { color: #ff9011; }
 
-
#![crate_type = "lib"]
+
#![crate_type = "lib"]
 
-use std::path::{Path, PathBuf};
+use std::path::{Path, PathBuf};
 
-#[cfg(target_os = "linux")]
-fn main() -> () {
-    let foo = true && false || true;
-    let _: *const () = 0;
-    let _ = &foo;
-    let _ = &&foo;
-    let _ = *foo;
-    mac!(foo, &mut bar);
-    assert!(self.length < N && index <= self.length);
-    ::std::env::var("gateau").is_ok();
-    #[rustfmt::skip]
-    let s:std::path::PathBuf = std::path::PathBuf::new();
-    let mut s = String::new();
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "windows")]
+fn main() -> () {
+    let foo = true && false || true;
+    let _: *const () = 0;
+    let _ = &foo;
+    let _ = &&foo;
+    let _ = *foo;
+    mac!(foo, &mut bar);
+    assert!(self.length < N && index <= self.length);
+    ::std::env::var("gateau").is_ok();
+    #[rustfmt::skip]
+    let s:std::path::PathBuf = std::path::PathBuf::new();
+    let mut s = String::new();
 
-    match &s {
-        ref mut x => {}
+    match &s {
+        ref mut x => {}
     }
 }
 
-macro_rules! bar {
-    ($foo:tt) => {};
+macro_rules! bar {
+    ($foo:tt) => {};
 }
 
diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs index fbfdc6767..ef85b566c 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.rs +++ b/src/librustdoc/html/highlight/fixtures/sample.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; #[cfg(target_os = "linux")] +#[cfg(target_os = "windows")] fn main() -> () { let foo = true && false || true; let _: *const () = 0; diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html index c0acf31a0..9f8915282 100644 --- a/src/librustdoc/html/highlight/fixtures/union.html +++ b/src/librustdoc/html/highlight/fixtures/union.html @@ -1,8 +1,8 @@ -union Foo { - i: i8, - u: i8, +union Foo { + i: i8, + u: i8, } -fn main() { - let union = 0; +fn main() { + let union = 0; } diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 1fea7e983..a5e633df4 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -3,7 +3,6 @@ use crate::html::format::Buffer; use expect_test::expect_file; use rustc_data_structures::fx::FxHashMap; use rustc_span::create_default_session_globals_then; -use rustc_span::edition::Edition; const STYLE: &str = r#" - - -"##, - suffix = self.1 - )?; - Ok(()) - } + write!(output_file, "# Rust Compiler Error Index\n")?; - fn title(&self, output: &mut dyn Write) -> Result<(), Box> { - write!(output, "

Rust Compiler Error Index

\n")?; - Ok(()) + for (err_code, description) in error_codes().iter() { + match description { + Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?, + None => {} + } } - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box> { - // Enclose each error in a div so they can be shown/hidden en masse. - let desc_desc = match info.description { - Some(_) => "error-described", - None => "error-undescribed", - }; - write!(output, "
", desc_desc)?; - - // Error title (with self-link). - write!( - output, - "

{0}

\n", - err_code - )?; + Ok(()) +} - // Description rendered as markdown. - match info.description { - Some(ref desc) => { - let mut id_map = self.0.borrow_mut(); - let playground = Playground { - crate_name: None, - url: String::from("https://play.rust-lang.org/"), - }; - write!( - output, - "{}", - Markdown { - content: desc, - links: &[], - ids: &mut id_map, - error_codes: ErrorCodes::Yes, - edition: DEFAULT_EDITION, - playground: &Some(playground), - heading_offset: HeadingOffset::H1, +// By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have +// to manually add `rust` attribute whenever needed. +fn add_rust_attribute_on_codeblock(explanation: &str) -> String { + // Very hacky way to add the rust attribute on all code blocks. + let mut skip = true; + explanation.split("\n```").fold(String::new(), |mut acc, part| { + if !acc.is_empty() { + acc.push_str("\n```"); + } + if !skip { + if let Some(attrs) = part.split('\n').next() { + if !attrs.contains("rust") + && (attrs.is_empty() + || attrs.contains("compile_fail") + || attrs.contains("ignore") + || attrs.contains("edition")) + { + if !attrs.is_empty() { + acc.push_str("rust,"); + } else { + acc.push_str("rust"); } - .into_string() - )? + } } - None => write!(output, "

No description.

\n")?, } - - write!(output, "
\n")?; - Ok(()) - } - - fn footer(&self, output: &mut dyn Write) -> Result<(), Box> { - write!( - output, - r##" - -"## - )?; - Ok(()) - } + skip = !skip; + acc.push_str(part); + acc + }) } -impl Formatter for MarkdownFormatter { - #[allow(unused_variables)] - fn header(&self, output: &mut dyn Write) -> Result<(), Box> { - Ok(()) - } - - fn title(&self, output: &mut dyn Write) -> Result<(), Box> { - write!(output, "# Rust Compiler Error Index\n")?; - Ok(()) - } - - fn error_code_block( - &self, - output: &mut dyn Write, - info: &ErrorMetadata, - err_code: &str, - ) -> Result<(), Box> { - Ok(match info.description { - Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?, - None => (), - }) - } - - #[allow(unused_variables)] - fn footer(&self, output: &mut dyn Write) -> Result<(), Box> { - Ok(()) +fn render_html(output_path: &Path) -> Result<(), Box> { + let mut introduction = format!( + " +# Rust error codes index + +This page lists all the error codes emitted by the Rust compiler. + +" + ); + + let err_codes = error_codes(); + let mut chapters = Vec::with_capacity(err_codes.len()); + + for (err_code, explanation) in err_codes.iter() { + if let Some(explanation) = explanation { + introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code)); + + let content = add_rust_attribute_on_codeblock(explanation); + chapters.push(BookItem::Chapter(Chapter { + name: err_code.to_string(), + content: format!("# Error code {}\n\n{}\n", err_code, content), + number: None, + sub_items: Vec::new(), + // We generate it into the `error_codes` folder. + path: Some(PathBuf::from(&format!("{}.html", err_code))), + source_path: None, + parent_names: Vec::new(), + })); + } else { + introduction.push_str(&format!(" * {}\n", err_code)); + } } -} - -/// Output an HTML page for the errors in `err_map` to `output_path`. -fn render_error_page( - err_map: &ErrorMetadataMap, - output_path: &Path, - formatter: T, -) -> Result<(), Box> { - let mut output_file = File::create(output_path)?; - - formatter.header(&mut output_file)?; - formatter.title(&mut output_file)?; - for (err_code, info) in err_map { - formatter.error_code_block(&mut output_file, info, err_code)?; - } + let mut config = Config::from_str(include_str!("book_config.toml"))?; + config.build.build_dir = output_path.join("error_codes").to_path_buf(); + let mut book = MDBook::load_with_config_and_summary( + env!("CARGO_MANIFEST_DIR"), + config, + parse_summary("")?, + )?; + let chapter = Chapter { + name: "Rust error codes index".to_owned(), + content: introduction, + number: None, + sub_items: chapters, + // Very important: this file is named as `error-index.html` and not `index.html`! + path: Some(PathBuf::from("error-index.html")), + source_path: None, + parent_names: Vec::new(), + }; + book.book.sections.push(BookItem::Chapter(chapter)); + book.build()?; + + // We can't put this content into another file, otherwise `mbdbook` will also put it into the + // output directory, making a duplicate. + fs::write( + output_path.join("error-index.html"), + r#" + + + Rust error codes index - Error codes index + + + + + +
If you are not automatically redirected to the error code index, please here. + + +"#, + )?; + + // No need for a 404 file, it's already handled by the server. + fs::remove_file(output_path.join("error_codes/404.html"))?; - formatter.footer(&mut output_file) + Ok(()) } fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box> { - let long_codes = register_all(); - let mut err_map = BTreeMap::new(); - for (code, desc) in long_codes { - err_map.insert(code.to_string(), ErrorMetadata { description: desc.map(String::from) }); - } match format { OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), - OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?, - OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?, + OutputFormat::HTML => render_html(dst), + OutputFormat::Markdown => render_markdown(dst), } - Ok(()) } fn parse_args() -> (OutputFormat, PathBuf) { let mut args = env::args().skip(1); let format = args.next(); let dst = args.next(); - let resource_suffix = args.next().unwrap_or_else(String::new); - let format = format - .map(|a| OutputFormat::from(&a, &resource_suffix)) - .unwrap_or(OutputFormat::from("html", &resource_suffix)); + let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html")); let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format { - OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"), - OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"), + OutputFormat::HTML => PathBuf::from("doc"), + OutputFormat::Markdown => PathBuf::from("doc/error-index.md"), OutputFormat::Unknown(..) => PathBuf::from(""), }); (format, dst) @@ -270,29 +198,8 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { rustc_driver::init_env_logger("RUST_LOG"); let (format, dst) = parse_args(); - let result = - rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst)); + let result = main_with_result(format, &dst); if let Err(e) = result { - panic!("{}", e.to_string()); - } -} - -fn register_all() -> Vec<(&'static str, Option<&'static str>)> { - let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new(); - macro_rules! register_diagnostics { - ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => ( - $( - {long_codes.extend([ - (stringify!($ecode), Some($message)), - ].iter());} - )* - $( - {long_codes.extend([ - stringify!($code), - ].iter().cloned().map(|s| (s, None)).collect::>());} - )* - ) + panic!("{:?}", e); } - include!(concat!(env!("OUT_DIR"), "/all_error_codes.rs")); - long_codes } diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js new file mode 100644 index 000000000..8c907f579 --- /dev/null +++ b/src/tools/error_index_generator/redirect.js @@ -0,0 +1,16 @@ +(function() { + if (window.location.hash) { + let code = window.location.hash.replace(/^#/, ''); + // We have to make sure this pattern matches to avoid inadvertently creating an + // open redirect. + if (!/^E[0-9]+$/.test(code)) { + return; + } + if (window.location.pathname.indexOf("/error_codes/") !== -1) { + // We're not at the top level, so we don't prepend with "./error_codes/". + window.location = './' + code + '.html'; + } else { + window.location = './error_codes/' + code + '.html'; + } + } +})() diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index a188750c5..f9e542327 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -1,77 +1,31 @@ -use crate::error::CkError; +use crate::config::Config; use serde_json::Value; use std::collections::HashMap; -use std::io; -use std::path::{Path, PathBuf}; +use std::path::Path; use fs_err as fs; #[derive(Debug)] pub struct Cache { - root: PathBuf, - files: HashMap, - values: HashMap, + value: Value, pub variables: HashMap, - last_path: Option, } impl Cache { /// Create a new cache, used to read files only once and otherwise store their contents. - pub fn new(doc_dir: &str) -> Cache { + pub fn new(config: &Config) -> Cache { + let root = Path::new(&config.doc_dir); + let filename = Path::new(&config.template).file_stem().unwrap(); + let file_path = root.join(&Path::with_extension(Path::new(filename), "json")); + let content = fs::read_to_string(&file_path).expect("failed to read JSON file"); + Cache { - root: Path::new(doc_dir).to_owned(), - files: HashMap::new(), - values: HashMap::new(), + value: serde_json::from_str::(&content).expect("failed to convert from JSON"), variables: HashMap::new(), - last_path: None, } } - fn resolve_path(&mut self, path: &String) -> PathBuf { - if path != "-" { - let resolve = self.root.join(path); - self.last_path = Some(resolve.clone()); - resolve - } else { - self.last_path - .as_ref() - // FIXME: Point to a line number - .expect("No last path set. Make sure to specify a full path before using `-`") - .clone() - } - } - - fn read_file(&mut self, path: PathBuf) -> Result { - if let Some(f) = self.files.get(&path) { - return Ok(f.clone()); - } - - let file = fs::read_to_string(&path)?; - - self.files.insert(path, file.clone()); - - Ok(file) - } - - /// Get the text from a file. If called multiple times, the file will only be read once - pub fn get_file(&mut self, path: &String) -> Result { - let path = self.resolve_path(path); - self.read_file(path) - } - - /// Parse the JSON from a file. If called multiple times, the file will only be read once. - pub fn get_value(&mut self, path: &String) -> Result { - let path = self.resolve_path(path); - - if let Some(v) = self.values.get(&path) { - return Ok(v.clone()); - } - - let content = self.read_file(path.clone())?; - let val = serde_json::from_str::(&content)?; - - self.values.insert(path, val.clone()); - - Ok(val) + pub fn value(&self) -> &Value { + &self.value } } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index c44624666..76770fe36 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -17,7 +17,7 @@ fn main() -> Result<(), String> { let config = parse_config(env::args().collect()); let mut failed = Vec::new(); - let mut cache = Cache::new(&config.doc_dir); + let mut cache = Cache::new(&config); let commands = get_commands(&config.template) .map_err(|_| format!("Jsondocck failed for {}", &config.template))?; @@ -50,15 +50,17 @@ pub enum CommandKind { Has, Count, Is, + IsMany, Set, } impl CommandKind { - fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool { + fn validate(&self, args: &[String], lineno: usize) -> bool { let count = match self { - CommandKind::Has => (1..=3).contains(&args.len()), - CommandKind::Count | CommandKind::Is => 3 == args.len(), - CommandKind::Set => 4 == args.len(), + CommandKind::Has => (1..=2).contains(&args.len()), + CommandKind::IsMany => args.len() >= 2, + CommandKind::Count | CommandKind::Is => 2 == args.len(), + CommandKind::Set => 3 == args.len(), }; if !count { @@ -66,15 +68,10 @@ impl CommandKind { return false; } - if args[0] == "-" && command_num == 0 { - print_err(&format!("Tried to use the previous path in the first command"), lineno); - return false; - } - if let CommandKind::Count = self { - if args[2].parse::().is_err() { + if args[1].parse::().is_err() { print_err( - &format!("Third argument to @count must be a valid usize (got `{}`)", args[2]), + &format!("Second argument to @count must be a valid usize (got `{}`)", args[2]), lineno, ); return false; @@ -89,6 +86,7 @@ impl fmt::Display for CommandKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let text = match self { CommandKind::Has => "has", + CommandKind::IsMany => "ismany", CommandKind::Count => "count", CommandKind::Is => "is", CommandKind::Set => "set", @@ -137,6 +135,7 @@ fn get_commands(template: &str) -> Result, ()> { "has" => CommandKind::Has, "count" => CommandKind::Count, "is" => CommandKind::Is, + "ismany" => CommandKind::IsMany, "set" => CommandKind::Set, _ => { print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); @@ -177,7 +176,7 @@ fn get_commands(template: &str) -> Result, ()> { } }; - if !cmd.validate(&args, commands.len(), lineno) { + if !cmd.validate(&args, lineno) { errors = true; continue; } @@ -195,26 +194,24 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let result = match command.kind { CommandKind::Has => { match command.args.len() { - // @has = file existence - 1 => cache.get_file(&command.args[0]).is_ok(), - // @has = check path exists - 2 => { - let val = cache.get_value(&command.args[0])?; - let results = select(&val, &command.args[1]).unwrap(); + // @has = check path exists + 1 => { + let val = cache.value(); + let results = select(val, &command.args[0]).unwrap(); !results.is_empty() } - // @has = check *any* item matched by path equals value - 3 => { - let val = cache.get_value(&command.args[0])?; - let results = select(&val, &command.args[1]).unwrap(); - let pat = string_to_value(&command.args[2], cache); + // @has = check *any* item matched by path equals value + 2 => { + let val = cache.value().clone(); + let results = select(&val, &command.args[0]).unwrap(); + let pat = string_to_value(&command.args[1], cache); let has = results.contains(&pat.as_ref()); // Give better error for when @has check fails if !command.negated && !has { return Err(CkError::FailedCheck( format!( "{} matched to {:?} but didn't have {:?}", - &command.args[1], + &command.args[0], results, pat.as_ref() ), @@ -227,19 +224,56 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { _ => unreachable!(), } } - CommandKind::Count => { - // @count = Check that the jsonpath matches exactly [count] times - assert_eq!(command.args.len(), 3); - let expected: usize = command.args[2].parse().unwrap(); + CommandKind::IsMany => { + // @ismany ... + let (query, values) = if let [query, values @ ..] = &command.args[..] { + (query, values) + } else { + unreachable!("Checked in CommandKind::validate") + }; + let val = cache.value(); + let got_values = select(val, &query).unwrap(); + assert!(!command.negated, "`@!ismany` is not supported"); - let val = cache.get_value(&command.args[0])?; - let results = select(&val, &command.args[1]).unwrap(); + // Serde json doesn't implement Ord or Hash for Value, so we must + // use a Vec here. While in theory that makes setwize equality + // O(n^2), in practice n will never be large enought to matter. + let expected_values = + values.iter().map(|v| string_to_value(v, cache)).collect::>(); + if expected_values.len() != got_values.len() { + return Err(CkError::FailedCheck( + format!( + "Expected {} values, but `{}` matched to {} values ({:?})", + expected_values.len(), + query, + got_values.len(), + got_values + ), + command, + )); + }; + for got_value in got_values { + if !expected_values.iter().any(|exp| &**exp == got_value) { + return Err(CkError::FailedCheck( + format!("`{}` has match {:?}, which was not expected", query, got_value), + command, + )); + } + } + true + } + CommandKind::Count => { + // @count = Check that the jsonpath matches exactly [count] times + assert_eq!(command.args.len(), 2); + let expected: usize = command.args[1].parse().unwrap(); + let val = cache.value(); + let results = select(val, &command.args[0]).unwrap(); let eq = results.len() == expected; if !command.negated && !eq { return Err(CkError::FailedCheck( format!( "`{}` matched to `{:?}` with length {}, but expected length {}", - &command.args[1], + &command.args[0], results, results.len(), expected @@ -251,17 +285,17 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { } } CommandKind::Is => { - // @has = check *exactly one* item matched by path, and it equals value - assert_eq!(command.args.len(), 3); - let val = cache.get_value(&command.args[0])?; - let results = select(&val, &command.args[1]).unwrap(); - let pat = string_to_value(&command.args[2], cache); + // @has = check *exactly one* item matched by path, and it equals value + assert_eq!(command.args.len(), 2); + let val = cache.value().clone(); + let results = select(&val, &command.args[0]).unwrap(); + let pat = string_to_value(&command.args[1], cache); let is = results.len() == 1 && results[0] == pat.as_ref(); if !command.negated && !is { return Err(CkError::FailedCheck( format!( "{} matched to {:?}, but expected {:?}", - &command.args[1], + &command.args[0], results, pat.as_ref() ), @@ -272,16 +306,16 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { } } CommandKind::Set => { - // @set = - assert_eq!(command.args.len(), 4); + // @set = + assert_eq!(command.args.len(), 3); assert_eq!(command.args[1], "=", "Expected an `=`"); - let val = cache.get_value(&command.args[2])?; - let results = select(&val, &command.args[3]).unwrap(); + let val = cache.value().clone(); + let results = select(&val, &command.args[2]).unwrap(); assert_eq!( results.len(), 1, "Expected 1 match for `{}` (because of @set): matched to {:?}", - command.args[3], + command.args[2], results ); match results.len() { @@ -294,7 +328,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { _ => { panic!( "Got multiple results in `@set` for `{}`: {:?}", - &command.args[3], results + &command.args[2], results, ); } } diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml new file mode 100644 index 000000000..84a6c7f96 --- /dev/null +++ b/src/tools/jsondoclint/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "jsondoclint" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.62" +fs-err = "2.8.1" +rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } +serde_json = "1.0.85" diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs new file mode 100644 index 000000000..ad8e96a0b --- /dev/null +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -0,0 +1,184 @@ +use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; + +/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`] +#[derive(Debug)] +pub(crate) enum Kind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, + // Not in ItemKind + ProcMacro, +} + +impl Kind { + pub fn can_appear_in_mod(self) -> bool { + use Kind::*; + match self { + Module => true, + ExternCrate => true, + Import => true, + Union => true, + Struct => true, + Enum => true, + Function => true, + Trait => true, + TraitAlias => true, + Impl => true, + Typedef => true, + Constant => true, + Static => true, + Macro => true, + ProcMacro => true, + Primitive => true, + ForeignType => true, + + // FIXME(adotinthevoid): I'm not sure if these are corrent + Keyword => false, + OpaqueTy => false, + ProcAttribute => false, + ProcDerive => false, + + // Only in traits + AssocConst => false, + AssocType => false, + Method => false, + + StructField => false, // Only in structs or variants + Variant => false, // Only in enums + } + } + + pub fn can_appear_in_trait(self) -> bool { + match self { + Kind::AssocConst => true, + Kind::AssocType => true, + Kind::Method => true, + + Kind::Module => false, + Kind::ExternCrate => false, + Kind::Import => false, + Kind::Struct => false, + Kind::StructField => false, + Kind::Union => false, + Kind::Enum => false, + Kind::Variant => false, + Kind::Function => false, + Kind::Typedef => false, + Kind::OpaqueTy => false, + Kind::Constant => false, + Kind::Trait => false, + Kind::TraitAlias => false, + Kind::Impl => false, + Kind::Static => false, + Kind::ForeignType => false, + Kind::Macro => false, + Kind::ProcAttribute => false, + Kind::ProcDerive => false, + Kind::Primitive => false, + Kind::Keyword => false, + Kind::ProcMacro => false, + } + } + + pub fn is_struct_field(self) -> bool { + matches!(self, Kind::StructField) + } + pub fn is_module(self) -> bool { + matches!(self, Kind::Module) + } + pub fn is_impl(self) -> bool { + matches!(self, Kind::Impl) + } + pub fn is_variant(self) -> bool { + matches!(self, Kind::Variant) + } + pub fn is_trait(self) -> bool { + matches!(self, Kind::Trait) + } + pub fn is_struct_enum_union(self) -> bool { + matches!(self, Kind::Struct | Kind::Enum | Kind::Union) + } + + pub fn from_item(i: &Item) -> Self { + use Kind::*; + match i.inner { + ItemEnum::Module(_) => Module, + ItemEnum::Import(_) => Import, + ItemEnum::Union(_) => Union, + ItemEnum::Struct(_) => Struct, + ItemEnum::StructField(_) => StructField, + ItemEnum::Enum(_) => Enum, + ItemEnum::Variant(_) => Variant, + ItemEnum::Function(_) => Function, + ItemEnum::Trait(_) => Trait, + ItemEnum::TraitAlias(_) => TraitAlias, + ItemEnum::Method(_) => Method, + ItemEnum::Impl(_) => Impl, + ItemEnum::Typedef(_) => Typedef, + ItemEnum::OpaqueTy(_) => OpaqueTy, + ItemEnum::Constant(_) => Constant, + ItemEnum::Static(_) => Static, + ItemEnum::Macro(_) => Macro, + ItemEnum::ProcMacro(_) => ProcMacro, + // https://github.com/rust-lang/rust/issues/100961 + ItemEnum::PrimitiveType(_) => Primitive, + ItemEnum::ForeignType => ForeignType, + ItemEnum::ExternCrate { .. } => ExternCrate, + ItemEnum::AssocConst { .. } => AssocConst, + ItemEnum::AssocType { .. } => AssocType, + } + } + + pub fn from_summary(s: &ItemSummary) -> Self { + use Kind::*; + match s.kind { + ItemKind::AssocConst => AssocConst, + ItemKind::AssocType => AssocType, + ItemKind::Constant => Constant, + ItemKind::Enum => Enum, + ItemKind::ExternCrate => ExternCrate, + ItemKind::ForeignType => ForeignType, + ItemKind::Function => Function, + ItemKind::Impl => Impl, + ItemKind::Import => Import, + ItemKind::Keyword => Keyword, + ItemKind::Macro => Macro, + ItemKind::Method => Method, + ItemKind::Module => Module, + ItemKind::OpaqueTy => OpaqueTy, + ItemKind::Primitive => Primitive, + ItemKind::ProcAttribute => ProcAttribute, + ItemKind::ProcDerive => ProcDerive, + ItemKind::Static => Static, + ItemKind::Struct => Struct, + ItemKind::StructField => StructField, + ItemKind::Trait => Trait, + ItemKind::TraitAlias => TraitAlias, + ItemKind::Typedef => Typedef, + ItemKind::Union => Union, + ItemKind::Variant => Variant, + } + } +} diff --git a/src/tools/jsondoclint/src/json_find.rs b/src/tools/jsondoclint/src/json_find.rs new file mode 100644 index 000000000..95ea88666 --- /dev/null +++ b/src/tools/jsondoclint/src/json_find.rs @@ -0,0 +1,74 @@ +use std::fmt::Write; + +use serde_json::Value; + +#[derive(Debug, Clone)] +pub enum SelectorPart { + Field(String), + Index(usize), +} + +pub type Selector = Vec; + +pub fn to_jsonpath(sel: &Selector) -> String { + let mut s = String::from("$"); + for part in sel { + match part { + SelectorPart::Field(name) => { + if is_jsonpath_safe(name) { + write!(&mut s, ".{}", name).unwrap(); + } else { + // This is probably wrong in edge cases, but all Id's are + // just ascii alphanumerics, `-` `_`, and `:` + write!(&mut s, "[{name:?}]").unwrap(); + } + } + SelectorPart::Index(idx) => write!(&mut s, "[{idx}]").unwrap(), + } + } + s +} + +fn is_jsonpath_safe(s: &str) -> bool { + s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') +} + +pub fn find_selector(haystack: &Value, needle: &Value) -> Vec { + let mut result = Vec::new(); + let mut sel = Selector::new(); + find_selector_recursive(haystack, needle, &mut result, &mut sel); + result +} + +fn find_selector_recursive( + haystack: &Value, + needle: &Value, + result: &mut Vec, + pos: &mut Selector, +) { + if needle == haystack { + result.push(pos.clone()); + // Haystack cant both contain needle and be needle + } else { + match haystack { + Value::Null => {} + Value::Bool(_) => {} + Value::Number(_) => {} + Value::String(_) => {} + Value::Array(arr) => { + for (idx, subhaystack) in arr.iter().enumerate() { + pos.push(SelectorPart::Index(idx)); + find_selector_recursive(subhaystack, needle, result, pos); + pos.pop().unwrap(); + } + } + Value::Object(obj) => { + for (key, subhaystack) in obj { + pos.push(SelectorPart::Field(key.clone())); + find_selector_recursive(subhaystack, needle, result, pos); + pos.pop().unwrap(); + } + } + } + } +} diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs new file mode 100644 index 000000000..70d7a82a5 --- /dev/null +++ b/src/tools/jsondoclint/src/main.rs @@ -0,0 +1,64 @@ +use std::env; + +use anyhow::{anyhow, bail, Result}; +use fs_err as fs; +use rustdoc_json_types::{Crate, Id, FORMAT_VERSION}; +use serde_json::Value; + +pub(crate) mod item_kind; +mod json_find; +mod validator; + +#[derive(Debug)] +struct Error { + kind: ErrorKind, + id: Id, +} + +#[derive(Debug)] +enum ErrorKind { + NotFound, + Custom(String), +} + +fn main() -> Result<()> { + let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?; + let contents = fs::read_to_string(&path)?; + let krate: Crate = serde_json::from_str(&contents)?; + assert_eq!(krate.format_version, FORMAT_VERSION); + + let mut validator = validator::Validator::new(&krate); + validator.check_crate(); + + if !validator.errs.is_empty() { + for err in validator.errs { + match err.kind { + ErrorKind::NotFound => { + let krate_json: Value = serde_json::from_str(&contents)?; + + let sels = + json_find::find_selector(&krate_json, &Value::String(err.id.0.clone())); + match &sels[..] { + [] => unreachable!( + "id must be in crate, or it wouldn't be reported as not found" + ), + [sel] => eprintln!( + "{} not in index or paths, but refered to at '{}'", + err.id.0, + json_find::to_jsonpath(&sel) + ), + [sel, ..] => eprintln!( + "{} not in index or paths, but refered to at '{}' and more", + err.id.0, + json_find::to_jsonpath(&sel) + ), + } + } + ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg), + } + } + bail!("Errors validating json {path}"); + } + + Ok(()) +} diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs new file mode 100644 index 000000000..a0e77127d --- /dev/null +++ b/src/tools/jsondoclint/src/validator.rs @@ -0,0 +1,442 @@ +use std::collections::HashSet; +use std::hash::Hash; + +use rustdoc_json_types::{ + Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs, + GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, Module, OpaqueTy, + Path, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding, + TypeBindingKind, Typedef, Union, Variant, WherePredicate, +}; + +use crate::{item_kind::Kind, Error, ErrorKind}; + +/// The Validator walks over the JSON tree, and ensures it is well formed. +/// It is made of several parts. +/// +/// - `check_*`: These take a type from [`rustdoc_json_types`], and check that +/// it is well formed. This involves calling `check_*` functions on +/// fields of that item, and `add_*` functions on [`Id`]s. +/// - `add_*`: These add an [`Id`] to the worklist, after validating it to check if +/// the `Id` is a kind expected in this suituation. +#[derive(Debug)] +pub struct Validator<'a> { + pub(crate) errs: Vec, + krate: &'a Crate, + /// Worklist of Ids to check. + todo: HashSet<&'a Id>, + /// Ids that have already been visited, so don't need to be checked again. + seen_ids: HashSet<&'a Id>, + /// Ids that have already been reported missing. + missing_ids: HashSet<&'a Id>, +} + +enum PathKind { + Trait, + StructEnumUnion, +} + +impl<'a> Validator<'a> { + pub fn new(krate: &'a Crate) -> Self { + Self { + krate, + errs: Vec::new(), + seen_ids: HashSet::new(), + todo: HashSet::new(), + missing_ids: HashSet::new(), + } + } + + pub fn check_crate(&mut self) { + let root = &self.krate.root; + self.add_mod_id(root); + while let Some(id) = set_remove(&mut self.todo) { + self.seen_ids.insert(id); + self.check_item(id); + } + } + + fn check_item(&mut self, id: &'a Id) { + if let Some(item) = &self.krate.index.get(id) { + match &item.inner { + ItemEnum::Import(x) => self.check_import(x), + ItemEnum::Union(x) => self.check_union(x), + ItemEnum::Struct(x) => self.check_struct(x), + ItemEnum::StructField(x) => self.check_struct_field(x), + ItemEnum::Enum(x) => self.check_enum(x), + ItemEnum::Variant(x) => self.check_variant(x, id), + ItemEnum::Function(x) => self.check_function(x), + ItemEnum::Trait(x) => self.check_trait(x), + ItemEnum::TraitAlias(x) => self.check_trait_alias(x), + ItemEnum::Method(x) => self.check_method(x), + ItemEnum::Impl(x) => self.check_impl(x), + ItemEnum::Typedef(x) => self.check_typedef(x), + ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), + ItemEnum::Constant(x) => self.check_constant(x), + ItemEnum::Static(x) => self.check_static(x), + ItemEnum::ForeignType => {} // nop + ItemEnum::Macro(x) => self.check_macro(x), + ItemEnum::ProcMacro(x) => self.check_proc_macro(x), + ItemEnum::PrimitiveType(x) => self.check_primitive_type(x), + ItemEnum::Module(x) => self.check_module(x), + // FIXME: Why don't these have their own structs? + ItemEnum::ExternCrate { .. } => {} + ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_), + ItemEnum::AssocType { generics, bounds, default } => { + self.check_generics(generics); + bounds.iter().for_each(|b| self.check_generic_bound(b)); + if let Some(ty) = default { + self.check_type(ty); + } + } + } + } else { + assert!(self.krate.paths.contains_key(id)); + } + } + + // Core checkers + fn check_module(&mut self, module: &'a Module) { + module.items.iter().for_each(|i| self.add_mod_item_id(i)); + } + + fn check_import(&mut self, x: &'a Import) { + if x.glob { + self.add_mod_id(x.id.as_ref().unwrap()); + } else if let Some(id) = &x.id { + self.add_mod_item_id(id); + } + } + + fn check_union(&mut self, x: &'a Union) { + self.check_generics(&x.generics); + x.fields.iter().for_each(|i| self.add_field_id(i)); + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_struct(&mut self, x: &'a Struct) { + self.check_generics(&x.generics); + match &x.kind { + StructKind::Unit => {} + StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)), + StructKind::Plain { fields, fields_stripped: _ } => { + fields.iter().for_each(|f| self.add_field_id(f)) + } + } + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_struct_field(&mut self, x: &'a Type) { + self.check_type(x); + } + + fn check_enum(&mut self, x: &'a Enum) { + self.check_generics(&x.generics); + x.variants.iter().for_each(|i| self.add_variant_id(i)); + x.impls.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_variant(&mut self, x: &'a Variant, id: &'a Id) { + match x { + Variant::Plain(discr) => { + if let Some(discr) = discr { + if let (Err(_), Err(_)) = + (discr.value.parse::(), discr.value.parse::()) + { + self.fail( + id, + ErrorKind::Custom(format!( + "Failed to parse discriminant value `{}`", + discr.value + )), + ); + } + } + } + Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)), + Variant::Struct { fields, fields_stripped: _ } => { + fields.iter().for_each(|f| self.add_field_id(f)) + } + } + } + + fn check_function(&mut self, x: &'a Function) { + self.check_generics(&x.generics); + self.check_fn_decl(&x.decl); + } + + fn check_trait(&mut self, x: &'a Trait) { + self.check_generics(&x.generics); + x.items.iter().for_each(|i| self.add_trait_item_id(i)); + x.bounds.iter().for_each(|i| self.check_generic_bound(i)); + x.implementations.iter().for_each(|i| self.add_impl_id(i)); + } + + fn check_trait_alias(&mut self, x: &'a TraitAlias) { + self.check_generics(&x.generics); + x.params.iter().for_each(|i| self.check_generic_bound(i)); + } + + fn check_method(&mut self, x: &'a Method) { + self.check_fn_decl(&x.decl); + self.check_generics(&x.generics); + } + + fn check_impl(&mut self, x: &'a Impl) { + self.check_generics(&x.generics); + if let Some(path) = &x.trait_ { + self.check_path(path, PathKind::Trait); + } + self.check_type(&x.for_); + x.items.iter().for_each(|i| self.add_trait_item_id(i)); + if let Some(blanket_impl) = &x.blanket_impl { + self.check_type(blanket_impl) + } + } + + fn check_typedef(&mut self, x: &'a Typedef) { + self.check_generics(&x.generics); + self.check_type(&x.type_); + } + + fn check_opaque_ty(&mut self, x: &'a OpaqueTy) { + x.bounds.iter().for_each(|b| self.check_generic_bound(b)); + self.check_generics(&x.generics); + } + + fn check_constant(&mut self, x: &'a Constant) { + self.check_type(&x.type_); + } + + fn check_static(&mut self, x: &'a Static) { + self.check_type(&x.type_); + } + + fn check_macro(&mut self, _: &'a str) { + // nop + } + + fn check_proc_macro(&mut self, _: &'a ProcMacro) { + // nop + } + + fn check_primitive_type(&mut self, _: &'a str) { + // nop + } + + fn check_generics(&mut self, x: &'a Generics) { + x.params.iter().for_each(|p| self.check_generic_param_def(p)); + x.where_predicates.iter().for_each(|w| self.check_where_predicate(w)); + } + + fn check_type(&mut self, x: &'a Type) { + match x { + Type::ResolvedPath(path) => self.check_path(path, PathKind::StructEnumUnion), + Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait), + Type::Generic(_) => {} + Type::Primitive(_) => {} + Type::FunctionPointer(fp) => self.check_function_pointer(&**fp), + Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)), + Type::Slice(inner) => self.check_type(&**inner), + Type::Array { type_, len: _ } => self.check_type(&**type_), + Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)), + Type::Infer => {} + Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_), + Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_), + Type::QualifiedPath { name: _, args, self_type, trait_ } => { + self.check_generic_args(&**args); + self.check_type(&**self_type); + self.check_path(trait_, PathKind::Trait); + } + } + } + + fn check_fn_decl(&mut self, x: &'a FnDecl) { + x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty)); + if let Some(output) = &x.output { + self.check_type(output); + } + } + + fn check_generic_bound(&mut self, x: &'a GenericBound) { + match x { + GenericBound::TraitBound { trait_, generic_params, modifier: _ } => { + self.check_path(trait_, PathKind::Trait); + generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + GenericBound::Outlives(_) => {} + } + } + + fn check_path(&mut self, x: &'a Path, kind: PathKind) { + match kind { + PathKind::Trait => self.add_trait_id(&x.id), + PathKind::StructEnumUnion => self.add_struct_enum_union_id(&x.id), + } + if let Some(args) = &x.args { + self.check_generic_args(&**args); + } + } + + fn check_generic_args(&mut self, x: &'a GenericArgs) { + match x { + GenericArgs::AngleBracketed { args, bindings } => { + args.iter().for_each(|arg| self.check_generic_arg(arg)); + bindings.iter().for_each(|bind| self.check_type_binding(bind)); + } + GenericArgs::Parenthesized { inputs, output } => { + inputs.iter().for_each(|ty| self.check_type(ty)); + if let Some(o) = output { + self.check_type(o); + } + } + } + } + + fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) { + match &gpd.kind { + rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {} + rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => { + bounds.iter().for_each(|b| self.check_generic_bound(b)); + if let Some(ty) = default { + self.check_type(ty); + } + } + rustdoc_json_types::GenericParamDefKind::Const { type_, default: _ } => { + self.check_type(type_) + } + } + } + + fn check_generic_arg(&mut self, arg: &'a GenericArg) { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => self.check_type(ty), + GenericArg::Const(c) => self.check_constant(c), + GenericArg::Infer => {} + } + } + + fn check_type_binding(&mut self, bind: &'a TypeBinding) { + self.check_generic_args(&bind.args); + match &bind.binding { + TypeBindingKind::Equality(term) => self.check_term(term), + TypeBindingKind::Constraint(bounds) => { + bounds.iter().for_each(|b| self.check_generic_bound(b)) + } + } + } + + fn check_term(&mut self, term: &'a Term) { + match term { + Term::Type(ty) => self.check_type(ty), + Term::Constant(con) => self.check_constant(con), + } + } + + fn check_where_predicate(&mut self, w: &'a WherePredicate) { + match w { + WherePredicate::BoundPredicate { type_, bounds, generic_params } => { + self.check_type(type_); + bounds.iter().for_each(|b| self.check_generic_bound(b)); + generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + WherePredicate::RegionPredicate { lifetime: _, bounds } => { + bounds.iter().for_each(|b| self.check_generic_bound(b)); + } + WherePredicate::EqPredicate { lhs, rhs } => { + self.check_type(lhs); + self.check_term(rhs); + } + } + } + + fn check_dyn_trait(&mut self, dyn_trait: &'a DynTrait) { + for pt in &dyn_trait.traits { + self.check_path(&pt.trait_, PathKind::Trait); + pt.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + } + + fn check_function_pointer(&mut self, fp: &'a FunctionPointer) { + self.check_fn_decl(&fp.decl); + fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); + } + + fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) { + if let Some(kind) = self.kind_of(id) { + if valid(kind) { + if !self.seen_ids.contains(id) { + self.todo.insert(id); + } + } else { + self.fail_expecting(id, expected); + } + } else { + if !self.missing_ids.contains(id) { + self.missing_ids.insert(id); + self.fail(id, ErrorKind::NotFound) + } + } + } + + fn add_field_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_struct_field, "StructField"); + } + + fn add_mod_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_module, "Module"); + } + fn add_impl_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_impl, "Impl"); + } + + fn add_variant_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_variant, "Variant"); + } + + fn add_trait_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_trait, "Trait"); + } + + fn add_struct_enum_union_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_struct_enum_union, "Struct or Enum or Union"); + } + + /// Add an Id that appeared in a trait + fn add_trait_item_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item"); + } + + /// Add an Id that appeared in a mod + fn add_mod_item_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item") + } + + fn fail_expecting(&mut self, id: &Id, expected: &str) { + let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong. + self.fail(id, ErrorKind::Custom(format!("Expected {expected} but found {kind:?}"))); + } + + fn fail(&mut self, id: &Id, kind: ErrorKind) { + self.errs.push(Error { id: id.clone(), kind }); + } + + fn kind_of(&mut self, id: &Id) -> Option { + if let Some(item) = self.krate.index.get(id) { + Some(Kind::from_item(item)) + } else if let Some(summary) = self.krate.paths.get(id) { + Some(Kind::from_summary(summary)) + } else { + None + } + } +} + +fn set_remove(set: &mut HashSet) -> Option { + if let Some(id) = set.iter().next() { + let id = id.clone(); + set.take(&id) + } else { + None + } +} diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 9696e35b7..2a923a61b 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -8,6 +8,7 @@ use std::process::Command; /// Descriptions of rustc lint groups. static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("unused", "Lints that detect things being declared but not used, or excess syntax"), + ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"), ("rustdoc", "Rustdoc-specific lints"), ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), ("nonstandard-style", "Violation of standard naming conventions"), diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 90bd24a75..b5e977b26 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -8,12 +8,13 @@ //! make gcc/clang pass `-flavor ` as the first two arguments in the linker invocation //! and since Windows does not support symbolic links for files this wrapper is used in place of a //! symbolic link. It execs `../rust-lld -flavor ` by propagating the flavor argument -//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe` -//! child process. +//! obtained from the wrapper's name as the first two arguments. +//! On Windows it spawns a `..\rust-lld.exe` child process. +use std::env::{self, consts::EXE_SUFFIX}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::{env, process}; +use std::process; trait UnwrapOrExitWith { fn unwrap_or_exit_with(self, context: &str) -> T; @@ -42,7 +43,7 @@ impl UnwrapOrExitWith for Result { /// Exits if the parent directory cannot be determined. fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { let mut rust_lld_exe_name = "rust-lld".to_owned(); - rust_lld_exe_name.push_str(env::consts::EXE_SUFFIX); + rust_lld_exe_name.push_str(EXE_SUFFIX); let mut rust_lld_path = current_exe_path .parent() .unwrap_or_exit_with("directory containing current executable could not be determined") @@ -53,29 +54,33 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { rust_lld_path } +/// Extract LLD flavor name from the lld-wrapper executable name. +fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> { + let file = current_exe_path.file_name(); + let stem = file.and_then(|s| s.to_str()).map(|s| s.trim_end_matches(EXE_SUFFIX)); + Ok(match stem { + Some("ld.lld") => "gnu", + Some("ld64.lld") => "darwin", + Some("lld-link") => "link", + Some("wasm-ld") => "wasm", + _ => return Err(format!("{:?}", file)), + }) +} + /// Returns the command for invoking rust-lld with the correct flavor. -/// LLD only accepts the flavor argument at the first two arguments, so move it there. +/// LLD only accepts the flavor argument at the first two arguments, so pass it there. /// /// Exits on error. fn get_rust_lld_command(current_exe_path: &Path) -> process::Command { let rust_lld_path = get_rust_lld_path(current_exe_path); let mut command = process::Command::new(rust_lld_path); - let mut flavor = None; - let args = env::args_os() - .skip(1) - .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) { - Some(suffix) => { - flavor = Some(suffix.to_string()); - false - } - None => true, - }) - .collect::>(); + let flavor = + get_lld_flavor(current_exe_path).unwrap_or_exit_with("executable has unexpected name"); command.arg("-flavor"); - command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor= is not passed")); - command.args(args); + command.arg(flavor); + command.args(env::args_os().skip(1)); command } diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index fe5195738..c0cef8f7b 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -31,21 +31,17 @@ except ImportError: # read privileges on it). CI will fail otherwise. MAINTAINERS = { 'miri': {'oli-obk', 'RalfJung'}, - 'rls': {'Xanewok'}, - 'rustfmt': {'topecongiro', 'calebcartwright'}, - 'book': {'carols10cents', 'steveklabnik'}, + 'book': {'carols10cents'}, 'nomicon': {'frewsxcv', 'Gankra', 'JohnTitor'}, - 'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'}, - 'rust-by-example': {'steveklabnik', 'marioidival'}, + 'reference': {'Havvy', 'matthewjasper', 'ehuss'}, + 'rust-by-example': {'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, - 'edition-guide': {'ehuss', 'steveklabnik'}, + 'edition-guide': {'ehuss'}, 'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'}, } LABELS = { 'miri': ['A-miri', 'C-bug'], - 'rls': ['A-rls', 'C-bug'], - 'rustfmt': ['A-rustfmt', 'C-bug'], 'book': ['C-bug'], 'nomicon': ['C-bug'], 'reference': ['C-bug'], @@ -57,8 +53,6 @@ LABELS = { REPOS = { 'miri': 'https://github.com/rust-lang/miri', - 'rls': 'https://github.com/rust-lang/rls', - 'rustfmt': 'https://github.com/rust-lang/rustfmt', 'book': 'https://github.com/rust-lang/book', 'nomicon': 'https://github.com/rust-lang/nomicon', 'reference': 'https://github.com/rust-lang/reference', diff --git a/src/tools/replace-version-placeholder/Cargo.toml b/src/tools/replace-version-placeholder/Cargo.toml new file mode 100644 index 000000000..346ce6bd1 --- /dev/null +++ b/src/tools/replace-version-placeholder/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "replace-version-placeholder" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tidy = { path = "../tidy" } +walkdir = "2" diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs new file mode 100644 index 000000000..33b35d054 --- /dev/null +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -0,0 +1,30 @@ +use std::path::PathBuf; +use tidy::{t, walk}; + +pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; + +fn main() { + let root_path: PathBuf = std::env::args_os().nth(1).expect("need path to root of repo").into(); + let version_path = root_path.join("src").join("version"); + let version_str = t!(std::fs::read_to_string(&version_path), version_path); + let version_str = version_str.trim(); + walk::walk( + &root_path, + &mut |path| { + walk::filter_dirs(path) + // We exempt these as they require the placeholder + // for their operation + || path.ends_with("compiler/rustc_attr/src/builtin.rs") + || path.ends_with("src/tools/tidy/src/features/version.rs") + || path.ends_with("src/tools/replace-version-placeholder") + }, + &mut |entry, contents| { + if !contents.contains(VERSION_PLACEHOLDER) { + return; + } + let new_contents = contents.replace(VERSION_PLACEHOLDER, version_str); + let path = entry.path(); + t!(std::fs::write(&path, new_contents), path); + }, + ); +} diff --git a/src/tools/rust-analyzer/.vscode/launch.json b/src/tools/rust-analyzer/.vscode/launch.json index 021b8f048..1e21214ff 100644 --- a/src/tools/rust-analyzer/.vscode/launch.json +++ b/src/tools/rust-analyzer/.vscode/launch.json @@ -78,7 +78,7 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--disable-extension", "matklad.rust-analyzer", + "--disable-extension", "rust-lang.rust-analyzer", "--extensionDevelopmentPath=${workspaceFolder}/editors/code" ], "outFiles": [ diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 703f0e5b8..9f10d92c4 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.58" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" +checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" [[package]] name = "anymap" @@ -78,16 +78,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.28.4", + "object", "rustc-demangle", ] @@ -114,9 +114,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "camino" -version = "1.0.9" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" dependencies = [ "serde", ] @@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.83.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83553c2ef7717e58aecdf42dd9e3c876229f5a1f35a16435b5ddc4addef81827" +checksum = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2" dependencies = [ "proc-macro2", "quote", @@ -183,9 +183,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.83.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd42107d579d8ec2a5af20a8de62a37524a67bf6a4c0ff08a950068f0bfea91" +checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918" dependencies = [ "bitflags", "chalk-derive", @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.83.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c444031541a76c13c145e76d91f1548e9feb2240e7f0c3e77879ceb694994f2d" +checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478" dependencies = [ "chalk-derive", "chalk-ir", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.83.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76f2db19c5e8a3d42340cf5b4d90b8c218750536fca35e2bb285ab6653c0bc8" +checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc" dependencies = [ "chalk-derive", "chalk-ir", @@ -247,25 +247,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -273,9 +259,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -284,9 +270,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if", @@ -296,21 +282,11 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", @@ -359,9 +335,9 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "ena" @@ -458,15 +434,15 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" [[package]] name = "hashbrown" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -710,6 +686,7 @@ dependencies = [ "ide-db", "itertools", "profile", + "serde_json", "sourcegen", "stdx", "syntax", @@ -727,6 +704,7 @@ dependencies = [ "ide-db", "itertools", "parser", + "stdx", "syntax", "test-utils", "text-edit", @@ -793,9 +771,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "jod-thread" @@ -835,9 +813,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libloading" @@ -894,9 +872,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" +checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734" dependencies = [ "bitflags", "serde", @@ -943,9 +921,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" dependencies = [ "libc", ] @@ -1000,9 +978,9 @@ dependencies = [ [[package]] name = "notify" -version = "5.0.0-pre.15" +version = "5.0.0-pre.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7" +checksum = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693" dependencies = [ "bitflags", "crossbeam-channel", @@ -1026,15 +1004,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.29.0" @@ -1046,9 +1015,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "oorandom" @@ -1117,9 +1086,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" [[package]] name = "paths" @@ -1171,7 +1140,7 @@ name = "proc-macro-api" version = "0.0.0" dependencies = [ "memmap2", - "object 0.29.0", + "object", "paths", "profile", "serde", @@ -1186,12 +1155,11 @@ dependencies = [ name = "proc-macro-srv" version = "0.0.0" dependencies = [ - "crossbeam", "expect-test", "libloading", "mbe", "memmap2", - "object 0.29.0", + "object", "paths", "proc-macro-api", "proc-macro-test", @@ -1220,9 +1188,9 @@ version = "0.0.0" [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -1262,11 +1230,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "protobuf" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-support" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c" +dependencies = [ + "thiserror", +] + [[package]] name = "pulldown-cmark" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" dependencies = [ "bitflags", "memchr", @@ -1284,9 +1272,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -1317,18 +1305,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "regex-syntax", ] @@ -1344,9 +1332,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rowan" @@ -1393,6 +1381,7 @@ dependencies = [ "project-model", "rayon", "rustc-hash", + "scip", "serde", "serde_json", "sourcegen", @@ -1437,9 +1426,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "salsa" @@ -1479,6 +1468,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scip" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b" +dependencies = [ + "protobuf", +] + [[package]] name = "scoped-tls" version = "1.0.0" @@ -1493,27 +1491,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.138" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.138" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", @@ -1522,9 +1520,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "indexmap", "itoa", @@ -1534,9 +1532,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", @@ -1593,9 +1591,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -1664,6 +1662,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -1738,9 +1756,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if", "pin-project-lite", @@ -1761,9 +1779,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", "valuable", @@ -1782,9 +1800,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ "matchers", "once_cell", @@ -1904,6 +1922,7 @@ dependencies = [ "indexmap", "paths", "rustc-hash", + "stdx", ] [[package]] diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md index 8bb0517ed..8c3f6f846 100644 --- a/src/tools/rust-analyzer/README.md +++ b/src/tools/rust-analyzer/README.md @@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer ## License -Rust analyzer is primarily distributed under the terms of both the MIT +rust-analyzer is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/src/tools/rust-analyzer/bench_data/glorious_old_parser b/src/tools/rust-analyzer/bench_data/glorious_old_parser index 7e900dfeb..764893daa 100644 --- a/src/tools/rust-analyzer/bench_data/glorious_old_parser +++ b/src/tools/rust-analyzer/bench_data/glorious_old_parser @@ -1988,7 +1988,7 @@ impl<'a> Parser<'a> { err.span_suggestion( span, "declare the type after the parameter binding", - String::from(": "), + ": ", Applicability::HasPlaceholders, ); } else if require_name && is_trait_item { diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 9b5a10acf..b388e47de 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -6,13 +6,14 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; +use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; use cfg::CfgOptions; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::SmolStr; use tt::Subtree; -use vfs::{file_set::FileSet, FileId, VfsPath}; +use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; /// Files are grouped into source roots. A source root is a directory on the /// file systems which is watched for changes. Typically it corresponds to a @@ -31,22 +32,30 @@ pub struct SourceRoot { /// Libraries are considered mostly immutable, this assumption is used to /// optimize salsa's query structure pub is_library: bool, - pub(crate) file_set: FileSet, + file_set: FileSet, } impl SourceRoot { pub fn new_local(file_set: FileSet) -> SourceRoot { SourceRoot { is_library: false, file_set } } + pub fn new_library(file_set: FileSet) -> SourceRoot { SourceRoot { is_library: true, file_set } } + pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { self.file_set.path_for_file(file) } + pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { self.file_set.file_for_path(path) } + + pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { + self.file_set.resolve_path(path) + } + pub fn iter(&self) -> impl Iterator + '_ { self.file_set.iter() } @@ -72,12 +81,19 @@ impl SourceRoot { /// #[derive(Debug, Clone, Default /* Serialize, Deserialize */)] pub struct CrateGraph { - arena: FxHashMap, + arena: NoHashHashMap, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct CrateId(pub u32); +impl stdx::hash::NoHashHashable for CrateId {} +impl std::hash::Hash for CrateId { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateName(SmolStr); @@ -342,7 +358,7 @@ impl CrateGraph { // Check if adding a dep from `from` to `to` creates a cycle. To figure // that out, look for a path in the *opposite* direction, from `to` to // `from`. - if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { + if let Some(path) = self.find_path(&mut NoHashHashSet::default(), dep.crate_id, from) { let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); let err = CyclicDependenciesError { path }; assert!(err.from().0 == from && err.to().0 == dep.crate_id); @@ -365,7 +381,7 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut deps = FxHashSet::default(); + let mut deps = NoHashHashSet::default(); while let Some(krate) = worklist.pop() { if !deps.insert(krate) { @@ -382,10 +398,10 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut rev_deps = FxHashSet::default(); + let mut rev_deps = NoHashHashSet::default(); rev_deps.insert(of); - let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + let mut inverted_graph = NoHashHashMap::<_, Vec<_>>::default(); self.arena.iter().for_each(|(&krate, data)| { data.dependencies .iter() @@ -409,7 +425,7 @@ impl CrateGraph { /// come before the crate itself). pub fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); - let mut visited = FxHashSet::default(); + let mut visited = NoHashHashSet::default(); for krate in self.arena.keys().copied() { go(self, &mut visited, &mut res, krate); @@ -419,7 +435,7 @@ impl CrateGraph { fn go( graph: &CrateGraph, - visited: &mut FxHashSet, + visited: &mut NoHashHashSet, res: &mut Vec, source: CrateId, ) { @@ -459,7 +475,7 @@ impl CrateGraph { fn find_path( &self, - visited: &mut FxHashSet, + visited: &mut NoHashHashSet, from: CrateId, to: CrateId, ) -> Option> { diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 2d0a95b09..da11e4ae7 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -8,7 +8,7 @@ pub mod fixture; use std::{panic, sync::Arc}; -use rustc_hash::FxHashSet; +use stdx::hash::NoHashHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; pub use crate::{ @@ -58,7 +58,7 @@ pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc>; } /// Database which stores all significant input facts: source code and project @@ -94,10 +94,10 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; } -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { let graph = db.crate_graph(); let res = graph .iter() @@ -120,10 +120,10 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { // FIXME: this *somehow* should be platform agnostic... let source_root = self.0.file_source_root(path.anchor); let source_root = self.0.source_root(source_root); - source_root.file_set.resolve_path(path) + source_root.resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { let _p = profile::span("relevant_crates"); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index 4e8bc881a..d9f4ef5b7 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -57,6 +57,7 @@ pub struct FlycheckHandle { // XXX: drop order is significant sender: Sender, _thread: jod_thread::JoinHandle, + id: usize, } impl FlycheckHandle { @@ -72,18 +73,27 @@ impl FlycheckHandle { .name("Flycheck".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); - FlycheckHandle { sender, _thread: thread } + FlycheckHandle { id, sender, _thread: thread } } /// Schedule a re-start of the cargo check worker. - pub fn update(&self) { - self.sender.send(Restart).unwrap(); + pub fn restart(&self) { + self.sender.send(Restart::Yes).unwrap(); + } + + /// Stop this cargo check worker. + pub fn cancel(&self) { + self.sender.send(Restart::No).unwrap(); + } + + pub fn id(&self) -> usize { + self.id } } pub enum Message { /// Request adding a diagnostic with fixes included to a file - AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic }, + AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic }, /// Request check progress notification to client Progress { @@ -96,8 +106,9 @@ pub enum Message { impl fmt::Debug for Message { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Message::AddDiagnostic { workspace_root, diagnostic } => f + Message::AddDiagnostic { id, workspace_root, diagnostic } => f .debug_struct("AddDiagnostic") + .field("id", id) .field("workspace_root", workspace_root) .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) .finish(), @@ -114,9 +125,13 @@ pub enum Progress { DidCheckCrate(String), DidFinish(io::Result<()>), DidCancel, + DidFailToRestart(String), } -struct Restart; +enum Restart { + Yes, + No, +} struct FlycheckActor { id: usize, @@ -143,6 +158,7 @@ impl FlycheckActor { config: FlycheckConfig, workspace_root: AbsPathBuf, ) -> FlycheckActor { + tracing::info!(%id, ?workspace_root, "Spawning flycheck"); FlycheckActor { id, sender, config, workspace_root, cargo_handle: None } } fn progress(&self, progress: Progress) { @@ -158,10 +174,13 @@ impl FlycheckActor { fn run(mut self, inbox: Receiver) { while let Some(event) = self.next_event(&inbox) { match event { - Event::Restart(Restart) => { + Event::Restart(Restart::No) => { + self.cancel_check_process(); + } + Event::Restart(Restart::Yes) => { // Cancel the previously spawned process self.cancel_check_process(); - while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} + while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {} let command = self.check_command(); tracing::debug!(?command, "will restart flycheck"); @@ -175,15 +194,16 @@ impl FlycheckActor { self.progress(Progress::DidStart); } Err(error) => { - tracing::error!( - command = ?self.check_command(), - %error, "failed to restart flycheck" - ); + self.progress(Progress::DidFailToRestart(format!( + "Failed to run the following command: {:?} error={}", + self.check_command(), + error + ))); } } } Event::CheckEvent(None) => { - tracing::debug!("flycheck finished"); + tracing::debug!(flycheck_id = self.id, "flycheck finished"); // Watcher finished let cargo_handle = self.cargo_handle.take().unwrap(); @@ -203,6 +223,7 @@ impl FlycheckActor { CargoMessage::Diagnostic(msg) => { self.send(Message::AddDiagnostic { + id: self.id, workspace_root: self.workspace_root.clone(), diagnostic: msg, }); @@ -216,6 +237,10 @@ impl FlycheckActor { fn cancel_check_process(&mut self) { if let Some(cargo_handle) = self.cargo_handle.take() { + tracing::debug!( + command = ?self.check_command(), + "did cancel flycheck" + ); cargo_handle.cancel(); self.progress(Progress::DidCancel); } @@ -338,7 +363,7 @@ impl CargoActor { // // Because cargo only outputs one JSON object per line, we can // simply skip a line if it doesn't parse, which just ignores any - // erroneus output. + // erroneous output. let mut error = String::new(); let mut read_at_least_one_message = false; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 080a307b1..22f5fb992 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -4,6 +4,7 @@ mod lower; #[cfg(test)] mod tests; pub mod scope; +mod pretty; use std::{ops::Index, sync::Arc}; @@ -249,6 +250,10 @@ pub type PatSource = InFile; pub type LabelPtr = AstPtr; pub type LabelSource = InFile; + +pub type FieldPtr = AstPtr; +pub type FieldSource = InFile; + /// An item body together with the mapping from syntax nodes to HIR expression /// IDs. This is needed to go from e.g. a position in a file to the HIR /// expression containing it; but for type inference etc., we want to operate on @@ -263,18 +268,18 @@ pub type LabelSource = InFile; #[derive(Default, Debug, Eq, PartialEq)] pub struct BodySourceMap { expr_map: FxHashMap, - expr_map_back: ArenaMap>, + expr_map_back: ArenaMap, pat_map: FxHashMap, - pat_map_back: ArenaMap>, + pat_map_back: ArenaMap, label_map: FxHashMap, label_map_back: ArenaMap, /// We don't create explicit nodes for record fields (`S { record_field: 92 }`). /// Instead, we use id of expression (`92`) to identify the field. - field_map: FxHashMap>, ExprId>, - field_map_back: FxHashMap>>, + field_map: FxHashMap, + field_map_back: FxHashMap, expansions: FxHashMap>, HirFileId>, @@ -352,6 +357,10 @@ impl Body { } } + pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { + pretty::print_body_hir(db, self, owner) + } + fn new( db: &dyn DefDatabase, expander: Expander, @@ -415,7 +424,7 @@ impl Index for Body { // Perhaps `expr_syntax` and `expr_id`? impl BodySourceMap { pub fn expr_syntax(&self, expr: ExprId) -> Result { - self.expr_map_back[expr].clone() + self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax) } pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option { @@ -429,7 +438,7 @@ impl BodySourceMap { } pub fn pat_syntax(&self, pat: PatId) -> Result { - self.pat_map_back[pat].clone() + self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { @@ -451,9 +460,10 @@ impl BodySourceMap { self.label_map.get(&src).cloned() } - pub fn field_syntax(&self, expr: ExprId) -> InFile> { + pub fn field_syntax(&self, expr: ExprId) -> FieldSource { self.field_map_back[&expr].clone() } + pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option { let src = node.map(AstPtr::new); self.field_map.get(&src).cloned() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 66f9c24e8..3b3297f78 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -24,7 +24,7 @@ use syntax::{ use crate::{ adt::StructKind, - body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, + body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr}, body::{BodyDiagnostic, ExprSource, PatSource}, builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, db::DefDatabase, @@ -150,21 +150,21 @@ impl ExprCollector<'_> { LowerCtx::new(self.db, self.expander.current_file_id) } - fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { + fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { let src = self.expander.to_source(ptr); - let id = self.make_expr(expr, Ok(src.clone())); + let id = self.make_expr(expr, src.clone()); self.source_map.expr_map.insert(src, id); id } // desugared exprs don't have ptr, that's wrong and should be fixed // somehow. fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { - self.make_expr(expr, Err(SyntheticSyntax)) + self.body.exprs.alloc(expr) } fn missing_expr(&mut self) -> ExprId { self.alloc_expr_desugared(Expr::Missing) } - fn make_expr(&mut self, expr: Expr, src: Result) -> ExprId { + fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId { let id = self.body.exprs.alloc(expr); self.source_map.expr_map_back.insert(id, src); id @@ -172,20 +172,20 @@ impl ExprCollector<'_> { fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let src = self.expander.to_source(ptr); - let id = self.make_pat(pat, Ok(src.clone())); + let id = self.make_pat(pat, src.clone()); self.source_map.pat_map.insert(src, id); id } fn missing_pat(&mut self) -> PatId { - self.make_pat(Pat::Missing, Err(SyntheticSyntax)) + self.body.pats.alloc(Pat::Missing) } - fn make_pat(&mut self, pat: Pat, src: Result) -> PatId { + fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId { let id = self.body.pats.alloc(pat); self.source_map.pat_map_back.insert(id, src); id } - fn alloc_label(&mut self, label: Label, ptr: AstPtr) -> LabelId { + fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { let src = self.expander.to_source(ptr); let id = self.make_label(label, src.clone()); self.source_map.label_map.insert(src, id); @@ -550,12 +550,6 @@ impl ExprCollector<'_> { None => self.alloc_expr(Expr::Missing, syntax_ptr), } } - ast::Expr::MacroStmts(e) => { - let statements = e.statements().filter_map(|s| self.collect_stmt(s)).collect(); - let tail = e.expr().map(|e| self.collect_expr(e)); - - self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr) - } ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr), }) } @@ -632,11 +626,46 @@ impl ExprCollector<'_> { } } - fn collect_stmt(&mut self, s: ast::Stmt) -> Option { + fn collect_macro_as_stmt( + &mut self, + statements: &mut Vec, + mac: ast::MacroExpr, + ) -> Option { + let mac_call = mac.macro_call()?; + let syntax_ptr = AstPtr::new(&ast::Expr::from(mac)); + let macro_ptr = AstPtr::new(&mac_call); + let expansion = self.collect_macro_call( + mac_call, + macro_ptr, + false, + |this, expansion: Option| match expansion { + Some(expansion) => { + expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt)); + expansion.expr().and_then(|expr| match expr { + ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac), + expr => Some(this.collect_expr(expr)), + }) + } + None => None, + }, + ); + match expansion { + Some(tail) => { + // Make the macro-call point to its expanded expression so we can query + // semantics on syntax pointers to the macro + let src = self.expander.to_source(syntax_ptr); + self.source_map.expr_map.insert(src, tail); + Some(tail) + } + None => None, + } + } + + fn collect_stmt(&mut self, statements: &mut Vec, s: ast::Stmt) { match s { ast::Stmt::LetStmt(stmt) => { if self.check_cfg(&stmt).is_none() { - return None; + return; } let pat = self.collect_pat_opt(stmt.pat()); let type_ref = @@ -646,61 +675,26 @@ impl ExprCollector<'_> { .let_else() .and_then(|let_else| let_else.block_expr()) .map(|block| self.collect_block(block)); - Some(Statement::Let { pat, type_ref, initializer, else_branch }) + statements.push(Statement::Let { pat, type_ref, initializer, else_branch }); } ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); - if let Some(expr) = &expr { - if self.check_cfg(expr).is_none() { - return None; - } + match &expr { + Some(expr) if self.check_cfg(expr).is_none() => return, + _ => (), } let has_semi = stmt.semicolon_token().is_some(); // Note that macro could be expanded to multiple statements - if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr { - let mac_call = mac.macro_call()?; - let syntax_ptr = AstPtr::new(expr); - let macro_ptr = AstPtr::new(&mac_call); - let stmt = self.collect_macro_call( - mac_call, - macro_ptr, - false, - |this, expansion: Option| match expansion { - Some(expansion) => { - let statements = expansion - .statements() - .filter_map(|stmt| this.collect_stmt(stmt)) - .collect(); - let tail = expansion.expr().map(|expr| this.collect_expr(expr)); - - let mac_stmts = this.alloc_expr( - Expr::MacroStmts { tail, statements }, - AstPtr::new(&ast::Expr::MacroStmts(expansion)), - ); - - Some(mac_stmts) - } - None => None, - }, - ); - - let expr = match stmt { - Some(expr) => { - // Make the macro-call point to its expanded expression so we can query - // semantics on syntax pointers to the macro - let src = self.expander.to_source(syntax_ptr); - self.source_map.expr_map.insert(src, expr); - expr - } - None => self.alloc_expr(Expr::Missing, syntax_ptr), - }; - Some(Statement::Expr { expr, has_semi }) + if let Some(ast::Expr::MacroExpr(mac)) = expr { + if let Some(expr) = self.collect_macro_as_stmt(statements, mac) { + statements.push(Statement::Expr { expr, has_semi }) + } } else { let expr = self.collect_expr_opt(expr); - Some(Statement::Expr { expr, has_semi }) + statements.push(Statement::Expr { expr, has_semi }); } } - ast::Stmt::Item(_item) => None, + ast::Stmt::Item(_item) => (), } } @@ -721,9 +715,12 @@ impl ExprCollector<'_> { let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); let prev_local_module = mem::replace(&mut self.expander.module, module); - let mut statements: Vec<_> = - block.statements().filter_map(|s| self.collect_stmt(s)).collect(); - let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e)); + let mut statements = Vec::new(); + block.statements().for_each(|s| self.collect_stmt(&mut statements, s)); + let tail = block.tail_expr().and_then(|e| match e { + ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac), + expr => self.maybe_collect_expr(expr), + }); let tail = tail.or_else(|| { let stmt = statements.pop()?; if let Statement::Expr { expr, has_semi: false } = stmt { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs new file mode 100644 index 000000000..f2fed9544 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -0,0 +1,608 @@ +//! A pretty-printer for HIR. + +use std::fmt::{self, Write}; + +use crate::{ + expr::{Array, BindingAnnotation, Literal, Statement}, + pretty::{print_generic_args, print_path, print_type_ref}, + type_ref::TypeRef, +}; + +use super::*; + +pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { + let needs_semi; + let header = match owner { + DefWithBodyId::FunctionId(it) => { + needs_semi = false; + let item_tree_id = it.lookup(db).id; + format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name) + } + DefWithBodyId::StaticId(it) => { + needs_semi = true; + let item_tree_id = it.lookup(db).id; + format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name) + } + DefWithBodyId::ConstId(it) => { + needs_semi = true; + let item_tree_id = it.lookup(db).id; + let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name { + Some(name) => name.to_string(), + None => "_".to_string(), + }; + format!("const {} = ", name) + } + }; + + let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false }; + p.print_expr(body.body_expr); + if needs_semi { + p.buf.push(';'); + } + p.buf +} + +macro_rules! w { + ($dst:expr, $($arg:tt)*) => { + { let _ = write!($dst, $($arg)*); } + }; +} + +macro_rules! wln { + ($dst:expr) => { + { let _ = writeln!($dst); } + }; + ($dst:expr, $($arg:tt)*) => { + { let _ = writeln!($dst, $($arg)*); } + }; +} + +struct Printer<'a> { + body: &'a Body, + buf: String, + indent_level: usize, + needs_indent: bool, +} + +impl<'a> Write for Printer<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + for line in s.split_inclusive('\n') { + if self.needs_indent { + match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + Some('\n') | None => {} + _ => self.buf.push('\n'), + } + self.buf.push_str(&" ".repeat(self.indent_level)); + self.needs_indent = false; + } + + self.buf.push_str(line); + self.needs_indent = line.ends_with('\n'); + } + + Ok(()) + } +} + +impl<'a> Printer<'a> { + fn indented(&mut self, f: impl FnOnce(&mut Self)) { + self.indent_level += 1; + wln!(self); + f(self); + self.indent_level -= 1; + self.buf = self.buf.trim_end_matches('\n').to_string(); + } + + fn whitespace(&mut self) { + match self.buf.chars().next_back() { + None | Some('\n' | ' ') => {} + _ => self.buf.push(' '), + } + } + + fn newline(&mut self) { + match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + Some('\n') | None => {} + _ => writeln!(self).unwrap(), + } + } + + fn print_expr(&mut self, expr: ExprId) { + let expr = &self.body[expr]; + + match expr { + Expr::Missing => w!(self, "�"), + Expr::Underscore => w!(self, "_"), + Expr::Path(path) => self.print_path(path), + Expr::If { condition, then_branch, else_branch } => { + w!(self, "if "); + self.print_expr(*condition); + w!(self, " "); + self.print_expr(*then_branch); + if let Some(els) = *else_branch { + w!(self, " else "); + self.print_expr(els); + } + } + Expr::Let { pat, expr } => { + w!(self, "let "); + self.print_pat(*pat); + w!(self, " = "); + self.print_expr(*expr); + } + Expr::Loop { body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "loop "); + self.print_expr(*body); + } + Expr::While { condition, body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "while "); + self.print_expr(*condition); + self.print_expr(*body); + } + Expr::For { iterable, pat, body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "for "); + self.print_pat(*pat); + w!(self, " in "); + self.print_expr(*iterable); + self.print_expr(*body); + } + Expr::Call { callee, args, is_assignee_expr: _ } => { + self.print_expr(*callee); + w!(self, "("); + if !args.is_empty() { + self.indented(|p| { + for arg in &**args { + p.print_expr(*arg); + wln!(p, ","); + } + }); + } + w!(self, ")"); + } + Expr::MethodCall { receiver, method_name, args, generic_args } => { + self.print_expr(*receiver); + w!(self, ".{}", method_name); + if let Some(args) = generic_args { + w!(self, "::<"); + print_generic_args(args, self).unwrap(); + w!(self, ">"); + } + w!(self, "("); + if !args.is_empty() { + self.indented(|p| { + for arg in &**args { + p.print_expr(*arg); + wln!(p, ","); + } + }); + } + w!(self, ")"); + } + Expr::Match { expr, arms } => { + w!(self, "match "); + self.print_expr(*expr); + w!(self, " {{"); + self.indented(|p| { + for arm in &**arms { + p.print_pat(arm.pat); + if let Some(guard) = arm.guard { + w!(p, " if "); + p.print_expr(guard); + } + w!(p, " => "); + p.print_expr(arm.expr); + wln!(p, ","); + } + }); + wln!(self, "}}"); + } + Expr::Continue { label } => { + w!(self, "continue"); + if let Some(label) = label { + w!(self, " {}", label); + } + } + Expr::Break { expr, label } => { + w!(self, "break"); + if let Some(label) = label { + w!(self, " {}", label); + } + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::Return { expr } => { + w!(self, "return"); + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::Yield { expr } => { + w!(self, "yield"); + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + + w!(self, "{{"); + self.indented(|p| { + for field in &**fields { + w!(p, "{}: ", field.name); + p.print_expr(field.expr); + wln!(p, ","); + } + if let Some(spread) = spread { + w!(p, ".."); + p.print_expr(*spread); + wln!(p); + } + if *ellipsis { + wln!(p, ".."); + } + }); + w!(self, "}}"); + } + Expr::Field { expr, name } => { + self.print_expr(*expr); + w!(self, ".{}", name); + } + Expr::Await { expr } => { + self.print_expr(*expr); + w!(self, ".await"); + } + Expr::Try { expr } => { + self.print_expr(*expr); + w!(self, "?"); + } + Expr::TryBlock { body } => { + w!(self, "try "); + self.print_expr(*body); + } + Expr::Async { body } => { + w!(self, "async "); + self.print_expr(*body); + } + Expr::Const { body } => { + w!(self, "const "); + self.print_expr(*body); + } + Expr::Cast { expr, type_ref } => { + self.print_expr(*expr); + w!(self, " as "); + self.print_type_ref(type_ref); + } + Expr::Ref { expr, rawness, mutability } => { + w!(self, "&"); + if rawness.is_raw() { + w!(self, "raw "); + } + if mutability.is_mut() { + w!(self, "mut "); + } + self.print_expr(*expr); + } + Expr::Box { expr } => { + w!(self, "box "); + self.print_expr(*expr); + } + Expr::UnaryOp { expr, op } => { + let op = match op { + ast::UnaryOp::Deref => "*", + ast::UnaryOp::Not => "!", + ast::UnaryOp::Neg => "-", + }; + w!(self, "{}", op); + self.print_expr(*expr); + } + Expr::BinaryOp { lhs, rhs, op } => { + let (bra, ket) = match op { + None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""), + _ => ("(", ")"), + }; + w!(self, "{}", bra); + self.print_expr(*lhs); + w!(self, "{} ", ket); + match op { + Some(op) => w!(self, "{}", op), + None => w!(self, "�"), // :) + } + w!(self, " {}", bra); + self.print_expr(*rhs); + w!(self, "{}", ket); + } + Expr::Range { lhs, rhs, range_type } => { + if let Some(lhs) = lhs { + w!(self, "("); + self.print_expr(*lhs); + w!(self, ") "); + } + let range = match range_type { + ast::RangeOp::Exclusive => "..", + ast::RangeOp::Inclusive => "..=", + }; + w!(self, "{}", range); + if let Some(rhs) = rhs { + w!(self, "("); + self.print_expr(*rhs); + w!(self, ") "); + } + } + Expr::Index { base, index } => { + self.print_expr(*base); + w!(self, "["); + self.print_expr(*index); + w!(self, "]"); + } + Expr::Closure { args, arg_types, ret_type, body } => { + w!(self, "|"); + for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { + if i != 0 { + w!(self, ", "); + } + self.print_pat(*pat); + if let Some(ty) = ty { + w!(self, ": "); + self.print_type_ref(ty); + } + } + w!(self, "|"); + if let Some(ret_ty) = ret_type { + w!(self, " -> "); + self.print_type_ref(ret_ty); + } + self.whitespace(); + self.print_expr(*body); + } + Expr::Tuple { exprs, is_assignee_expr: _ } => { + w!(self, "("); + for expr in exprs.iter() { + self.print_expr(*expr); + w!(self, ", "); + } + w!(self, ")"); + } + Expr::Unsafe { body } => { + w!(self, "unsafe "); + self.print_expr(*body); + } + Expr::Array(arr) => { + w!(self, "["); + if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) { + self.indented(|p| match arr { + Array::ElementList { elements, is_assignee_expr: _ } => { + for elem in elements.iter() { + p.print_expr(*elem); + w!(p, ", "); + } + } + Array::Repeat { initializer, repeat } => { + p.print_expr(*initializer); + w!(p, "; "); + p.print_expr(*repeat); + } + }); + self.newline(); + } + w!(self, "]"); + } + Expr::Literal(lit) => self.print_literal(lit), + Expr::Block { id: _, statements, tail, label } => { + self.whitespace(); + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "{{"); + if !statements.is_empty() || tail.is_some() { + self.indented(|p| { + for stmt in &**statements { + p.print_stmt(stmt); + } + if let Some(tail) = tail { + p.print_expr(*tail); + } + p.newline(); + }); + } + w!(self, "}}"); + } + } + } + + fn print_pat(&mut self, pat: PatId) { + let pat = &self.body[pat]; + + match pat { + Pat::Missing => w!(self, "�"), + Pat::Wild => w!(self, "_"), + Pat::Tuple { args, ellipsis } => { + w!(self, "("); + for (i, pat) in args.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + if *ellipsis == Some(i) { + w!(self, ".., "); + } + self.print_pat(*pat); + } + w!(self, ")"); + } + Pat::Or(pats) => { + for (i, pat) in pats.iter().enumerate() { + if i != 0 { + w!(self, " | "); + } + self.print_pat(*pat); + } + } + Pat::Record { path, args, ellipsis } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + + w!(self, " {{"); + self.indented(|p| { + for arg in args.iter() { + w!(p, "{}: ", arg.name); + p.print_pat(arg.pat); + wln!(p, ","); + } + if *ellipsis { + wln!(p, ".."); + } + }); + w!(self, "}}"); + } + Pat::Range { start, end } => { + self.print_expr(*start); + w!(self, "..."); + self.print_expr(*end); + } + Pat::Slice { prefix, slice, suffix } => { + w!(self, "["); + for pat in prefix.iter() { + self.print_pat(*pat); + w!(self, ", "); + } + if let Some(pat) = slice { + self.print_pat(*pat); + w!(self, ", "); + } + for pat in suffix.iter() { + self.print_pat(*pat); + w!(self, ", "); + } + w!(self, "]"); + } + Pat::Path(path) => self.print_path(path), + Pat::Lit(expr) => self.print_expr(*expr), + Pat::Bind { mode, name, subpat } => { + let mode = match mode { + BindingAnnotation::Unannotated => "", + BindingAnnotation::Mutable => "mut ", + BindingAnnotation::Ref => "ref ", + BindingAnnotation::RefMut => "ref mut ", + }; + w!(self, "{}{}", mode, name); + if let Some(pat) = subpat { + self.whitespace(); + self.print_pat(*pat); + } + } + Pat::TupleStruct { path, args, ellipsis } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + w!(self, "("); + for (i, arg) in args.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + if *ellipsis == Some(i) { + w!(self, ", .."); + } + self.print_pat(*arg); + } + w!(self, ")"); + } + Pat::Ref { pat, mutability } => { + w!(self, "&"); + if mutability.is_mut() { + w!(self, "mut "); + } + self.print_pat(*pat); + } + Pat::Box { inner } => { + w!(self, "box "); + self.print_pat(*inner); + } + Pat::ConstBlock(c) => { + w!(self, "const "); + self.print_expr(*c); + } + } + } + + fn print_stmt(&mut self, stmt: &Statement) { + match stmt { + Statement::Let { pat, type_ref, initializer, else_branch } => { + w!(self, "let "); + self.print_pat(*pat); + if let Some(ty) = type_ref { + w!(self, ": "); + self.print_type_ref(ty); + } + if let Some(init) = initializer { + w!(self, " = "); + self.print_expr(*init); + } + if let Some(els) = else_branch { + w!(self, " else "); + self.print_expr(*els); + } + wln!(self, ";"); + } + Statement::Expr { expr, has_semi } => { + self.print_expr(*expr); + if *has_semi { + w!(self, ";"); + } + wln!(self); + } + } + } + + fn print_literal(&mut self, literal: &Literal) { + match literal { + Literal::String(it) => w!(self, "{:?}", it), + Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()), + Literal::Char(it) => w!(self, "'{}'", it.escape_debug()), + Literal::Bool(it) => w!(self, "{}", it), + Literal::Int(i, suffix) => { + w!(self, "{}", i); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + Literal::Uint(i, suffix) => { + w!(self, "{}", i); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + Literal::Float(f, suffix) => { + w!(self, "{}", f); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + } + } + + fn print_type_ref(&mut self, ty: &TypeRef) { + print_type_ref(ty, self).unwrap(); + } + + fn print_path(&mut self, path: &Path) { + print_path(path, self).unwrap(); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index f4c390dce..45f64ebb0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -47,16 +47,9 @@ pub struct ScopeData { impl ExprScopes { pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { let body = db.body(def); - Arc::new(ExprScopes::new(&*body)) - } - - fn new(body: &Body) -> ExprScopes { - let mut scopes = - ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; - let mut root = scopes.root_scope(); - scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); - scopes + let mut scopes = ExprScopes::new(&*body); + scopes.shrink_to_fit(); + Arc::new(scopes) } pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { @@ -89,6 +82,17 @@ impl ExprScopes { pub fn scope_by_expr(&self) -> &FxHashMap { &self.scope_by_expr } +} + +impl ExprScopes { + fn new(body: &Body) -> ExprScopes { + let mut scopes = + ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; + let mut root = scopes.root_scope(); + scopes.add_params_bindings(body, root, &body.params); + compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); + scopes + } fn root_scope(&mut self) -> ScopeId { self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] }) @@ -138,6 +142,13 @@ impl ExprScopes { fn set_scope(&mut self, node: ExprId, scope: ScopeId) { self.scope_by_expr.insert(node, scope); } + + fn shrink_to_fit(&mut self) { + let ExprScopes { scopes, scope_by_expr } = self; + scopes.shrink_to_fit(); + scopes.values_mut().for_each(|it| it.entries.shrink_to_fit()); + scope_by_expr.shrink_to_fit(); + } } fn compute_block_scopes( @@ -176,9 +187,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope scopes.set_scope(expr, *scope); match &body[expr] { - Expr::MacroStmts { statements, tail } => { - compute_block_scopes(statements, *tail, body, scopes, scope); - } Expr::Block { statements, tail, id, label } => { let mut scope = scopes.new_block_scope(*scope, *id, make_label(label)); // Overwrite the old scope for the block expr, so that every block scope can be found diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index 25a408036..dd69c3ab4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -156,3 +156,38 @@ impl BuiltinFloat { Some(res) } } + +impl fmt::Display for BuiltinInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinInt::Isize => "isize", + BuiltinInt::I8 => "i8", + BuiltinInt::I16 => "i16", + BuiltinInt::I32 => "i32", + BuiltinInt::I64 => "i64", + BuiltinInt::I128 => "i128", + }) + } +} + +impl fmt::Display for BuiltinUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinUint::Usize => "usize", + BuiltinUint::U8 => "u8", + BuiltinUint::U16 => "u16", + BuiltinUint::U32 => "u32", + BuiltinUint::U64 => "u64", + BuiltinUint::U128 => "u128", + }) + } +} + +impl fmt::Display for BuiltinFloat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinFloat::F32 => "f32", + BuiltinFloat::F64 => "f64", + }) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 35c870895..631ae3cf1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind}; +use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind}; use smallvec::SmallVec; use syntax::ast; @@ -12,7 +12,10 @@ use crate::{ db::DefDatabase, intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, - nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap}, + nameres::{ + attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::ProcMacroKind, + DefMap, + }, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -210,6 +213,13 @@ pub struct TraitData { impl TraitData { pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc { + db.trait_data_with_diagnostics(tr).0 + } + + pub(crate) fn trait_data_with_diagnostics_query( + db: &dyn DefDatabase, + tr: TraitId, + ) -> (Arc, Arc>) { let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); let item_tree = tree_id.item_tree(db); let tr_def = &item_tree[tree_id.value]; @@ -229,17 +239,20 @@ impl TraitData { let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, attribute_calls) = collector.finish(); - - Arc::new(TraitData { - name, - attribute_calls, - items, - is_auto, - is_unsafe, - visibility, - skip_array_during_method_dispatch, - }) + let (items, attribute_calls, diagnostics) = collector.finish(); + + ( + Arc::new(TraitData { + name, + attribute_calls, + items, + is_auto, + is_unsafe, + visibility, + skip_array_during_method_dispatch, + }), + Arc::new(diagnostics), + ) } pub fn associated_types(&self) -> impl Iterator + '_ { @@ -280,7 +293,14 @@ pub struct ImplData { impl ImplData { pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc { - let _p = profile::span("impl_data_query"); + db.impl_data_with_diagnostics(id).0 + } + + pub(crate) fn impl_data_with_diagnostics_query( + db: &dyn DefDatabase, + id: ImplId, + ) -> (Arc, Arc>) { + let _p = profile::span("impl_data_with_diagnostics_query"); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); let item_tree = tree_id.item_tree(db); @@ -293,10 +313,13 @@ impl ImplData { AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); - let (items, attribute_calls) = collector.finish(); + let (items, attribute_calls, diagnostics) = collector.finish(); let items = items.into_iter().map(|(_, item)| item).collect(); - Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }) + ( + Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }), + Arc::new(diagnostics), + ) } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { @@ -437,6 +460,7 @@ struct AssocItemCollector<'a> { db: &'a dyn DefDatabase, module_id: ModuleId, def_map: Arc, + inactive_diagnostics: Vec, container: ItemContainerId, expander: Expander, @@ -459,15 +483,21 @@ impl<'a> AssocItemCollector<'a> { expander: Expander::new(db, file_id, module_id), items: Vec::new(), attr_calls: Vec::new(), + inactive_diagnostics: Vec::new(), } } fn finish( self, - ) -> (Vec<(Name, AssocItemId)>, Option, MacroCallId)>>>) { + ) -> ( + Vec<(Name, AssocItemId)>, + Option, MacroCallId)>>>, + Vec, + ) { ( self.items, if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, + self.inactive_diagnostics, ) } @@ -479,6 +509,12 @@ impl<'a> AssocItemCollector<'a> { 'items: for &item in assoc_items { let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); if !attrs.is_cfg_enabled(self.expander.cfg_options()) { + self.inactive_diagnostics.push(DefDiagnostic::unconfigured_code( + self.module_id.local_id, + InFile::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()), + attrs.cfg().unwrap(), + self.expander.cfg_options().clone(), + )); continue; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index df6dcb024..40b2f734b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -20,7 +20,7 @@ use crate::{ intern::Interned, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItemTarget, LangItems}, - nameres::DefMap, + nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, @@ -106,9 +106,16 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { #[salsa::invoke(ImplData::impl_data_query)] fn impl_data(&self, e: ImplId) -> Arc; + #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)] + fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, Arc>); + #[salsa::invoke(TraitData::trait_data_query)] fn trait_data(&self, e: TraitId) -> Arc; + #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)] + fn trait_data_with_diagnostics(&self, tr: TraitId) + -> (Arc, Arc>); + #[salsa::invoke(TypeAliasData::type_alias_data_query)] fn type_alias_data(&self, e: TypeAliasId) -> Arc; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs index c1b3788ac..419d3feec 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs @@ -12,6 +12,8 @@ //! //! See also a neighboring `body` module. +use std::fmt; + use hir_expand::name::Name; use la_arena::{Idx, RawIdx}; @@ -52,8 +54,8 @@ impl FloatTypeWrapper { } } -impl std::fmt::Display for FloatTypeWrapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for FloatTypeWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", f64::from_bits(self.0)) } } @@ -204,10 +206,6 @@ pub enum Expr { Unsafe { body: ExprId, }, - MacroStmts { - statements: Box<[Statement]>, - tail: Option, - }, Array(Array), Literal(Literal), Underscore, @@ -261,7 +259,7 @@ impl Expr { Expr::Let { expr, .. } => { f(*expr); } - Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => { + Expr::Block { statements, tail, .. } => { for stmt in statements.iter() { match stmt { Statement::Let { initializer, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 2397cf501..469b28c2d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -451,7 +451,7 @@ impl HasChildSource for GenericDefId { if let GenericDefId::TraitId(id) = *self { let trait_ref = id.lookup(db).source(db).value; let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(trait_ref)) + params.insert(idx, Either::Right(trait_ref)); } if let Some(generic_params_list) = generic_params_list { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 375587ee9..3342d4db4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -14,7 +14,7 @@ //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`). //! //! The `ItemTree` for the currently open file can be displayed by using the VS Code command -//! "Rust Analyzer: Debug ItemTree". +//! "rust-analyzer: Debug ItemTree". //! //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index f12d9a127..34dd817fd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -2,13 +2,10 @@ use std::fmt::{self, Write}; -use itertools::Itertools; - use crate::{ attr::RawAttrs, generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, - path::GenericArg, - type_ref::TraitBoundModifier, + pretty::{print_path, print_type_bounds, print_type_ref}, visibility::RawVisibility, }; @@ -464,183 +461,15 @@ impl<'a> Printer<'a> { } fn print_type_ref(&mut self, type_ref: &TypeRef) { - // FIXME: deduplicate with `HirDisplay` impl - match type_ref { - TypeRef::Never => w!(self, "!"), - TypeRef::Placeholder => w!(self, "_"), - TypeRef::Tuple(fields) => { - w!(self, "("); - for (i, field) in fields.iter().enumerate() { - if i != 0 { - w!(self, ", "); - } - self.print_type_ref(field); - } - w!(self, ")"); - } - TypeRef::Path(path) => self.print_path(path), - TypeRef::RawPtr(pointee, mtbl) => { - let mtbl = match mtbl { - Mutability::Shared => "*const", - Mutability::Mut => "*mut", - }; - w!(self, "{} ", mtbl); - self.print_type_ref(pointee); - } - TypeRef::Reference(pointee, lt, mtbl) => { - let mtbl = match mtbl { - Mutability::Shared => "", - Mutability::Mut => "mut ", - }; - w!(self, "&"); - if let Some(lt) = lt { - w!(self, "{} ", lt.name); - } - w!(self, "{}", mtbl); - self.print_type_ref(pointee); - } - TypeRef::Array(elem, len) => { - w!(self, "["); - self.print_type_ref(elem); - w!(self, "; {}]", len); - } - TypeRef::Slice(elem) => { - w!(self, "["); - self.print_type_ref(elem); - w!(self, "]"); - } - TypeRef::Fn(args_and_ret, varargs) => { - let ((_, return_type), args) = - args_and_ret.split_last().expect("TypeRef::Fn is missing return type"); - w!(self, "fn("); - for (i, (_, typeref)) in args.iter().enumerate() { - if i != 0 { - w!(self, ", "); - } - self.print_type_ref(typeref); - } - if *varargs { - if !args.is_empty() { - w!(self, ", "); - } - w!(self, "..."); - } - w!(self, ") -> "); - self.print_type_ref(return_type); - } - TypeRef::Macro(_ast_id) => { - w!(self, ""); - } - TypeRef::Error => w!(self, "{{unknown}}"), - TypeRef::ImplTrait(bounds) => { - w!(self, "impl "); - self.print_type_bounds(bounds); - } - TypeRef::DynTrait(bounds) => { - w!(self, "dyn "); - self.print_type_bounds(bounds); - } - } + print_type_ref(type_ref, self).unwrap(); } fn print_type_bounds(&mut self, bounds: &[Interned]) { - for (i, bound) in bounds.iter().enumerate() { - if i != 0 { - w!(self, " + "); - } - - match bound.as_ref() { - TypeBound::Path(path, modifier) => { - match modifier { - TraitBoundModifier::None => (), - TraitBoundModifier::Maybe => w!(self, "?"), - } - self.print_path(path) - } - TypeBound::ForLifetime(lifetimes, path) => { - w!(self, "for<{}> ", lifetimes.iter().format(", ")); - self.print_path(path); - } - TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), - TypeBound::Error => w!(self, "{{unknown}}"), - } - } + print_type_bounds(bounds, self).unwrap(); } fn print_path(&mut self, path: &Path) { - match path.type_anchor() { - Some(anchor) => { - w!(self, "<"); - self.print_type_ref(anchor); - w!(self, ">::"); - } - None => match path.kind() { - PathKind::Plain => {} - PathKind::Super(0) => w!(self, "self::"), - PathKind::Super(n) => { - for _ in 0..*n { - w!(self, "super::"); - } - } - PathKind::Crate => w!(self, "crate::"), - PathKind::Abs => w!(self, "::"), - PathKind::DollarCrate(_) => w!(self, "$crate::"), - }, - } - - for (i, segment) in path.segments().iter().enumerate() { - if i != 0 { - w!(self, "::"); - } - - w!(self, "{}", segment.name); - if let Some(generics) = segment.args_and_bindings { - // NB: these are all in type position, so `::<` turbofish syntax is not necessary - w!(self, "<"); - let mut first = true; - let args = if generics.has_self_type { - let (self_ty, args) = generics.args.split_first().unwrap(); - w!(self, "Self="); - self.print_generic_arg(self_ty); - first = false; - args - } else { - &generics.args - }; - for arg in args { - if !first { - w!(self, ", "); - } - first = false; - self.print_generic_arg(arg); - } - for binding in &generics.bindings { - if !first { - w!(self, ", "); - } - first = false; - w!(self, "{}", binding.name); - if !binding.bounds.is_empty() { - w!(self, ": "); - self.print_type_bounds(&binding.bounds); - } - if let Some(ty) = &binding.type_ref { - w!(self, " = "); - self.print_type_ref(ty); - } - } - - w!(self, ">"); - } - } - } - - fn print_generic_arg(&mut self, arg: &GenericArg) { - match arg { - GenericArg::Type(ty) => self.print_type_ref(ty), - GenericArg::Const(c) => w!(self, "{}", c), - GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), - } + print_path(path, self).unwrap(); } fn print_generic_params(&mut self, params: &GenericParams) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 5cdf36cc6..e30d9652b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -283,10 +283,10 @@ struct S { "#, expect![[r#" pub(self) struct S { - pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>, - pub(self) b: Qualified::Syntax, - pub(self) c: ::Path<'a>, - pub(self) d: dyn for<'a> Trait<'a>, + pub(self) a: Mixed::<'a, T, Item = (), OtherItem = u8>, + pub(self) b: Qualified::::Syntax, + pub(self) c: ::Path::<'a>, + pub(self) d: dyn for<'a> Trait::<'a>, } "#]], ) @@ -329,7 +329,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} T: Copy, U: ?Sized; - impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> + impl<'a, 'b, T, const K: u8> S::<'a, 'b, T, K> where T: Copy, T: 'a, @@ -352,7 +352,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where Self: Super, T: 'a, - Self: for<'a> Tr<'a, T> + Self: for<'a> Tr::<'a, T> { } "#]], diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 56603f4b1..32ebfda4f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -53,6 +53,7 @@ pub mod import_map; mod test_db; #[cfg(test)] mod macro_expansion_tests; +mod pretty; use std::{ hash::{Hash, Hasher}, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 92dffa7f3..4f626105a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -295,13 +295,13 @@ fn test_concat_expand() { #[rustc_builtin_macro] macro_rules! concat {} -fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false); } +fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); } "##, expect![[r##" #[rustc_builtin_macro] macro_rules! concat {} -fn main() { "foor0bar\nfalse"; } +fn main() { "foor0bar\nfalse\"\u{0}"; } "##]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 30d39d52f..457e43925 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -885,7 +885,7 @@ macro_rules! m { ($t:ty) => ( fn bar() -> $ t {} ) } -fn bar() -> & 'a Baz {} +fn bar() -> &'a Baz {} fn bar() -> extern "Rust"fn() -> Ret {} "#]], @@ -1578,7 +1578,7 @@ macro_rules !register_methods { ($$($val: expr), *) = > { struct Foo; impl Foo { - $(fn $method()-> & 'static[u32] { + $(fn $method()-> &'static[u32] { &[$$($$val), *] } )* @@ -1591,10 +1591,10 @@ macro_rules !implement_methods { ($($val: expr), *) = > { struct Foo; impl Foo { - fn alpha()-> & 'static[u32] { + fn alpha()-> &'static[u32] { &[$($val), *] } - fn beta()-> & 'static[u32] { + fn beta()-> &'static[u32] { &[$($val), *] } } @@ -1602,10 +1602,10 @@ macro_rules !implement_methods { } struct Foo; impl Foo { - fn alpha() -> & 'static[u32] { + fn alpha() -> &'static[u32] { &[1, 2, 3] } - fn beta() -> & 'static[u32] { + fn beta() -> &'static[u32] { &[1, 2, 3] } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 2dff4adf2..d2505e7ca 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -166,7 +166,7 @@ macro_rules! int_base { } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Binary for isize { - fn fmt(&self , f: &mut fmt::Formatter< '_>) -> fmt::Result { + fn fmt(&self , f: &mut fmt::Formatter<'_>) -> fmt::Result { Binary.fmt_int(*self as usize, f) } } @@ -724,7 +724,7 @@ macro_rules! delegate_impl { } } } -impl <> Data for & 'amut G where G: Data {} +impl <> Data for &'amut G where G: Data {} "##]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs index 0710b1ac3..b8d2ca687 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -78,7 +78,7 @@ m!(static bar: &'static str = "hello";); macro_rules! m { ($($t:tt)*) => { $($t)*} } -static bar: & 'static str = "hello"; +static bar: &'static str = "hello"; "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 72c44a0fb..029821e5e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -87,7 +87,7 @@ fn foo() { bar.; blub } fn foo() { bar.; blub } fn foo() { - bar. ; + bar.; blub }"##]], ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 6eb530ecc..9b4ce9f97 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -64,7 +64,7 @@ use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; use profile::Count; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use stdx::format_to; use syntax::{ast, SmolStr}; @@ -98,7 +98,11 @@ pub struct DefMap { /// The prelude module for this crate. This either comes from an import /// marked with the `prelude_import` attribute, or (in the normal case) from /// a dependency (`std` or `core`). + /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used, + /// but that attribute is nightly and when used in a block, it affects resolution globally + /// so we aren't handling this correctly anyways). prelude: Option, + /// The extern prelude is only populated for non-block DefMaps extern_prelude: FxHashMap, /// Side table for resolving derive helpers. @@ -114,6 +118,8 @@ pub struct DefMap { registered_attrs: Vec, /// Custom tool modules registered with `#![register_tool]`. registered_tools: Vec, + /// Unstable features of Rust enabled with `#![feature(A, B)]`. + unstable_features: FxHashSet, edition: Edition, recursion_limit: Option, @@ -284,6 +290,7 @@ impl DefMap { modules, registered_attrs: Vec::new(), registered_tools: Vec::new(), + unstable_features: FxHashSet::default(), diagnostics: Vec::new(), } } @@ -314,6 +321,10 @@ impl DefMap { &self.registered_attrs } + pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool { + self.unstable_features.contains(feature) + } + pub fn root(&self) -> LocalModuleId { self.root } @@ -479,6 +490,7 @@ impl DefMap { registered_tools, fn_proc_macro_mapping, derive_helpers_in_scope, + unstable_features, proc_macro_loading_error: _, block: _, edition: _, @@ -496,6 +508,7 @@ impl DefMap { registered_tools.shrink_to_fit(); fn_proc_macro_mapping.shrink_to_fit(); derive_helpers_in_scope.shrink_to_fit(); + unstable_features.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 8a6bb929c..495bbe457 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -294,6 +294,17 @@ impl DefCollector<'_> { continue; } + if *attr_name == hir_expand::name![feature] { + let features = + attr.parse_path_comma_token_tree().into_iter().flatten().filter_map( + |feat| match feat.segments() { + [name] => Some(name.to_smol_str()), + _ => None, + }, + ); + self.def_map.unstable_features.extend(features); + } + let attr_is_register_like = *attr_name == hir_expand::name![register_attr] || *attr_name == hir_expand::name![register_tool]; if !attr_is_register_like { @@ -501,10 +512,9 @@ impl DefCollector<'_> { Edition::Edition2021 => name![rust_2021], }; - let path_kind = if self.def_map.edition == Edition::Edition2015 { - PathKind::Plain - } else { - PathKind::Abs + let path_kind = match self.def_map.edition { + Edition::Edition2015 => PathKind::Plain, + _ => PathKind::Abs, }; let path = ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter()); @@ -524,7 +534,6 @@ impl DefCollector<'_> { match per_ns.types { Some((ModuleDefId::ModuleId(m), _)) => { self.def_map.prelude = Some(m); - return; } types => { tracing::debug!( @@ -839,7 +848,10 @@ impl DefCollector<'_> { tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 - if import.is_extern_crate && module_id == self.def_map.root { + if import.is_extern_crate + && self.def_map.block.is_none() + && module_id == self.def_map.root + { if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) { self.def_map.extern_prelude.insert(name.clone(), def); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs index 0d01f6d0a..ed7e920fd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs @@ -73,7 +73,7 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } } - pub(super) fn unconfigured_code( + pub fn unconfigured_code( container: LocalModuleId, ast: AstId, cfg: CfgExpr, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index 52a620fe2..ca7bcc814 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -65,6 +65,7 @@ impl ModDir { name: &Name, attr_path: Option<&SmolStr>, ) -> Result<(FileId, bool, ModDir), Box<[String]>> { + let name = name.unescaped(); let orig_file_id = file_id.original_file(db.upcast()); let mut candidate_files = ArrayVec::<_, 2>::new(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index c579bc919..8dfda6df6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -399,14 +399,15 @@ impl DefMap { Some(_) | None => from_scope.or(from_builtin), }, }; - let from_extern_prelude = self - .extern_prelude - .get(name) - .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)); - let from_prelude = self.resolve_in_prelude(db, name); + let extern_prelude = || { + self.extern_prelude + .get(name) + .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)) + }; + let prelude = || self.resolve_in_prelude(db, name); - from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) + from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude) } fn resolve_name_in_crate_root_or_extern_prelude( @@ -414,20 +415,19 @@ impl DefMap { db: &dyn DefDatabase, name: &Name, ) -> PerNs { - let arc; - let crate_def_map = match self.block { + let from_crate_root = match self.block { Some(_) => { - arc = self.crate_root(db).def_map(db); - &arc + let def_map = self.crate_root(db).def_map(db); + def_map[def_map.root].scope.get(name) } - None => self, + None => self[self.root].scope.get(name), + }; + let from_extern_prelude = || { + self.resolve_name_in_extern_prelude(db, name) + .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)) }; - let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name); - let from_extern_prelude = self - .resolve_name_in_extern_prelude(db, name) - .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)); - from_crate_root.or(from_extern_prelude) + from_crate_root.or_else(from_extern_prelude) } fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs index 5089ef2d8..52b79cd0f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs @@ -45,7 +45,7 @@ impl Attrs { kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) }, }), - // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]` + // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]` [ TokenTree::Leaf(Leaf::Ident(trait_name)), TokenTree::Leaf(Leaf::Punct(comma)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs index 79a74873b..ba3bf8b5a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -127,15 +127,31 @@ mod r#async; use self::r#async::Bar; //- /async.rs +mod foo; +mod r#async; pub struct Bar; + +//- /async/foo.rs +pub struct Foo; + +//- /async/async.rs +pub struct Baz; "#, expect![[r#" crate Bar: t v - async: t + r#async: t - crate::async + crate::r#async Bar: t v + foo: t + r#async: t + + crate::r#async::foo + Foo: t v + + crate::r#async::r#async + Baz: t v "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs index bf5bf10c4..2bc1f8e92 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs @@ -43,6 +43,10 @@ impl PerNs { self.types.is_none() && self.values.is_none() && self.macros.is_none() } + pub fn is_full(&self) -> bool { + self.types.is_some() && self.values.is_some() && self.macros.is_some() + } + pub fn take_types(self) -> Option { self.types.map(|it| it.0) } @@ -84,6 +88,14 @@ impl PerNs { } } + pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs { + if self.is_full() { + self + } else { + self.or(f()) + } + } + pub fn iter_items(self) -> impl Iterator { let _p = profile::span("PerNs::iter_items"); self.types diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs new file mode 100644 index 000000000..6636c8a23 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -0,0 +1,209 @@ +//! Display and pretty printing routines. + +use std::fmt::{self, Write}; + +use hir_expand::mod_path::PathKind; +use itertools::Itertools; + +use crate::{ + intern::Interned, + path::{GenericArg, GenericArgs, Path}, + type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, +}; + +pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result { + match path.type_anchor() { + Some(anchor) => { + write!(buf, "<")?; + print_type_ref(anchor, buf)?; + write!(buf, ">::")?; + } + None => match path.kind() { + PathKind::Plain => {} + PathKind::Super(0) => write!(buf, "self")?, + PathKind::Super(n) => { + for i in 0..*n { + if i == 0 { + buf.write_str("super")?; + } else { + buf.write_str("::super")?; + } + } + } + PathKind::Crate => write!(buf, "crate")?, + PathKind::Abs => {} + PathKind::DollarCrate(_) => write!(buf, "$crate")?, + }, + } + + for (i, segment) in path.segments().iter().enumerate() { + if i != 0 || !matches!(path.kind(), PathKind::Plain) { + write!(buf, "::")?; + } + + write!(buf, "{}", segment.name)?; + if let Some(generics) = segment.args_and_bindings { + write!(buf, "::<")?; + print_generic_args(generics, buf)?; + + write!(buf, ">")?; + } + } + + Ok(()) +} + +pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result { + let mut first = true; + let args = if generics.has_self_type { + let (self_ty, args) = generics.args.split_first().unwrap(); + write!(buf, "Self=")?; + print_generic_arg(self_ty, buf)?; + first = false; + args + } else { + &generics.args + }; + for arg in args { + if !first { + write!(buf, ", ")?; + } + first = false; + print_generic_arg(arg, buf)?; + } + for binding in &generics.bindings { + if !first { + write!(buf, ", ")?; + } + first = false; + write!(buf, "{}", binding.name)?; + if !binding.bounds.is_empty() { + write!(buf, ": ")?; + print_type_bounds(&binding.bounds, buf)?; + } + if let Some(ty) = &binding.type_ref { + write!(buf, " = ")?; + print_type_ref(ty, buf)?; + } + } + Ok(()) +} + +pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result { + match arg { + GenericArg::Type(ty) => print_type_ref(ty, buf), + GenericArg::Const(c) => write!(buf, "{}", c), + GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name), + } +} + +pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result { + // FIXME: deduplicate with `HirDisplay` impl + match type_ref { + TypeRef::Never => write!(buf, "!")?, + TypeRef::Placeholder => write!(buf, "_")?, + TypeRef::Tuple(fields) => { + write!(buf, "(")?; + for (i, field) in fields.iter().enumerate() { + if i != 0 { + write!(buf, ", ")?; + } + print_type_ref(field, buf)?; + } + write!(buf, ")")?; + } + TypeRef::Path(path) => print_path(path, buf)?, + TypeRef::RawPtr(pointee, mtbl) => { + let mtbl = match mtbl { + Mutability::Shared => "*const", + Mutability::Mut => "*mut", + }; + write!(buf, "{} ", mtbl)?; + print_type_ref(pointee, buf)?; + } + TypeRef::Reference(pointee, lt, mtbl) => { + let mtbl = match mtbl { + Mutability::Shared => "", + Mutability::Mut => "mut ", + }; + write!(buf, "&")?; + if let Some(lt) = lt { + write!(buf, "{} ", lt.name)?; + } + write!(buf, "{}", mtbl)?; + print_type_ref(pointee, buf)?; + } + TypeRef::Array(elem, len) => { + write!(buf, "[")?; + print_type_ref(elem, buf)?; + write!(buf, "; {}]", len)?; + } + TypeRef::Slice(elem) => { + write!(buf, "[")?; + print_type_ref(elem, buf)?; + write!(buf, "]")?; + } + TypeRef::Fn(args_and_ret, varargs) => { + let ((_, return_type), args) = + args_and_ret.split_last().expect("TypeRef::Fn is missing return type"); + write!(buf, "fn(")?; + for (i, (_, typeref)) in args.iter().enumerate() { + if i != 0 { + write!(buf, ", ")?; + } + print_type_ref(typeref, buf)?; + } + if *varargs { + if !args.is_empty() { + write!(buf, ", ")?; + } + write!(buf, "...")?; + } + write!(buf, ") -> ")?; + print_type_ref(return_type, buf)?; + } + TypeRef::Macro(_ast_id) => { + write!(buf, "")?; + } + TypeRef::Error => write!(buf, "{{unknown}}")?, + TypeRef::ImplTrait(bounds) => { + write!(buf, "impl ")?; + print_type_bounds(bounds, buf)?; + } + TypeRef::DynTrait(bounds) => { + write!(buf, "dyn ")?; + print_type_bounds(bounds, buf)?; + } + } + + Ok(()) +} + +pub(crate) fn print_type_bounds( + bounds: &[Interned], + buf: &mut dyn Write, +) -> fmt::Result { + for (i, bound) in bounds.iter().enumerate() { + if i != 0 { + write!(buf, " + ")?; + } + + match bound.as_ref() { + TypeBound::Path(path, modifier) => { + match modifier { + TraitBoundModifier::None => (), + TraitBoundModifier::Maybe => write!(buf, "?")?, + } + print_path(path, buf)?; + } + TypeBound::ForLifetime(lifetimes, path) => { + write!(buf, "for<{}> ", lifetimes.iter().format(", "))?; + print_path(path, buf)?; + } + TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?, + TypeBound::Error => write!(buf, "{{unknown}}")?, + } + } + + Ok(()) +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 3163fa0f9..8aa5973ca 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -31,12 +31,10 @@ pub struct Resolver { /// /// When using, you generally want to process the scopes in reverse order, /// there's `scopes` *method* for that. - /// - /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec. scopes: Vec, + module_scope: ModuleItemMap, } -// FIXME how to store these best #[derive(Debug, Clone)] struct ModuleItemMap { def_map: Arc, @@ -53,7 +51,7 @@ struct ExprScope { #[derive(Debug, Clone)] enum Scope { /// All the items and imported names of a module - ModuleScope(ModuleItemMap), + BlockScope(ModuleItemMap), /// Brings the generic parameters of an item into scope GenericParams { def: GenericDefId, params: Interned }, /// Brings `Self` in `impl` block into scope @@ -127,24 +125,6 @@ impl Resolver { } } - fn scopes(&self) -> impl Iterator { - self.scopes.iter().rev() - } - - fn resolve_module_path( - &self, - db: &dyn DefDatabase, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> PerNs { - let (item_map, module) = self.module_scope(); - let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); - if segment_index.is_some() { - return PerNs::none(); - } - module_res - } - pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } @@ -155,7 +135,7 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, ) -> Option { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module); match module_res.take_types()? { ModuleDefId::TraitId(it) => { @@ -183,37 +163,38 @@ impl Resolver { ) -> Option<(TypeNs, Option)> { let first_name = path.segments().first()?; let skip_to_mod = path.kind != PathKind::Plain; + if skip_to_mod { + return self.module_scope.resolve_path_in_type_ns(db, path); + } + + let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) }; + for scope in self.scopes() { match scope { Scope::ExprScope(_) => continue, - Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue, - Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::GenericParam(id), idx)); + return Some((TypeNs::GenericParam(id), remaining_idx())); } } - Scope::ImplDefScope(impl_) => { + &Scope::ImplDefScope(impl_) => { if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::SelfType(*impl_), idx)); + return Some((TypeNs::SelfType(impl_), remaining_idx())); } } - Scope::AdtScope(adt) => { + &Scope::AdtScope(adt) => { if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::AdtSelfType(*adt), idx)); + return Some((TypeNs::AdtSelfType(adt), remaining_idx())); } } - Scope::ModuleScope(m) => { + Scope::BlockScope(m) => { if let Some(res) = m.resolve_path_in_type_ns(db, path) { return Some(res); } } } } - None + self.module_scope.resolve_path_in_type_ns(db, path) } pub fn resolve_path_in_type_ns_fully( @@ -235,7 +216,7 @@ impl Resolver { ) -> Option { match visibility { RawVisibility::Module(_) => { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); item_map.resolve_visibility(db, module, visibility) } RawVisibility::Public => Some(Visibility::Public), @@ -251,18 +232,14 @@ impl Resolver { let tmp = name![self]; let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); + if skip_to_mod { + return self.module_scope.resolve_path_in_value_ns(db, path); + } + for scope in self.scopes() { match scope { - Scope::AdtScope(_) - | Scope::ExprScope(_) - | Scope::GenericParams { .. } - | Scope::ImplDefScope(_) - if skip_to_mod => - { - continue - } - - Scope::ExprScope(scope) if n_segments <= 1 => { + Scope::ExprScope(_) if n_segments > 1 => continue, + Scope::ExprScope(scope) => { let entry = scope .expr_scopes .entries(scope.scope_id) @@ -273,44 +250,39 @@ impl Resolver { return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); } } - Scope::ExprScope(_) => continue, - Scope::GenericParams { params, def } if n_segments > 1 => { if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); return Some(ResolveValueResult::Partial(ty, 1)); } } - Scope::GenericParams { params, def } if n_segments == 1 => { + Scope::GenericParams { .. } if n_segments != 1 => continue, + Scope::GenericParams { params, def } => { if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); return Some(ResolveValueResult::ValueNs(val)); } } - Scope::GenericParams { .. } => continue, - Scope::ImplDefScope(impl_) => { + &Scope::ImplDefScope(impl_) => { if first_name == &name![Self] { - if n_segments > 1 { - let ty = TypeNs::SelfType(*impl_); - return Some(ResolveValueResult::Partial(ty, 1)); + return Some(if n_segments > 1 { + ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1) } else { - return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_))); - } + ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)) + }); } } + // bare `Self` doesn't work in the value namespace in a struct/enum definition + Scope::AdtScope(_) if n_segments == 1 => continue, Scope::AdtScope(adt) => { - if n_segments == 1 { - // bare `Self` doesn't work in the value namespace in a struct/enum definition - continue; - } if first_name == &name![Self] { let ty = TypeNs::AdtSelfType(*adt); return Some(ResolveValueResult::Partial(ty, 1)); } } - Scope::ModuleScope(m) => { + Scope::BlockScope(m) => { if let Some(def) = m.resolve_path_in_value_ns(db, path) { return Some(def); } @@ -318,15 +290,16 @@ impl Resolver { } } + if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) { + return res; + } + // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back // to resolving to the primitive type, to allow this to still work in the presence of // `use core::u16;`. if path.kind == PathKind::Plain && path.segments().len() > 1 { - match BuiltinType::by_name(&path.segments()[0]) { - Some(builtin) => { - return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); - } - None => {} + if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) { + return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); } } @@ -345,7 +318,7 @@ impl Resolver { } pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() } @@ -395,30 +368,43 @@ impl Resolver { for scope in self.scopes() { scope.process_names(&mut res, db); } + let ModuleItemMap { ref def_map, module_id } = self.module_scope; + // FIXME: should we provide `self` here? + // f( + // Name::self_param(), + // PerNs::types(Resolution::Def { + // def: m.module.into(), + // }), + // ); + def_map[module_id].scope.entries().for_each(|(name, def)| { + res.add_per_ns(name, def); + }); + def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| { + macs.iter().for_each(|&mac| { + res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac)))); + }) + }); + def_map.extern_prelude().for_each(|(name, &def)| { + res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); + }); + BUILTIN_SCOPE.iter().for_each(|(name, &def)| { + res.add_per_ns(name, def); + }); + if let Some(prelude) = def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { + res.add_per_ns(name, def) + } + } res.map } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { let mut traits = FxHashSet::default(); + for scope in self.scopes() { match scope { - Scope::ModuleScope(m) => { - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(m.def_map[m.module_id].scope.traits()); - - // Add all traits that are in scope because of the containing DefMaps - m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { - if let Some(prelude) = def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(def_map[module].scope.traits()); - None::<()> - }); - } + Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::ImplDefScope(impl_) => { if let Some(target_trait) = &db.impl_data(impl_).target_trait { if let Some(TypeNs::TraitId(trait_)) = @@ -431,35 +417,28 @@ impl Resolver { _ => (), } } - traits - } - fn module_scope(&self) -> (&DefMap, LocalModuleId) { - self.scopes() - .find_map(|scope| match scope { - Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)), - _ => None, - }) - .expect("module scope invariant violated") + // Fill in the prelude traits + if let Some(prelude) = self.module_scope.def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + } + // Fill in module visible traits + traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits()); + traits } pub fn module(&self) -> ModuleId { - let (def_map, local_id) = self.module_scope(); + let (def_map, local_id) = self.item_scope(); def_map.module_id(local_id) } pub fn krate(&self) -> CrateId { - self.def_map().krate() + self.module_scope.def_map.krate() } pub fn def_map(&self) -> &DefMap { - self.scopes - .get(0) - .and_then(|scope| match scope { - Scope::ModuleScope(m) => Some(&m.def_map), - _ => None, - }) - .expect("module scope invariant violated") + self.item_scope().0 } pub fn where_predicates_in_scope( @@ -488,6 +467,36 @@ impl Resolver { } } +impl Resolver { + fn scopes(&self) -> impl Iterator { + self.scopes.iter().rev() + } + + fn resolve_module_path( + &self, + db: &dyn DefDatabase, + path: &ModPath, + shadow: BuiltinShadowMode, + ) -> PerNs { + let (item_map, module) = self.item_scope(); + let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); + if segment_index.is_some() { + return PerNs::none(); + } + module_res + } + + /// The innermost block scope that contains items or the module scope that contains this resolver. + fn item_scope(&self) -> (&DefMap, LocalModuleId) { + self.scopes() + .find_map(|scope| match scope { + Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)), + _ => None, + }) + .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id)) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ScopeDef { ModuleDef(ModuleDefId), @@ -502,14 +511,7 @@ pub enum ScopeDef { impl Scope { fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) { match self { - Scope::ModuleScope(m) => { - // FIXME: should we provide `self` here? - // f( - // Name::self_param(), - // PerNs::types(Resolution::Def { - // def: m.module.into(), - // }), - // ); + Scope::BlockScope(m) => { m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { acc.add_per_ns(name, def); }); @@ -521,18 +523,6 @@ impl Scope { ); }) }); - m.def_map.extern_prelude().for_each(|(name, &def)| { - acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); - }); - BUILTIN_SCOPE.iter().for_each(|(name, &def)| { - acc.add_per_ns(name, def); - }); - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { - acc.add_per_ns(name, def) - } - } } Scope::GenericParams { params, def: parent } => { let parent = *parent; @@ -596,7 +586,7 @@ pub fn resolver_for_scope( if let Some(block) = scopes.block(scope) { if let Some(def_map) = db.block_def_map(block) { let root = def_map.root(); - r = r.push_module_scope(def_map, root); + r = r.push_block_scope(def_map, root); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? @@ -623,8 +613,8 @@ impl Resolver { self.push_scope(Scope::ImplDefScope(impl_def)) } - fn push_module_scope(self, def_map: Arc, module_id: LocalModuleId) -> Resolver { - self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id })) + fn push_block_scope(self, def_map: Arc, module_id: LocalModuleId) -> Resolver { + self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id })) } fn push_expr_scope( @@ -768,14 +758,19 @@ pub trait HasResolver: Copy { impl HasResolver for ModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { let mut def_map = self.def_map(db); - let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)]; + let mut modules: SmallVec<[_; 1]> = smallvec![]; + let mut module_id = self.local_id; while let Some(parent) = def_map.parent() { + modules.push((def_map, module_id)); def_map = parent.def_map(db); - modules.push((def_map.clone(), parent.local_id)); + module_id = parent.local_id; } - let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) }; + let mut resolver = Resolver { + scopes: Vec::with_capacity(modules.len()), + module_scope: ModuleItemMap { def_map, module_id }, + }; for (def_map, module) in modules.into_iter().rev() { - resolver = resolver.push_module_scope(def_map, module); + resolver = resolver.push_block_scope(def_map, module); } resolver } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 9cdc18d6b..b7908bdda 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -10,7 +10,7 @@ use base_db::{ SourceDatabase, Upcast, }; use hir_expand::{db::AstDatabase, InFile}; -use rustc_hash::FxHashSet; +use stdx::hash::NoHashHashSet; use syntax::{algo, ast, AstNode}; use crate::{ @@ -76,7 +76,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs index 924805962..5b4c71be7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs @@ -77,6 +77,10 @@ impl Rawness { Rawness::Ref } } + + pub fn is_raw(&self) -> bool { + matches!(self, Self::RawPtr) + } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 6e22a877a..087268a9e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -224,7 +224,7 @@ pub(crate) fn field_visibilities_query( let resolver = variant_id.module(db).resolver(db); let mut res = ArenaMap::default(); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, field_data.visibility.resolve(db, &resolver)) + res.insert(field_id, field_data.visibility.resolve(db, &resolver)); } Arc::new(res) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs index c1ddef03b..11c0a6764 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs @@ -15,7 +15,7 @@ use std::{ use la_arena::{Arena, Idx}; use profile::Count; use rustc_hash::FxHasher; -use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; +use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. pub struct FileAstId { @@ -92,18 +92,12 @@ impl AstIdMap { // change parent's id. This means that, say, adding a new function to a // trait does not change ids of top-level items, which helps caching. bdfs(node, |it| { - match_ast! { - match it { - ast::Item(module_item) => { - res.alloc(module_item.syntax()); - true - }, - ast::BlockExpr(block) => { - res.alloc(block.syntax()); - true - }, - _ => false, - } + let kind = it.kind(); + if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) { + res.alloc(&it); + true + } else { + false } }); res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ()); @@ -123,6 +117,7 @@ impl AstIdMap { let raw = self.erased_ast_id(item.syntax()); FileAstId { raw, _ty: PhantomData } } + fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { let ptr = SyntaxNodePtr::new(item); let hash = hash_ptr(&ptr); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 76da7c9f1..8befa7f7d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -251,9 +251,13 @@ fn format_args_expand( } for arg in &mut args { // Remove `key =`. - if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) + if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { - arg.token_trees.drain(..2); + // but not with `==` + if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' ) + { + arg.token_trees.drain(..2); + } } } let _format_string = args.remove(0); @@ -357,6 +361,12 @@ fn unquote_str(lit: &tt::Literal) -> Option { token.value().map(|it| it.into_owned()) } +fn unquote_char(lit: &tt::Literal) -> Option { + let lit = ast::make::tokens::literal(&lit.to_string()); + let token = ast::Char::cast(lit)?; + token.value() +} + fn unquote_byte_string(lit: &tt::Literal) -> Option> { let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::ByteString::cast(lit)?; @@ -408,8 +418,12 @@ fn concat_expand( // concat works with string and char literals, so remove any quotes. // It also works with integer, float and boolean literals, so just use the rest // as-is. - let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); - text.push_str(&component); + if let Some(c) = unquote_char(it) { + text.push(c); + } else { + let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); + text.push_str(&component); + } } // handle boolean literals tt::TokenTree::Leaf(tt::Leaf::Ident(id)) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index bd60c3d26..bc97ee15c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -321,7 +321,11 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet SyntaxFixups { preorder.skip_subtree(); continue; } - // In some other situations, we can fix things by just appending some tokens. let end_range = TextRange::empty(node.text_range().end()); match_ast! { @@ -142,8 +141,127 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::WhileExpr(it) => { + if it.condition().is_none() { + // insert placeholder token after the while token + let while_token = match it.while_token() { + Some(t) => t, + None => continue, + }; + append.insert(while_token.into(), vec![ + SyntheticToken { + kind: SyntaxKind::IDENT, + text: "__ra_fixup".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, + ast::LoopExpr(it) => { + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, // FIXME: foo:: - // FIXME: for, loop, match etc. + ast::MatchExpr(it) => { + if it.expr().is_none() { + let match_token = match it.match_token() { + Some(t) => t, + None => continue + }; + append.insert(match_token.into(), vec![ + SyntheticToken { + kind: SyntaxKind::IDENT, + text: "__ra_fixup".into(), + range: end_range, + id: EMPTY_ID + }, + ]); + } + if it.match_arm_list().is_none() { + // No match arms + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, + ast::ForExpr(it) => { + let for_token = match it.for_token() { + Some(token) => token, + None => continue + }; + + let [pat, in_token, iter] = [ + (SyntaxKind::UNDERSCORE, "_"), + (SyntaxKind::IN_KW, "in"), + (SyntaxKind::IDENT, "__ra_fixup") + ].map(|(kind, text)| SyntheticToken { kind, text: text.into(), range: end_range, id: EMPTY_ID}); + + if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() { + append.insert(for_token.into(), vec![pat, in_token, iter]); + // does something funky -- see test case for_no_pat + } else if it.pat().is_none() { + append.insert(for_token.into(), vec![pat]); + } + + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, _ => (), } } @@ -236,6 +354,111 @@ mod tests { assert_eq!(tt.to_string(), original_as_tt.to_string()); } + #[test] + fn just_for_token() { + check( + r#" +fn foo() { + for +} +"#, + expect![[r#" +fn foo () {for _ in __ra_fixup {}} +"#]], + ) + } + + #[test] + fn for_no_iter_pattern() { + check( + r#" +fn foo() { + for {} +} +"#, + expect![[r#" +fn foo () {for _ in __ra_fixup {}} +"#]], + ) + } + + #[test] + fn for_no_body() { + check( + r#" +fn foo() { + for bar in qux +} +"#, + expect![[r#" +fn foo () {for bar in qux {}} +"#]], + ) + } + + // FIXME: https://github.com/rust-lang/rust-analyzer/pull/12937#discussion_r937633695 + #[test] + fn for_no_pat() { + check( + r#" +fn foo() { + for in qux { + + } +} +"#, + expect![[r#" +fn foo () {__ra_fixup} +"#]], + ) + } + + #[test] + fn match_no_expr_no_arms() { + check( + r#" +fn foo() { + match +} +"#, + expect![[r#" +fn foo () {match __ra_fixup {}} +"#]], + ) + } + + #[test] + fn match_expr_no_arms() { + check( + r#" +fn foo() { + match x { + + } +} +"#, + expect![[r#" +fn foo () {match x {}} +"#]], + ) + } + + #[test] + fn match_no_expr() { + check( + r#" +fn foo() { + match { + _ => {} + } +} +"#, + expect![[r#" +fn foo () {match __ra_fixup {}} +"#]], + ) + } + #[test] fn incomplete_field_expr_1() { check( @@ -245,7 +468,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a . __ra_fixup} +fn foo () {a .__ra_fixup} "#]], ) } @@ -255,11 +478,11 @@ fn foo () {a . __ra_fixup} check( r#" fn foo() { - a. ; + a.; } "#, expect![[r#" -fn foo () {a . __ra_fixup ;} +fn foo () {a .__ra_fixup ;} "#]], ) } @@ -269,12 +492,12 @@ fn foo () {a . __ra_fixup ;} check( r#" fn foo() { - a. ; + a.; bar(); } "#, expect![[r#" -fn foo () {a . __ra_fixup ; bar () ;} +fn foo () {a .__ra_fixup ; bar () ;} "#]], ) } @@ -302,7 +525,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {let x = a . __ra_fixup ;} +fn foo () {let x = a .__ra_fixup ;} "#]], ) } @@ -318,7 +541,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a . b ; bar () ;} +fn foo () {a .b ; bar () ;} "#]], ) } @@ -376,6 +599,61 @@ fn foo() { // the {} gets parsed as the condition, I think? expect![[r#" fn foo () {if {} {}} +"#]], + ) + } + + #[test] + fn fixup_while_1() { + check( + r#" +fn foo() { + while +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_while_2() { + check( + r#" +fn foo() { + while foo +} +"#, + expect![[r#" +fn foo () {while foo {}} +"#]], + ) + } + #[test] + fn fixup_while_3() { + check( + r#" +fn foo() { + while {} +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_loop() { + check( + r#" +fn foo() { + loop +} +"#, + expect![[r#" +fn foo () {loop {}} "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 252293090..fc128102f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -130,7 +130,6 @@ pub struct MacroDefId { pub enum MacroDefKind { Declarative(AstId), BuiltIn(BuiltinFnLikeExpander, AstId), - // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander BuiltInAttr(BuiltinAttrExpander, AstId), BuiltInDerive(BuiltinDeriveExpander, AstId), BuiltInEager(EagerExpander, AstId), @@ -617,7 +616,7 @@ impl ExpansionInfo { let token_id = match token_id_in_attr_input { Some(token_id) => token_id, - // the token is not inside an attribute's input so do the lookup in the macro_arg as ususal + // the token is not inside an attribute's input so do the lookup in the macro_arg as usual None => { let relative_range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; @@ -970,7 +969,7 @@ impl ExpandTo { if parent.kind() == MACRO_EXPR && parent .parent() - .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS)) + .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS)) { return ExpandTo::Statements; } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index fea09521e..d7586d129 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -22,7 +22,7 @@ pub struct ModPath { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EscapedModPath<'a>(&'a ModPath); +pub struct UnescapedModPath<'a>(&'a ModPath); #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum PathKind { @@ -102,8 +102,8 @@ impl ModPath { } } - pub fn escaped(&self) -> EscapedModPath<'_> { - EscapedModPath(self) + pub fn unescaped(&self) -> UnescapedModPath<'_> { + UnescapedModPath(self) } fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result { @@ -134,9 +134,9 @@ impl ModPath { } first_segment = false; if escaped { - segment.escaped().fmt(f)? - } else { segment.fmt(f)? + } else { + segment.unescaped().fmt(f)? }; } Ok(()) @@ -145,13 +145,13 @@ impl ModPath { impl Display for ModPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self._fmt(f, false) + self._fmt(f, true) } } -impl<'a> Display for EscapedModPath<'a> { +impl<'a> Display for UnescapedModPath<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0._fmt(f, true) + self.0._fmt(f, false) } } @@ -257,6 +257,7 @@ macro_rules! __known_path { (core::ops::RangeToInclusive) => {}; (core::ops::RangeInclusive) => {}; (core::future::Future) => {}; + (core::future::IntoFuture) => {}; (core::ops::Try) => {}; ($path:path) => { compile_error!("Please register your known path in the path module") diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 85b0a7735..4ce21a579 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -7,12 +7,16 @@ use syntax::{ast, SmolStr, SyntaxKind}; /// `Name` is a wrapper around string, which is used in hir for both references /// and declarations. In theory, names should also carry hygiene info, but we are /// not there yet! +/// +/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it +/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the +/// name without "r#". #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Name(Repr); -/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier +/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct EscapedName<'a>(&'a Name); +pub struct UnescapedName<'a>(&'a Name); #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] enum Repr { @@ -34,37 +38,26 @@ fn is_raw_identifier(name: &str) -> bool { is_keyword && !matches!(name, "self" | "crate" | "super" | "Self") } -impl<'a> fmt::Display for EscapedName<'a> { +impl<'a> fmt::Display for UnescapedName<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 .0 { Repr::Text(text) => { - if is_raw_identifier(text) { - write!(f, "r#{}", &text) - } else { - fmt::Display::fmt(&text, f) - } + let text = text.strip_prefix("r#").unwrap_or(text); + fmt::Display::fmt(&text, f) } Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), } } } -impl<'a> EscapedName<'a> { - pub fn is_escaped(&self) -> bool { - match &self.0 .0 { - Repr::Text(it) => is_raw_identifier(&it), - Repr::TupleField(_) => false, - } - } - - /// Returns the textual representation of this name as a [`SmolStr`]. - /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in - /// the general case. +impl<'a> UnescapedName<'a> { + /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over + /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case. pub fn to_smol_str(&self) -> SmolStr { match &self.0 .0 { Repr::Text(it) => { - if is_raw_identifier(&it) { - SmolStr::from_iter(["r#", &it]) + if let Some(stripped) = it.strip_prefix("r#") { + SmolStr::new(stripped) } else { it.clone() } @@ -98,8 +91,16 @@ impl Name { /// Resolve a name from the text of token. fn resolve(raw_text: &str) -> Name { match raw_text.strip_prefix("r#") { - Some(text) => Name::new_text(SmolStr::new(text)), - None => Name::new_text(raw_text.into()), + // When `raw_text` starts with "r#" but the name does not coincide with any + // keyword, we never need the prefix so we strip it. + Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)), + // Keywords (in the current edition) *can* be used as a name in earlier editions of + // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their + // escaped form. + None if is_raw_identifier(raw_text) => { + Name::new_text(SmolStr::from_iter(["r#", raw_text])) + } + _ => Name::new_text(raw_text.into()), } } @@ -142,8 +143,15 @@ impl Name { } } - pub fn escaped(&self) -> EscapedName<'_> { - EscapedName(self) + pub fn unescaped(&self) -> UnescapedName<'_> { + UnescapedName(self) + } + + pub fn is_escaped(&self) -> bool { + match &self.0 { + Repr::Text(it) => it.starts_with("r#"), + Repr::TupleField(_) => false, + } } } @@ -258,6 +266,7 @@ pub mod known { Try, Ok, Future, + IntoFuture, Result, Option, Output, @@ -327,6 +336,7 @@ pub mod known { test, test_case, recursion_limit, + feature, // Safe intrinsics abort, add_with_overflow, @@ -381,6 +391,7 @@ pub mod known { bitor, bitxor_assign, bitxor, + branch, deref_mut, deref, div_assign, @@ -390,12 +401,14 @@ pub mod known { future_trait, index, index_mut, + into_future, mul_assign, mul, neg, not, owned_box, partial_ord, + poll, r#fn, rem_assign, rem, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index 82f410ecd..e839e97bf 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -196,8 +196,8 @@ impl_to_to_tokentrees! { tt::Literal => self { self }; tt::Ident => self { self }; tt::Punct => self { self }; - &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}; - String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}} + &str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}; + String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}} } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 5cd444c1a..7f143f396 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -18,9 +18,9 @@ ena = "0.14.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.83.0", default-features = false } -chalk-ir = "0.83.0" -chalk-recursive = { version = "0.83.0", default-features = false } +chalk-solve = { version = "0.84.0", default-features = false } +chalk-ir = "0.84.0" +chalk-recursive = { version = "0.84.0", default-features = false } la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.12.0" typed-arena = "2.0.1" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index b6f226dbf..344036dd8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -104,8 +104,7 @@ pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option { fn builtin_deref(ty: &Ty) -> Option<&Ty> { match ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(ty), - TyKind::Raw(.., ty) => Some(ty), + TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty), _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index a9c124b42..4a5533c64 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -164,6 +164,8 @@ impl TyExt for Ty { fn dyn_trait(&self) -> Option { let trait_ref = match self.kind(Interner) { + // The principal trait bound should be the first element of the bounds. This is an + // invariant ensured by `TyLoweringContext::lower_dyn_trait()`. TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { match b.skip_binders() { WhereClause::Implemented(trait_ref) => Some(trait_ref), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 0495a4e64..6ecb6e6fd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -2,7 +2,6 @@ use std::{ collections::HashMap, - convert::TryInto, fmt::{Display, Write}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 642e03edd..c8df4c796 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -159,12 +159,7 @@ impl ExprValidator { } let pattern_arena = Arena::new(); - let cx = MatchCheckCtx { - module: self.owner.module(db.upcast()), - body: self.owner, - db, - pattern_arena: &pattern_arena, - }; + let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena); let mut m_arms = Vec::with_capacity(arms.len()); let mut has_lowering_errors = false; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs index bbbe539c1..47d60fc41 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -52,7 +52,10 @@ use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId}; use smallvec::{smallvec, SmallVec}; use stdx::never; -use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind}; +use crate::{ + infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty, + TyExt, TyKind, +}; use super::{ is_box, @@ -557,8 +560,8 @@ impl SplitWildcard { TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)], // TyKind::Array(..) if ... => unhandled(), TyKind::Array(..) | TyKind::Slice(..) => unhandled(), - &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { - let enum_data = cx.db.enum_data(enum_id); + TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => { + let enum_data = cx.db.enum_data(*enum_id); // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an // additional "unknown" constructor. @@ -591,14 +594,15 @@ impl SplitWildcard { let mut ctors: SmallVec<[_; 1]> = enum_data .variants .iter() - .filter(|&(_, _v)| { + .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id }) + .filter(|&variant| { // If `exhaustive_patterns` is enabled, we exclude variants known to be // uninhabited. let is_uninhabited = is_exhaustive_pat_feature - && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()"); + && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db); !is_uninhabited }) - .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id })) + .map(Variant) .collect(); if is_secretly_empty || is_declared_nonexhaustive { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs index 1221327b9..c4d709a97 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs @@ -277,7 +277,7 @@ use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId}; use smallvec::{smallvec, SmallVec}; use typed_arena::Arena; -use crate::{db::HirDatabase, Ty, TyExt}; +use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt}; use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; @@ -289,13 +289,27 @@ pub(crate) struct MatchCheckCtx<'a, 'p> { pub(crate) db: &'a dyn HirDatabase, /// Lowered patterns from arms plus generated by the check. pub(crate) pattern_arena: &'p Arena>, + exhaustive_patterns: bool, } impl<'a, 'p> MatchCheckCtx<'a, 'p> { - pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool { - // FIXME(iDawer) implement exhaustive_patterns feature. More info in: - // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085 - false + pub(crate) fn new( + module: ModuleId, + body: DefWithBodyId, + db: &'a dyn HirDatabase, + pattern_arena: &'p Arena>, + ) -> Self { + let def_map = db.crate_def_map(module.krate()); + let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns"); + Self { module, body, db, pattern_arena, exhaustive_patterns } + } + + pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool { + if self.feature_exhaustive_patterns() { + is_ty_uninhabited_from(ty, self.module, self.db) + } else { + false + } } /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. @@ -311,10 +325,9 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> { } } - // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." + // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." pub(super) fn feature_exhaustive_patterns(&self) -> bool { - // FIXME see MatchCheckCtx::is_uninhabited - false + self.exhaustive_patterns } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 46eeea0e6..10ffde87e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -182,7 +182,7 @@ pub(crate) type InferResult = Result, TypeError>; #[derive(Debug, PartialEq, Eq, Clone)] pub enum InferenceDiagnostic { NoSuchField { expr: ExprId }, - BreakOutsideOfLoop { expr: ExprId }, + BreakOutsideOfLoop { expr: ExprId, is_break: bool }, MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize }, } @@ -418,18 +418,45 @@ pub(crate) struct InferenceContext<'a> { #[derive(Clone, Debug)] struct BreakableContext { + /// Whether this context contains at least one break expression. may_break: bool, + /// The coercion target of the context. coerce: CoerceMany, + /// The optional label of the context. label: Option, + kind: BreakableKind, +} + +#[derive(Clone, Debug)] +enum BreakableKind { + Block, + Loop, + /// A border is something like an async block, closure etc. Anything that prevents + /// breaking/continuing through + Border, } fn find_breakable<'c>( ctxs: &'c mut [BreakableContext], label: Option<&name::Name>, +) -> Option<&'c mut BreakableContext> { + let mut ctxs = ctxs + .iter_mut() + .rev() + .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop)); + match label { + Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label), + None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)), + } +} + +fn find_continuable<'c>( + ctxs: &'c mut [BreakableContext], + label: Option<&name::Name>, ) -> Option<&'c mut BreakableContext> { match label { - Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), - None => ctxs.last_mut(), + Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)), + None => find_breakable(ctxs, label), } } @@ -734,6 +761,7 @@ impl<'a> InferenceContext<'a> { let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(strukt.into())); } + ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None), _ => return (self.err_ty(), None), }, Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)), @@ -875,7 +903,10 @@ impl<'a> InferenceContext<'a> { } fn resolve_future_future_output(&self) -> Option { - let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?; + let trait_ = self + .resolver + .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture]) + .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index d164e64a8..2d04a864a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -10,25 +10,25 @@ use chalk_ir::{ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp}, + expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp}, generics::TypeOrConstParamData, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, - ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup, + ConstParamId, FieldId, ItemContainerId, Lookup, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; use stdx::always; use syntax::ast::RangeOp; use crate::{ autoderef::{self, Autoderef}, consteval, - infer::coerce::CoerceMany, + infer::{coerce::CoerceMany, find_continuable, BreakableKind}, lower::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, - method_resolution::{self, VisibleFromModule}, + method_resolution::{self, lang_names_for_bin_op, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, utils::{generics, Generics}, @@ -120,32 +120,37 @@ impl<'a> InferenceContext<'a> { let ty = match label { Some(_) => { let break_ty = self.table.new_type_var(); - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(break_ty.clone()), - label: label.map(|label| self.body[label].name.clone()), - }); - let ty = self.infer_block( - tgt_expr, - statements, - *tail, - &Expectation::has_type(break_ty), + let (breaks, ty) = self.with_breakable_ctx( + BreakableKind::Block, + break_ty.clone(), + *label, + |this| { + this.infer_block( + tgt_expr, + statements, + *tail, + &Expectation::has_type(break_ty), + ) + }, ); - let ctxt = self.breakables.pop().expect("breakable stack broken"); - if ctxt.may_break { - ctxt.coerce.complete() - } else { - ty - } + breaks.unwrap_or(ty) } None => self.infer_block(tgt_expr, statements, *tail, expected), }; self.resolver = old_resolver; ty } - Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), + Expr::Unsafe { body } => self.infer_expr(*body, expected), + Expr::Const { body } => { + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr(*body, expected) + }) + .1 + } Expr::TryBlock { body } => { - let _inner = self.infer_expr(*body, expected); + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + let _inner = this.infer_expr(*body, expected); + }); // FIXME should be std::result::Result<{inner}, _> self.err_ty() } @@ -154,7 +159,10 @@ impl<'a> InferenceContext<'a> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + let (_, inner_ty) = + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)) + }); self.diverges = prev_diverges; self.return_ty = prev_ret_ty; @@ -166,54 +174,44 @@ impl<'a> InferenceContext<'a> { TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)) .intern(Interner) } - Expr::Loop { body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.table.new_type_var()), - label: label.map(|label| self.body[label].name.clone()), - }); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - - let ctxt = self.breakables.pop().expect("breakable stack broken"); + &Expr::Loop { body, label } => { + let ty = self.table.new_type_var(); + let (breaks, ()) = + self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| { + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); + }); - if ctxt.may_break { - self.diverges = Diverges::Maybe; - ctxt.coerce.complete() - } else { - TyKind::Never.intern(Interner) + match breaks { + Some(breaks) => { + self.diverges = Diverges::Maybe; + breaks + } + None => TyKind::Never.intern(Interner), } } - Expr::While { condition, body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), + &Expr::While { condition, body, label } => { + self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { + this.infer_expr( + condition, + &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), + ); + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); - self.infer_expr( - *condition, - &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), - ); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); + // the body may not run, so it diverging doesn't mean we diverge self.diverges = Diverges::Maybe; TyBuilder::unit() } - Expr::For { iterable, body, pat, label } => { - let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), - }); + &Expr::For { iterable, body, pat, label } => { + let iterable_ty = self.infer_expr(iterable, &Expectation::none()); let pat_ty = self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); - self.infer_pat(*pat, &pat_ty, BindingMode::default()); + self.infer_pat(pat, &pat_ty, BindingMode::default()); + self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); + }); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); // the body may not run, so it diverging doesn't mean we diverge self.diverges = Diverges::Maybe; TyBuilder::unit() @@ -269,7 +267,9 @@ impl<'a> InferenceContext<'a> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + }); self.diverges = prev_diverges; self.return_ty = prev_ret_ty; @@ -372,37 +372,45 @@ impl<'a> InferenceContext<'a> { let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()) } - Expr::Continue { .. } => TyKind::Never.intern(Interner), - Expr::Break { expr, label } => { - let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) { - Some(ctxt) => { - // avoiding the borrowck - mem::replace( - &mut ctxt.coerce, - CoerceMany::new(self.result.standard_types.unknown.clone()), - ) - } - None => CoerceMany::new(self.result.standard_types.unknown.clone()), + Expr::Continue { label } => { + if let None = find_continuable(&mut self.breakables, label.as_ref()) { + self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { + expr: tgt_expr, + is_break: false, + }); }; - + TyKind::Never.intern(Interner) + } + Expr::Break { expr, label } => { let val_ty = if let Some(expr) = *expr { self.infer_expr(expr, &Expectation::none()) } else { TyBuilder::unit() }; - // FIXME: create a synthetic `()` during lowering so we have something to refer to here? - coerce.coerce(self, *expr, &val_ty); + match find_breakable(&mut self.breakables, label.as_ref()) { + Some(ctxt) => { + // avoiding the borrowck + let mut coerce = mem::replace( + &mut ctxt.coerce, + CoerceMany::new(self.result.standard_types.unknown.clone()), + ); - if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { - ctxt.coerce = coerce; - ctxt.may_break = true; - } else { - self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { - expr: tgt_expr, - }); - }; + // FIXME: create a synthetic `()` during lowering so we have something to refer to here? + coerce.coerce(self, *expr, &val_ty); + let ctxt = find_breakable(&mut self.breakables, label.as_ref()) + .expect("breakable stack changed during coercion"); + ctxt.coerce = coerce; + ctxt.may_break = true; + } + None => { + self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { + expr: tgt_expr, + is_break: true, + }); + } + } TyKind::Never.intern(Interner) } Expr::Return { expr } => { @@ -794,9 +802,6 @@ impl<'a> InferenceContext<'a> { None => self.table.new_float_var(), }, }, - Expr::MacroStmts { tail, statements } => { - self.infer_block(tgt_expr, statements, *tail, expected) - } Expr::Underscore => { // Underscore expressions may only appear in assignee expressions, // which are handled by `infer_assignee_expr()`, so any underscore @@ -947,7 +952,9 @@ impl<'a> InferenceContext<'a> { let lhs_ty = self.infer_expr(lhs, &lhs_expectation); let rhs_ty = self.table.new_type_var(); - let func = self.resolve_binop_method(op); + let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { + self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name) + }); let func = match func { Some(func) => func, None => { @@ -1474,54 +1481,19 @@ impl<'a> InferenceContext<'a> { }) } - fn resolve_binop_method(&self, op: BinaryOp) -> Option { - let (name, lang_item) = match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name!(add), name!(add)), - ArithOp::Mul => (name!(mul), name!(mul)), - ArithOp::Sub => (name!(sub), name!(sub)), - ArithOp::Div => (name!(div), name!(div)), - ArithOp::Rem => (name!(rem), name!(rem)), - ArithOp::Shl => (name!(shl), name!(shl)), - ArithOp::Shr => (name!(shr), name!(shr)), - ArithOp::BitXor => (name!(bitxor), name!(bitxor)), - ArithOp::BitOr => (name!(bitor), name!(bitor)), - ArithOp::BitAnd => (name!(bitand), name!(bitand)), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name!(add_assign), name!(add_assign)), - ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), - ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), - ArithOp::Div => (name!(div_assign), name!(div_assign)), - ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), - ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), - ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), - ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), - ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), - ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), - CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name!(le), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name!(lt), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name!(ge), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name!(gt), name!(partial_ord)) - } - }, - BinaryOp::Assignment { op: None } => return None, - }; - - let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?; - - self.db.trait_data(trait_).method_by_name(&name) + fn with_breakable_ctx( + &mut self, + kind: BreakableKind, + ty: Ty, + label: Option, + cb: impl FnOnce(&mut Self) -> T, + ) -> (Option, T) { + self.breakables.push({ + let label = label.map(|label| self.body[label].name.clone()); + BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label } + }); + let res = cb(self); + let ctx = self.breakables.pop().expect("breakable stack broken"); + (ctx.may_break.then(|| ctx.coerce.complete()), res) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 5e7320a5d..53259d66d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -14,8 +14,9 @@ use crate::{ consteval::intern_const_scalar, infer::{BindingMode, Expectation, InferenceContext, TypeMismatch}, lower::lower_to_chalk_mutability, - static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt, - TyKind, + primitive::UintTy, + static_lifetime, ConcreteConst, ConstValue, Interner, Scalar, Substitution, Ty, TyBuilder, + TyExt, TyKind, }; use super::PatLike; @@ -294,7 +295,29 @@ impl<'a> InferenceContext<'a> { let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); self.infer_expr(*end, &Expectation::has_type(start_ty)) } - Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), + &Pat::Lit(expr) => { + // FIXME: using `Option` here is a workaround until we can use if-let chains in stable. + let mut pat_ty = None; + + // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. + if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] { + if let Some((inner, ..)) = expected.as_reference() { + let inner = self.resolve_ty_shallow(inner); + if matches!(inner.kind(Interner), TyKind::Slice(_)) { + let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); + let slice_ty = TyKind::Slice(elem_ty).intern(Interner); + let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty) + .intern(Interner); + self.write_expr_ty(expr, ty.clone()); + pat_ty = Some(ty); + } + } + } + + pat_ty.unwrap_or_else(|| { + self.infer_expr(expr, &Expectation::has_type(expected.clone())) + }) + } Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { let (inner_ty, alloc_ty) = match expected.as_adt() { @@ -343,7 +366,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. Pat::Path(..) => true, Pat::ConstBlock(..) => true, - Pat::Lit(expr) => !matches!(body[*expr], Expr::Literal(Literal::String(..))), + Pat::Lit(expr) => { + !matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..))) + } Pat::Bind { mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated, subpat: Some(subpat), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs new file mode 100644 index 000000000..0c547192a --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -0,0 +1,173 @@ +//! Type inhabitedness logic. +use std::ops::ControlFlow::{self, Break, Continue}; + +use chalk_ir::{ + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + DebruijnIndex, +}; +use hir_def::{ + adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId, + EnumVariantId, HasModule, Lookup, ModuleId, VariantId, +}; + +use crate::{ + db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind, +}; + +/// Checks whether a type is visibly uninhabited from a particular module. +pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool { + let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); + inhabitedness == BREAK_VISIBLY_UNINHABITED +} + +/// Checks whether a variant is visibly uninhabited from a particular module. +pub(crate) fn is_enum_variant_uninhabited_from( + variant: EnumVariantId, + subst: &Substitution, + target_mod: ModuleId, + db: &dyn HirDatabase, +) -> bool { + let enum_data = db.enum_data(variant.parent); + let vars_attrs = db.variants_attrs(variant.parent); + let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate(); + + let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let inhabitedness = uninhabited_from.visit_variant( + variant.into(), + &enum_data.variants[variant.local_id].variant_data, + subst, + &vars_attrs[variant.local_id], + is_local, + ); + inhabitedness == BREAK_VISIBLY_UNINHABITED +} + +struct UninhabitedFrom<'a> { + target_mod: ModuleId, + db: &'a dyn HirDatabase, +} + +const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); +const BREAK_VISIBLY_UNINHABITED: ControlFlow = Break(VisiblyUninhabited); +#[derive(PartialEq, Eq)] +struct VisiblyUninhabited; + +impl TypeVisitor for UninhabitedFrom<'_> { + type BreakTy = VisiblyUninhabited; + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor { + self + } + + fn visit_ty( + &mut self, + ty: &Ty, + outer_binder: DebruijnIndex, + ) -> ControlFlow { + match ty.kind(Interner) { + TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst), + TyKind::Never => BREAK_VISIBLY_UNINHABITED, + TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder), + TyKind::Array(item_ty, len) => match try_usize_const(len) { + Some(0) | None => CONTINUE_OPAQUELY_INHABITED, + Some(1..) => item_ty.super_visit_with(self, outer_binder), + }, + + TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED, + } + } + + fn interner(&self) -> Interner { + Interner + } +} + +impl UninhabitedFrom<'_> { + fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow { + let attrs = self.db.attrs(adt.into()); + let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists(); + let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate(); + if adt_non_exhaustive && !is_local { + return CONTINUE_OPAQUELY_INHABITED; + } + + // An ADT is uninhabited iff all its variants uninhabited. + match adt { + // rustc: For now, `union`s are never considered uninhabited. + AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED, + AdtId::StructId(s) => { + let struct_data = self.db.struct_data(s); + self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local) + } + AdtId::EnumId(e) => { + let vars_attrs = self.db.variants_attrs(e); + let enum_data = self.db.enum_data(e); + + for (local_id, enum_var) in enum_data.variants.iter() { + let variant_inhabitedness = self.visit_variant( + EnumVariantId { parent: e, local_id }.into(), + &enum_var.variant_data, + subst, + &vars_attrs[local_id], + is_local, + ); + match variant_inhabitedness { + Break(VisiblyUninhabited) => continue, + Continue(()) => return CONTINUE_OPAQUELY_INHABITED, + } + } + BREAK_VISIBLY_UNINHABITED + } + } + } + + fn visit_variant( + &mut self, + variant: VariantId, + variant_data: &VariantData, + subst: &Substitution, + attrs: &Attrs, + is_local: bool, + ) -> ControlFlow { + let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists(); + if non_exhaustive_field_list && !is_local { + return CONTINUE_OPAQUELY_INHABITED; + } + + let is_enum = matches!(variant, VariantId::EnumVariantId(..)); + let field_tys = self.db.field_types(variant); + let field_vis = self.db.field_visibilities(variant); + + for (fid, _) in variant_data.fields().iter() { + self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?; + } + CONTINUE_OPAQUELY_INHABITED + } + + fn visit_field( + &mut self, + vis: Visibility, + ty: &Binders, + subst: &Substitution, + is_enum: bool, + ) -> ControlFlow { + if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) { + let ty = ty.clone().substitute(Interner, subst); + ty.visit_with(self, DebruijnIndex::INNERMOST) + } else { + CONTINUE_OPAQUELY_INHABITED + } + } +} + +fn try_usize_const(c: &Const) -> Option { + let data = &c.data(Interner); + if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) { + return None; + } + match data.value { + ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value), + _ => None, + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 5a5d610e3..a82a331d4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -14,6 +14,7 @@ mod chalk_db; mod chalk_ext; pub mod consteval; mod infer; +mod inhabitedness; mod interner; mod lower; mod mapping; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 3ed9c941f..532544fee 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1,12 +1,12 @@ //! Methods for lowering the HIR to types. There are two main cases here: //! //! - Lowering a type reference like `&usize` or `Option` to a -//! type: The entry point for this is `Ty::from_hir`. -//! - Building the type for an item: This happens through the `type_for_def` query. +//! type: The entry point for this is `TyLoweringContext::lower_ty`. +//! - Building the type for an item: This happens through the `ty` query. //! //! This usually involves resolving names, collecting generic arguments etc. use std::{ - cell::{Cell, RefCell}, + cell::{Cell, RefCell, RefMut}, iter, sync::Arc, }; @@ -47,7 +47,7 @@ use crate::{ consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, make_binders, - mapping::ToChalk, + mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, @@ -238,18 +238,7 @@ impl<'a> TyLoweringContext<'a> { }) .intern(Interner) } - TypeRef::DynTrait(bounds) => { - let self_ty = - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - QuantifiedWhereClauses::from_iter( - Interner, - bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), - ) - }); - let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) - } + TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), TypeRef::ImplTrait(bounds) => { match self.impl_trait_mode { ImplTraitLoweringMode::Opaque => { @@ -341,26 +330,29 @@ impl<'a> TyLoweringContext<'a> { } } TypeRef::Macro(macro_call) => { - let (expander, recursion_start) = { - let mut expander = self.expander.borrow_mut(); - if expander.is_some() { - (Some(expander), false) - } else { - *expander = Some(Expander::new( - self.db.upcast(), - macro_call.file_id, - self.resolver.module(), - )); - (Some(expander), true) + let (mut expander, recursion_start) = { + match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) { + // There already is an expander here, this means we are already recursing + Ok(expander) => (expander, false), + // No expander was created yet, so we are at the start of the expansion recursion + // and therefore have to create an expander. + Err(expander) => ( + RefMut::map(expander, |it| { + it.insert(Expander::new( + self.db.upcast(), + macro_call.file_id, + self.resolver.module(), + )) + }), + true, + ), } }; - let ty = if let Some(mut expander) = expander { - let expander_mut = expander.as_mut().unwrap(); + let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - match expander_mut.enter_expand::(self.db.upcast(), macro_call) { + match expander.enter_expand::(self.db.upcast(), macro_call) { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = - LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); + let ctx = LowerCtx::new(self.db.upcast(), expander.current_file_id()); let type_ref = TypeRef::from_ast(&ctx, expanded); drop(expander); @@ -373,11 +365,14 @@ impl<'a> TyLoweringContext<'a> { .exit(self.db.upcast(), mark); Some(ty) } - _ => None, + _ => { + drop(expander); + None + } } - } else { - None }; + + // drop the expander, resetting it to pre-recursion state if recursion_start { *self.expander.borrow_mut() = None; } @@ -468,29 +463,10 @@ impl<'a> TyLoweringContext<'a> { } } 0 => { - let self_ty = Some( - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - ); - let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - ctx.lower_trait_ref_from_resolved_path( - trait_, - resolved_segment, - self_ty, - ) - }); - let dyn_ty = DynTy { - bounds: crate::make_single_type_binders( - QuantifiedWhereClauses::from_iter( - Interner, - Some(crate::wrap_empty_binders(WhereClause::Implemented( - trait_ref, - ))), - ), - ), - lifetime: static_lifetime(), - }; - TyKind::Dyn(dyn_ty).intern(Interner) + // Trait object type without dyn; this should be handled in upstream. See + // `lower_path()`. + stdx::never!("unexpected fully resolved trait path"); + TyKind::Error.intern(Interner) } _ => { // FIXME report error (ambiguous associated type) @@ -509,7 +485,14 @@ impl<'a> TyLoweringContext<'a> { TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) } ParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id.into()).expect("matching generics"); + let idx = match generics.param_idx(param_id.into()) { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) } } @@ -555,11 +538,20 @@ impl<'a> TyLoweringContext<'a> { let (ty, res) = self.lower_ty_ext(type_ref); return self.lower_ty_relative_path(ty, res, path.segments()); } + let (resolution, remaining_index) = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { Some(it) => it, None => return (TyKind::Error.intern(Interner), None), }; + + if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { + // trait object type without dyn + let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); + let ty = self.lower_dyn_trait(&[Interned::new(bound)]); + return (ty, None); + } + let (resolved_segment, remaining_segments) = match remaining_index { None => ( path.segments().last().expect("resolved path has at least one element"), @@ -987,6 +979,78 @@ impl<'a> TyLoweringContext<'a> { }) } + fn lower_dyn_trait(&self, bounds: &[Interned]) -> Ty { + let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); + // INVARIANT: The principal trait bound must come first. Others may be in any order but + // should be in the same order for the same set but possibly different order of bounds in + // the input. + // This invariant is used by `TyExt::dyn_trait()` and chalk. + let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { + let mut bounds: Vec<_> = bounds + .iter() + .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) + .collect(); + + let mut multiple_regular_traits = false; + let mut multiple_same_projection = false; + bounds.sort_unstable_by(|lhs, rhs| { + use std::cmp::Ordering; + match (lhs.skip_binders(), rhs.skip_binders()) { + (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => { + let lhs_id = lhs.trait_id; + let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto; + let rhs_id = rhs.trait_id; + let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto; + + if !lhs_is_auto && !rhs_is_auto { + multiple_regular_traits = true; + } + // Note that the ordering here is important; this ensures the invariant + // mentioned above. + (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id)) + } + (WhereClause::Implemented(_), _) => Ordering::Less, + (_, WhereClause::Implemented(_)) => Ordering::Greater, + (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => { + match (&lhs.alias, &rhs.alias) { + (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => { + // We only compare the `associated_ty_id`s. We shouldn't have + // multiple bounds for an associated type in the correct Rust code, + // and if we do, we error out. + if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id { + multiple_same_projection = true; + } + lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id) + } + // We don't produce `AliasTy::Opaque`s yet. + _ => unreachable!(), + } + } + // We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet. + _ => unreachable!(), + } + }); + + if multiple_regular_traits || multiple_same_projection { + return None; + } + + // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the + // bounds. We shouldn't have repeated elements besides auto traits at this point. + bounds.dedup(); + + Some(QuantifiedWhereClauses::from_iter(Interner, bounds)) + }); + + if let Some(bounds) = bounds { + let bounds = crate::make_single_type_binders(bounds); + TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) + } else { + // FIXME: report error (additional non-auto traits or associated type rebound) + TyKind::Error.intern(Interner) + } + } + fn lower_impl_trait( &self, bounds: &[Interned], @@ -1126,7 +1190,7 @@ pub(crate) fn field_types_query( let ctx = TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))) + res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } Arc::new(res) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 15df7b3dd..9a63d5013 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -336,7 +336,7 @@ impl InherentImpls { } } -pub fn inherent_impl_crates_query( +pub(crate) fn inherent_impl_crates_query( db: &dyn HirDatabase, krate: CrateId, fp: TyFingerprint, @@ -419,6 +419,55 @@ pub fn def_crates( } } +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> { + use hir_expand::name; + use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; + Some(match op { + BinaryOp::LogicOp(_) => return None, + BinaryOp::ArithOp(aop) => match aop { + ArithOp::Add => (name!(add), name!(add)), + ArithOp::Mul => (name!(mul), name!(mul)), + ArithOp::Sub => (name!(sub), name!(sub)), + ArithOp::Div => (name!(div), name!(div)), + ArithOp::Rem => (name!(rem), name!(rem)), + ArithOp::Shl => (name!(shl), name!(shl)), + ArithOp::Shr => (name!(shr), name!(shr)), + ArithOp::BitXor => (name!(bitxor), name!(bitxor)), + ArithOp::BitOr => (name!(bitor), name!(bitor)), + ArithOp::BitAnd => (name!(bitand), name!(bitand)), + }, + BinaryOp::Assignment { op: Some(aop) } => match aop { + ArithOp::Add => (name!(add_assign), name!(add_assign)), + ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), + ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), + ArithOp::Div => (name!(div_assign), name!(div_assign)), + ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), + ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), + ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), + ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), + ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), + ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), + }, + BinaryOp::CmpOp(cop) => match cop { + CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), + CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), + CmpOp::Ord { ordering: Ordering::Less, strict: false } => { + (name!(le), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Less, strict: true } => { + (name!(lt), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { + (name!(ge), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { + (name!(gt), name!(partial_ord)) + } + }, + BinaryOp::Assignment { op: None } => return None, + }) +} + /// Look up the method with the given name. pub(crate) fn lookup_method( ty: &Canonical, @@ -1015,6 +1064,14 @@ pub fn resolve_indexing_op( None } +macro_rules! check_that { + ($cond:expr) => { + if !$cond { + return false; + } + }; +} + fn is_valid_candidate( table: &mut InferenceTable<'_>, name: Option<&Name>, @@ -1023,54 +1080,10 @@ fn is_valid_candidate( self_ty: &Ty, visible_from_module: Option, ) -> bool { - macro_rules! check_that { - ($cond:expr) => { - if !$cond { - return false; - } - }; - } - let db = table.db; match item { AssocItemId::FunctionId(m) => { - let data = db.function_data(m); - - check_that!(name.map_or(true, |n| n == &data.name)); - check_that!(visible_from_module.map_or(true, |from_module| { - let v = db.function_visibility(m).is_visible_from(db.upcast(), from_module); - if !v { - cov_mark::hit!(autoderef_candidate_not_visible); - } - v - })); - - table.run_in_snapshot(|table| { - let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build(); - let expect_self_ty = match m.lookup(db.upcast()).container { - ItemContainerId::TraitId(_) => { - subst.at(Interner, 0).assert_ty_ref(Interner).clone() - } - ItemContainerId::ImplId(impl_id) => { - subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner) - } - // We should only get called for associated items (impl/trait) - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { - unreachable!() - } - }; - check_that!(table.unify(&expect_self_ty, self_ty)); - if let Some(receiver_ty) = receiver_ty { - check_that!(data.has_self_param()); - - let sig = db.callable_item_signature(m.into()); - let expected_receiver = - sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst); - - check_that!(table.unify(&receiver_ty, &expected_receiver)); - } - true - }) + is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module) } AssocItemId::ConstId(c) => { let data = db.const_data(c); @@ -1103,6 +1116,94 @@ fn is_valid_candidate( } } +fn is_valid_fn_candidate( + table: &mut InferenceTable<'_>, + fn_id: FunctionId, + name: Option<&Name>, + receiver_ty: Option<&Ty>, + self_ty: &Ty, + visible_from_module: Option, +) -> bool { + let db = table.db; + let data = db.function_data(fn_id); + + check_that!(name.map_or(true, |n| n == &data.name)); + check_that!(visible_from_module.map_or(true, |from_module| { + let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module); + if !v { + cov_mark::hit!(autoderef_candidate_not_visible); + } + v + })); + + table.run_in_snapshot(|table| { + let container = fn_id.lookup(db.upcast()).container; + let impl_subst = match container { + ItemContainerId::ImplId(it) => { + TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build() + } + ItemContainerId::TraitId(it) => { + TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build() + } + _ => unreachable!(), + }; + + let fn_subst = TyBuilder::subst_for_def(db, fn_id) + .use_parent_substs(&impl_subst) + .fill_with_inference_vars(table) + .build(); + + let expect_self_ty = match container { + ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(), + ItemContainerId::ImplId(impl_id) => { + fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner) + } + // We should only get called for associated items (impl/trait) + ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { + unreachable!() + } + }; + check_that!(table.unify(&expect_self_ty, self_ty)); + + if let Some(receiver_ty) = receiver_ty { + check_that!(data.has_self_param()); + + let sig = db.callable_item_signature(fn_id.into()); + let expected_receiver = + sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst); + + check_that!(table.unify(&receiver_ty, &expected_receiver)); + } + + if let ItemContainerId::ImplId(impl_id) = container { + // We need to consider the bounds on the impl to distinguish functions of the same name + // for a type. + let predicates = db.generic_predicates(impl_id.into()); + predicates + .iter() + .map(|predicate| { + let (p, b) = predicate + .clone() + .substitute(Interner, &impl_subst) + // Skipping the inner binders is ok, as we don't handle quantified where + // clauses yet. + .into_value_and_skipped_binders(); + stdx::always!(b.len(Interner) == 0); + p + }) + // It's ok to get ambiguity here, as we may not have enough information to prove + // obligations. We'll check if the user is calling the selected method properly + // later anyway. + .all(|p| table.try_obligation(p.cast(Interner)).is_some()) + } else { + // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in + // `iterate_trait_method_candidates()`. + // For others, this function shouldn't be called. + true + } + }) +} + pub fn implements_trait( ty: &Canonical, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index dc7252f70..118e5311e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -10,7 +10,7 @@ use base_db::{ }; use hir_def::{db::DefDatabase, ModuleId}; use hir_expand::db::AstDatabase; -use rustc_hash::{FxHashMap, FxHashSet}; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::TextRange; use test_utils::extract_annotations; @@ -80,7 +80,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -102,7 +102,7 @@ impl TestDB { self.module_for_file_opt(file_id).unwrap() } - pub(crate) fn extract_annotations(&self) -> FxHashMap> { + pub(crate) fn extract_annotations(&self) -> NoHashHashMap> { let mut files = Vec::new(); let crate_graph = self.crate_graph(); for krate in crate_graph.iter() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index a1ab6060e..b3adafaaf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -193,8 +193,6 @@ fn expr_macro_def_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize 39..442 '{ ...!(); }': () 73..94 'spam!(...am!())': {unknown} 100..119 'for _ ...!() {}': () @@ -276,8 +274,6 @@ fn expr_macro_rules_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize 53..456 '{ ...!(); }': () 87..108 'spam!(...am!())': {unknown} 114..133 'for _ ...!() {}': () @@ -312,7 +308,6 @@ fn expr_macro_expanded_in_stmts() { } "#, expect![[r#" - !0..8 'leta=();': () !3..4 'a': () !5..7 '()': () 57..84 '{ ...); } }': () @@ -321,7 +316,7 @@ fn expr_macro_expanded_in_stmts() { } #[test] -fn recurisve_macro_expanded_in_stmts() { +fn recursive_macro_expanded_in_stmts() { check_infer( r#" macro_rules! ng { @@ -340,11 +335,6 @@ fn recurisve_macro_expanded_in_stmts() { } "#, expect![[r#" - !0..7 'leta=3;': () - !0..13 'ng!{[leta=3]}': () - !0..13 'ng!{[leta=]3}': () - !0..13 'ng!{[leta]=3}': () - !0..13 'ng!{[let]a=3}': () !3..4 'a': i32 !5..6 '3': i32 196..237 '{ ...= a; }': () @@ -369,8 +359,6 @@ fn recursive_inner_item_macro_rules() { "#, expect![[r#" !0..1 '1': i32 - !0..7 'mac!($)': () - !0..26 'macro_...>{1};}': () 107..143 '{ ...!(); }': () 129..130 'a': i32 "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 68463dc06..81588a7c4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1790,3 +1790,46 @@ impl u16 { "#, ) } + +#[test] +fn with_impl_bounds() { + check_types( + r#" +trait Trait {} +struct Foo(T); +impl Trait for isize {} + +impl Foo { + fn foo() -> isize { 0 } + fn bar(&self) -> isize { 0 } +} + +impl Foo<()> { + fn foo() {} + fn bar(&self) {} +} + +fn f() { + let _ = Foo::::foo(); + //^isize + let _ = Foo(0isize).bar(); + //^isize + let _ = Foo::<()>::foo(); + //^() + let _ = Foo(()).bar(); + //^() + let _ = Foo::::foo(); + //^{unknown} + let _ = Foo(0usize).bar(); + //^{unknown} +} + +fn g(a: T) { + let _ = Foo::::foo(); + //^isize + let _ = Foo(a).bar(); + //^isize +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 399553356..eb04bf877 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -315,6 +315,51 @@ fn infer_pattern_match_string_literal() { ); } +#[test] +fn infer_pattern_match_byte_string_literal() { + check_infer_with_mismatches( + r#" + //- minicore: index + struct S; + impl core::ops::Index for [T; N] { + type Output = [u8]; + fn index(&self, index: core::ops::RangeFull) -> &Self::Output { + loop {} + } + } + fn test(v: [u8; 3]) { + if let b"foo" = &v[S] {} + if let b"foo" = &v {} + } + "#, + expect![[r#" + 105..109 'self': &[T; N] + 111..116 'index': {unknown} + 157..180 '{ ... }': &[u8] + 167..174 'loop {}': ! + 172..174 '{}': () + 191..192 'v': [u8; 3] + 203..261 '{ ...v {} }': () + 209..233 'if let...[S] {}': () + 212..230 'let b"... &v[S]': bool + 216..222 'b"foo"': &[u8] + 216..222 'b"foo"': &[u8] + 225..230 '&v[S]': &[u8] + 226..227 'v': [u8; 3] + 226..230 'v[S]': [u8] + 228..229 'S': S + 231..233 '{}': () + 238..259 'if let... &v {}': () + 241..256 'let b"foo" = &v': bool + 245..251 'b"foo"': &[u8; 3] + 245..251 'b"foo"': &[u8; 3] + 254..256 '&v': &[u8; 3] + 255..256 'v': [u8; 3] + 257..259 '{}': () + "#]], + ); +} + #[test] fn infer_pattern_match_or() { check_infer_with_mismatches( @@ -443,6 +488,42 @@ fn infer_adt_pattern() { ); } +#[test] +fn tuple_struct_destructured_with_self() { + check_infer( + r#" +struct Foo(usize,); +impl Foo { + fn f() { + let Self(s,) = &Foo(0,); + let Self(s,) = &mut Foo(0,); + let Self(s,) = Foo(0,); + } +} + "#, + expect![[r#" + 42..151 '{ ... }': () + 56..64 'Self(s,)': Foo + 61..62 's': &usize + 67..75 '&Foo(0,)': &Foo + 68..71 'Foo': Foo(usize) -> Foo + 68..75 'Foo(0,)': Foo + 72..73 '0': usize + 89..97 'Self(s,)': Foo + 94..95 's': &mut usize + 100..112 '&mut Foo(0,)': &mut Foo + 105..108 'Foo': Foo(usize) -> Foo + 105..112 'Foo(0,)': Foo + 109..110 '0': usize + 126..134 'Self(s,)': Foo + 131..132 's': usize + 137..140 'Foo': Foo(usize) -> Foo + 137..144 'Foo(0,)': Foo + 141..142 '0': usize + "#]], + ); +} + #[test] fn enum_variant_through_self_in_pattern() { check_infer( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 93a88ab58..23e51a9c1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -573,7 +573,6 @@ fn issue_6811() { } "#, expect![[r#" - !0..16 'let_a=...t_b=1;': () !3..5 '_a': i32 !6..7 '1': i32 !11..13 '_b': i32 @@ -1526,6 +1525,34 @@ unsafe impl Storage for InlineStorage { ); } +#[test] +fn gat_crash_3() { + // FIXME: This test currently crashes rust analyzer in a debug build but not in a + // release build (i.e. for the user). With the assumption that tests will always be run + // in debug mode, we catch the unwind and expect that it panicked. See the + // [`crate::utils::generics`] function for more information. + cov_mark::check!(ignore_gats); + std::panic::catch_unwind(|| { + check_no_mismatches( + r#" +trait Collection { + type Item; + type Member: Collection; + fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>; +} +struct ConstGen { + data: [T; N], +} +impl Collection for ConstGen { + type Item = T; + type Member = ConstGen; +} + "#, + ); + }) + .expect_err("must panic"); +} + #[test] fn cfgd_out_self_param() { cov_mark::check!(cfgd_out_self_param); @@ -1648,3 +1675,19 @@ fn main() { "#]], ); } + +#[test] +fn trailing_empty_macro() { + check_no_mismatches( + r#" +macro_rules! m2 { + ($($t:tt)*) => {$($t)*}; +} + +fn macrostmts() -> u8 { + m2! { 0 } + m2! {} +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 5b08f5521..4ea103e5d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2549,7 +2549,6 @@ impl B for Astruct {} expect![[r#" 569..573 'self': Box<[T], A> 602..634 '{ ... }': Vec - 612..628 'unimpl...ted!()': Vec 648..761 '{ ...t]); }': () 658..661 'vec': Vec 664..679 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec @@ -3070,3 +3069,17 @@ fn main() { "#, ); } + +#[test] +fn nested_break() { + check_no_mismatches( + r#" +fn func() { + let int = loop { + break 0; + break (break 0); + }; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 75802a5eb..21a863197 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -137,6 +137,31 @@ fn not_send() -> Box + 'static> { ); } +#[test] +fn into_future_trait() { + check_types( + r#" +//- minicore: future +struct Futurable; +impl core::future::IntoFuture for Futurable { + type Output = u64; + type IntoFuture = IntFuture; +} + +struct IntFuture; +impl core::future::Future for IntFuture { + type Output = u64; +} + +fn test() { + let r = Futurable; + let v = r.await; + v; +} //^ u64 +"#, + ); +} + #[test] fn infer_try() { check_types( @@ -1476,6 +1501,34 @@ fn test(x: Trait, y: &Trait) -> u64 { 165..172 'z.foo()': u64 "#]], ); + + check_infer_with_mismatches( + r#" +//- minicore: fn, coerce_unsized +struct S; +impl S { + fn foo(&self) {} +} +fn f(_: &Fn(S)) {} +fn main() { + f(&|number| number.foo()); +} + "#, + expect![[r#" + 31..35 'self': &S + 37..39 '{}': () + 47..48 '_': &dyn Fn(S) + 58..60 '{}': () + 71..105 '{ ...()); }': () + 77..78 'f': fn f(&dyn Fn(S)) + 77..102 'f(&|nu...foo())': () + 79..101 '&|numb....foo()': &|S| -> () + 80..101 '|numbe....foo()': |S| -> () + 81..87 'number': S + 89..95 'number': S + 89..101 'number.foo()': () + "#]], + ) } #[test] @@ -3780,3 +3833,123 @@ fn test() { "#, ) } + +#[test] +fn dyn_multiple_auto_traits_in_different_order() { + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} + +fn f(t: &(dyn Sync + Send)) {} +fn g(t: &(dyn Send + Sync)) { + f(t); +} + "#, + ); + + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T {} + +fn f(t: &(dyn T + Send + Sync)) {} +fn g(t: &(dyn Sync + T + Send)) { + f(t); +} + "#, + ); + + check_infer_with_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T1 {} +trait T2 {} + +fn f(t: &(dyn T1 + T2 + Send + Sync)) {} +fn g(t: &(dyn Sync + T2 + T1 + Send)) { + f(t); +} + "#, + expect![[r#" + 68..69 't': &{unknown} + 101..103 '{}': () + 109..110 't': &{unknown} + 142..155 '{ f(t); }': () + 148..149 'f': fn f(&{unknown}) + 148..152 'f(t)': () + 150..151 't': &{unknown} + "#]], + ); + + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T { + type Proj: Send + Sync; +} + +fn f(t: &(dyn T + Send + Sync)) {} +fn g(t: &(dyn Sync + T + Send)) { + f(t); +} + "#, + ); +} + +#[test] +fn dyn_multiple_projection_bounds() { + check_no_mismatches( + r#" +trait Trait { + type T; + type U; +} + +fn f(t: &dyn Trait) {} +fn g(t: &dyn Trait) { + f(t); +} + "#, + ); + + check_types( + r#" +trait Trait { + type T; +} + +fn f(t: &dyn Trait) {} + //^&{unknown} + "#, + ); +} + +#[test] +fn dyn_duplicate_auto_trait() { + check_no_mismatches( + r#" +auto trait Send {} + +fn f(t: &(dyn Send + Send)) {} +fn g(t: &(dyn Send)) { + f(t); +} + "#, + ); + + check_no_mismatches( + r#" +auto trait Send {} +trait T {} + +fn f(t: &(dyn T + Send + Send)) {} +fn g(t: &(dyn T + Send)) { + f(t); +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 83319755d..d6638db02 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -176,10 +176,19 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) { let params = db.generic_params(def); + let parent_params = &parent_generics.as_ref().unwrap().params; let has_consts = params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_))); - return if has_consts { - // XXX: treat const generic associated types as not existing to avoid crashes (#11769) + let parent_has_consts = + parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_))); + return if has_consts || parent_has_consts { + // XXX: treat const generic associated types as not existing to avoid crashes + // (#11769) + // + // Note: Also crashes when the parent has const generics (also even if the GAT + // doesn't use them), see `tests::regression::gat_crash_3` for an example. + // Avoids that by disabling GATs when the parent (i.e. `impl` block) has + // const generics (#12193). // // Chalk expects the inner associated type's parameters to come // *before*, not after the trait's generics as we've always done it. @@ -264,12 +273,8 @@ impl Generics { fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> { if param.parent == self.def { - let (idx, (_local_id, data)) = self - .params - .iter() - .enumerate() - .find(|(_, (idx, _))| *idx == param.local_id) - .unwrap(); + let (idx, (_local_id, data)) = + self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?; let parent_len = self.parent_generics().map_or(0, Generics::len); Some((parent_len + idx, data)) } else { diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 6c6c11ea4..5edc16d8b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -14,6 +14,7 @@ use crate::{MacroKind, Type}; macro_rules! diagnostics { ($($diag:ident,)*) => { + #[derive(Debug)] pub enum AnyDiagnostic {$( $diag(Box<$diag>), )*} @@ -123,6 +124,7 @@ pub struct NoSuchField { #[derive(Debug)] pub struct BreakOutsideOfLoop { pub expr: InFile>, + pub is_break: bool, } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 8f984210e..e4bb63a86 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -72,7 +72,7 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use once_cell::unsync::Lazy; use rustc_hash::FxHashSet; -use stdx::{format_to, impl_from, never}; +use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasDocComments, HasName}, AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T, @@ -511,6 +511,7 @@ impl Module { .collect() } + /// Fills `acc` with the module's diagnostics. pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { let _p = profile::span("Module::diagnostics").detail(|| { format!("{:?}", self.name(db).map_or("".into(), |name| name.to_string())) @@ -531,11 +532,21 @@ impl Module { m.diagnostics(db, acc) } } + ModuleDef::Trait(t) => { + for diag in db.trait_data_with_diagnostics(t.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } + acc.extend(decl.diagnostics(db)) + } _ => acc.extend(decl.diagnostics(db)), } } for impl_def in self.impl_defs(db) { + for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), @@ -1136,6 +1147,20 @@ impl DefWithBody { } } + fn id(&self) -> DefWithBodyId { + match self { + DefWithBody::Function(it) => it.id.into(), + DefWithBody::Static(it) => it.id.into(), + DefWithBody::Const(it) => it.id.into(), + } + } + + /// A textual representation of the HIR of this def's body for debugging purposes. + pub fn debug_hir(self, db: &dyn HirDatabase) -> String { + let body = db.body(self.id()); + body.pretty_print(db.upcast(), self.id()) + } + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { let krate = self.module(db).id.krate(); @@ -1191,11 +1216,11 @@ impl DefWithBody { let field = source_map.field_syntax(*expr); acc.push(NoSuchField { field }.into()) } - hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { + &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => { let expr = source_map - .expr_syntax(*expr) + .expr_syntax(expr) .expect("break outside of loop in synthetic syntax"); - acc.push(BreakOutsideOfLoop { expr }.into()) + acc.push(BreakOutsideOfLoop { expr, is_break }.into()) } hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { match source_map.expr_syntax(*call_expr) { @@ -1470,19 +1495,6 @@ impl Function { let def_map = db.crate_def_map(loc.krate(db).into()); def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) } - - /// A textual representation of the HIR of this function for debugging purposes. - pub fn debug_hir(self, db: &dyn HirDatabase) -> String { - let body = db.body(self.id.into()); - - let mut result = String::new(); - format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); - for (id, expr) in body.exprs.iter() { - format_to!(result, "{:?}: {:?}\n", id, expr); - } - - result - } } // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. @@ -2777,20 +2789,32 @@ impl Type { self.ty.is_unknown() } - /// Checks that particular type `ty` implements `std::future::Future`. + /// Checks that particular type `ty` implements `std::future::IntoFuture` or + /// `std::future::Future`. /// This function is used in `.await` syntax completion. - pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { - let std_future_trait = db - .lang_item(self.env.krate, SmolStr::new_inline("future_trait")) - .and_then(|it| it.as_trait()); - let std_future_trait = match std_future_trait { + pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool { + let trait_ = db + .lang_item(self.env.krate, SmolStr::new_inline("into_future")) + .and_then(|it| { + let into_future_fn = it.as_function()?; + let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?; + let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?; + Some(into_future_trait.id) + }) + .or_else(|| { + let future_trait = + db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?; + future_trait.as_trait() + }); + + let trait_ = match trait_ { Some(it) => it, None => return false, }; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait) + method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_) } /// Checks that particular type `ty` implements `std::ops::FnOnce`. diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index c84318b2f..416b6f580 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -357,6 +357,26 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_method_call(call).map(Function::from) } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.imp.resolve_await_to_poll(await_expr).map(Function::from) + } + + pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.imp.resolve_prefix_expr(prefix_expr).map(Function::from) + } + + pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.imp.resolve_index_expr(index_expr).map(Function::from) + } + + pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.imp.resolve_bin_expr(bin_expr).map(Function::from) + } + + pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.imp.resolve_try_expr(try_expr).map(Function::from) + } + pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.imp.resolve_method_call_as_callable(call) } @@ -1066,6 +1086,26 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) + } + + fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) + } + + fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) + } + + fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) + } + + fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) + } + fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 1eb51b20c..342912b67 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -25,15 +25,21 @@ use hir_def::{ Lookup, ModuleDefId, VariantId, }; use hir_expand::{ - builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile, + builtin_fn_macro::BuiltinFnLikeExpander, + hygiene::Hygiene, + mod_path::path, + name, + name::{AsName, Name}, + HirFileId, InFile, }; use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, - TyExt, TyKind, TyLoweringContext, + method_resolution::{self, lang_names_for_bin_op}, + Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -134,11 +140,19 @@ impl SourceAnalyzer { ) -> Option> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; let expanded = db.parse_or_expand(macro_file)?; - - let res = match ast::MacroCall::cast(expanded.clone()) { - Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?, - _ => InFile::new(macro_file, ast::Expr::cast(expanded)?), + let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { + match stmts.expr()? { + ast::Expr::MacroExpr(mac) => { + self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))? + } + expr => InFile::new(macro_file, expr), + } + } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) { + self.expand_expr(db, InFile::new(macro_file, call))? + } else { + InFile::new(macro_file, ast::Expr::cast(expanded)?) }; + Some(res) } @@ -255,8 +269,111 @@ impl SourceAnalyzer { ) -> Option { let expr_id = self.expr_id(db, &call.clone().into())?; let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; - let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs); - f_in_impl.or(Some(f_in_trait)) + + Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) + } + + pub(crate) fn resolve_await_to_poll( + &self, + db: &dyn HirDatabase, + await_expr: &ast::AwaitExpr, + ) -> Option { + let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone(); + + let into_future_trait = self + .resolver + .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture]) + .map(Trait::from); + + if let Some(into_future_trait) = into_future_trait { + let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone()); + if type_.impls_trait(db, into_future_trait, &[]) { + let items = into_future_trait.items(db); + let into_future_type = items.into_iter().find_map(|item| match item { + AssocItem::TypeAlias(alias) + if alias.name(db) == hir_expand::name![IntoFuture] => + { + Some(alias) + } + _ => None, + })?; + let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?; + ty = future_trait.ty; + } + } + + let poll_fn = db + .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? + .as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build(); + Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs)) + } + + pub(crate) fn resolve_prefix_expr( + &self, + db: &dyn HirDatabase, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + let lang_item_name = match prefix_expr.op_kind()? { + ast::UnaryOp::Deref => name![deref], + ast::UnaryOp::Not => name![not], + ast::UnaryOp::Neg => name![neg], + }; + let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?; + + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub(crate) fn resolve_index_expr( + &self, + db: &dyn HirDatabase, + index_expr: &ast::IndexExpr, + ) -> Option { + let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?; + let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?; + + let lang_item_name = name![index]; + + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn) + .push(base_ty.clone()) + .push(index_ty.clone()) + .build(); + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub(crate) fn resolve_bin_expr( + &self, + db: &dyn HirDatabase, + binop_expr: &ast::BinExpr, + ) -> Option { + let op = binop_expr.op_kind()?; + let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?; + let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?; + + let op_fn = lang_names_for_bin_op(op) + .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?; + let substs = + hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub(crate) fn resolve_try_expr( + &self, + db: &dyn HirDatabase, + try_expr: &ast::TryExpr, + ) -> Option { + let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?; + + let op_fn = + db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } pub(crate) fn resolve_field( @@ -281,6 +398,7 @@ impl SourceAnalyzer { let local = if field.name_ref().is_some() { None } else { + // Shorthand syntax, resolve to the local let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { Some(ValueNs::LocalBinding(pat_id)) => { @@ -666,6 +784,29 @@ impl SourceAnalyzer { let fun_data = db.function_data(func); method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name) } + + fn resolve_impl_method_or_trait_def( + &self, + db: &dyn HirDatabase, + func: FunctionId, + substs: &Substitution, + ) -> FunctionId { + self.resolve_impl_method(db, func, substs).unwrap_or(func) + } + + fn lang_trait_fn( + &self, + db: &dyn HirDatabase, + lang_trait: &Name, + method_name: &Name, + ) -> Option { + db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?) + .method_by_name(method_name) + } + + fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { + self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?) + } } fn scope_for( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs index f9b426614..8c7670e0c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs @@ -1,28 +1,20 @@ //! See [`AssistContext`]. -use std::mem; - use hir::Semantics; -use ide_db::{ - base_db::{AnchoredPathBuf, FileId, FileRange}, - SnippetCap, -}; -use ide_db::{ - label::Label, - source_change::{FileSystemEdit, SourceChange}, - RootDatabase, -}; +use ide_db::base_db::{FileId, FileRange}; +use ide_db::{label::Label, RootDatabase}; use syntax::{ algo::{self, find_node_at_offset, find_node_at_range}, - AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, - SyntaxToken, TextRange, TextSize, TokenAtOffset, + AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange, + TextSize, TokenAtOffset, }; -use text_edit::{TextEdit, TextEditBuilder}; use crate::{ assist_config::AssistConfig, Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, }; +pub(crate) use ide_db::source_change::{SourceChangeBuilder, TreeMutator}; + /// `AssistContext` allows to apply an assist or check if it could be applied. /// /// Assists use a somewhat over-engineered approach, given the current needs. @@ -163,7 +155,7 @@ impl Assists { id: AssistId, label: impl Into, target: TextRange, - f: impl FnOnce(&mut AssistBuilder), + f: impl FnOnce(&mut SourceChangeBuilder), ) -> Option<()> { let mut f = Some(f); self.add_impl(None, id, label.into(), target, &mut |it| f.take().unwrap()(it)) @@ -175,7 +167,7 @@ impl Assists { id: AssistId, label: impl Into, target: TextRange, - f: impl FnOnce(&mut AssistBuilder), + f: impl FnOnce(&mut SourceChangeBuilder), ) -> Option<()> { let mut f = Some(f); self.add_impl(Some(group), id, label.into(), target, &mut |it| f.take().unwrap()(it)) @@ -187,7 +179,7 @@ impl Assists { id: AssistId, label: String, target: TextRange, - f: &mut dyn FnMut(&mut AssistBuilder), + f: &mut dyn FnMut(&mut SourceChangeBuilder), ) -> Option<()> { if !self.is_allowed(&id) { return None; @@ -195,7 +187,7 @@ impl Assists { let mut trigger_signature_help = false; let source_change = if self.resolve.should_resolve(&id) { - let mut builder = AssistBuilder::new(self.file); + let mut builder = SourceChangeBuilder::new(self.file); f(&mut builder); trigger_signature_help = builder.trigger_signature_help; Some(builder.finish()) @@ -216,132 +208,3 @@ impl Assists { } } } - -pub(crate) struct AssistBuilder { - edit: TextEditBuilder, - file_id: FileId, - source_change: SourceChange, - trigger_signature_help: bool, - - /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. - mutated_tree: Option, -} - -pub(crate) struct TreeMutator { - immutable: SyntaxNode, - mutable_clone: SyntaxNode, -} - -impl TreeMutator { - pub(crate) fn new(immutable: &SyntaxNode) -> TreeMutator { - let immutable = immutable.ancestors().last().unwrap(); - let mutable_clone = immutable.clone_for_update(); - TreeMutator { immutable, mutable_clone } - } - - pub(crate) fn make_mut(&self, node: &N) -> N { - N::cast(self.make_syntax_mut(node.syntax())).unwrap() - } - - pub(crate) fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { - let ptr = SyntaxNodePtr::new(node); - ptr.to_node(&self.mutable_clone) - } -} - -impl AssistBuilder { - pub(crate) fn new(file_id: FileId) -> AssistBuilder { - AssistBuilder { - edit: TextEdit::builder(), - file_id, - source_change: SourceChange::default(), - trigger_signature_help: false, - mutated_tree: None, - } - } - - pub(crate) fn edit_file(&mut self, file_id: FileId) { - self.commit(); - self.file_id = file_id; - } - - fn commit(&mut self) { - if let Some(tm) = self.mutated_tree.take() { - algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) - } - - let edit = mem::take(&mut self.edit).finish(); - if !edit.is_empty() { - self.source_change.insert_source_edit(self.file_id, edit); - } - } - - pub(crate) fn make_mut(&mut self, node: N) -> N { - self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node) - } - /// Returns a copy of the `node`, suitable for mutation. - /// - /// Syntax trees in rust-analyzer are typically immutable, and mutating - /// operations panic at runtime. However, it is possible to make a copy of - /// the tree and mutate the copy freely. Mutation is based on interior - /// mutability, and different nodes in the same tree see the same mutations. - /// - /// The typical pattern for an assist is to find specific nodes in the read - /// phase, and then get their mutable couterparts using `make_mut` in the - /// mutable state. - pub(crate) fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode { - self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) - } - - /// Remove specified `range` of text. - pub(crate) fn delete(&mut self, range: TextRange) { - self.edit.delete(range) - } - /// Append specified `text` at the given `offset` - pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into) { - self.edit.insert(offset, text.into()) - } - /// Append specified `snippet` at the given `offset` - pub(crate) fn insert_snippet( - &mut self, - _cap: SnippetCap, - offset: TextSize, - snippet: impl Into, - ) { - self.source_change.is_snippet = true; - self.insert(offset, snippet); - } - /// Replaces specified `range` of text with a given string. - pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into) { - self.edit.replace(range, replace_with.into()) - } - /// Replaces specified `range` of text with a given `snippet`. - pub(crate) fn replace_snippet( - &mut self, - _cap: SnippetCap, - range: TextRange, - snippet: impl Into, - ) { - self.source_change.is_snippet = true; - self.replace(range, snippet); - } - pub(crate) fn replace_ast(&mut self, old: N, new: N) { - algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) - } - pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into) { - let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; - self.source_change.push_file_system_edit(file_system_edit); - } - pub(crate) fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) { - let file_system_edit = FileSystemEdit::MoveFile { src, dst }; - self.source_change.push_file_system_edit(file_system_edit); - } - pub(crate) fn trigger_signature_help(&mut self) { - self.trigger_signature_help = true; - } - - fn finish(mut self) -> SourceChange { - self.commit(); - mem::take(&mut self.source_change) - } -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index c808c010c..62cf5ab4f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -944,7 +944,7 @@ foo!(); struct Foo(usize); impl FooB for Foo { - $0fn foo< 'lt>(& 'lt self){} + $0fn foo<'lt>(&'lt self){} } "#, ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index b16f6fe03..1a7919a5a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -5,6 +5,7 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics}; use ide_db::RootDatabase; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; +use syntax::ast::edit_in_place::Removable; use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; use crate::{ diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 4ab8e93a2..d8f522708 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -5,7 +5,7 @@ use syntax::{ match_ast, SyntaxNode, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; // Assist: convert_tuple_struct_to_named_struct // @@ -80,7 +80,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct( fn edit_struct_def( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: &Either, tuple_fields: ast::TupleFieldList, names: Vec, @@ -122,7 +122,7 @@ fn edit_struct_def( fn edit_struct_references( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: Either, names: &[ast::Name], ) { @@ -132,7 +132,7 @@ fn edit_struct_references( }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { + let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> { match_ast! { match node { ast::TupleStructPat(tuple_struct_pat) => { @@ -203,7 +203,7 @@ fn edit_struct_references( fn edit_field_references( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, fields: impl Iterator, names: &[ast::Name], ) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs new file mode 100644 index 000000000..54a7f480a --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -0,0 +1,294 @@ +use syntax::ast::{self, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: convert_two_arm_bool_match_to_matches_macro +// +// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation. +// +// ``` +// fn main() { +// match scrutinee$0 { +// Some(val) if val.cond() => true, +// _ => false, +// } +// } +// ``` +// -> +// ``` +// fn main() { +// matches!(scrutinee, Some(val) if val.cond()) +// } +// ``` +pub(crate) fn convert_two_arm_bool_match_to_matches_macro( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let match_expr = ctx.find_node_at_offset::()?; + let match_arm_list = match_expr.match_arm_list()?; + let mut arms = match_arm_list.arms(); + let first_arm = arms.next()?; + let second_arm = arms.next()?; + if arms.next().is_some() { + cov_mark::hit!(non_two_arm_match); + return None; + } + let first_arm_expr = first_arm.expr(); + let second_arm_expr = second_arm.expr(); + + let invert_matches = if is_bool_literal_expr(&first_arm_expr, true) + && is_bool_literal_expr(&second_arm_expr, false) + { + false + } else if is_bool_literal_expr(&first_arm_expr, false) + && is_bool_literal_expr(&second_arm_expr, true) + { + true + } else { + cov_mark::hit!(non_invert_bool_literal_arms); + return None; + }; + + let target_range = ctx.sema.original_range(match_expr.syntax()).range; + let expr = match_expr.expr()?; + + acc.add( + AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite), + "Convert to matches!", + target_range, + |builder| { + let mut arm_str = String::new(); + if let Some(ref pat) = first_arm.pat() { + arm_str += &pat.to_string(); + } + if let Some(ref guard) = first_arm.guard() { + arm_str += &format!(" {}", &guard.to_string()); + } + if invert_matches { + builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str)); + } else { + builder.replace(target_range, format!("matches!({}, {})", expr, arm_str)); + } + }, + ) +} + +fn is_bool_literal_expr(expr: &Option, expect_bool: bool) -> bool { + if let Some(ast::Expr::Literal(lit)) = expr { + if let ast::LiteralKind::Bool(b) = lit.kind() { + return b == expect_bool; + } + } + + return false; +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; + + use super::convert_two_arm_bool_match_to_matches_macro; + + #[test] + fn not_applicable_outside_of_range_left() { + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + $0 match a { + Some(_val) => true, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_non_two_arm_match() { + cov_mark::check!(non_two_arm_match); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(3) => true, + Some(4) => true, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_non_bool_literal_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => val == 3, + _ => false + } +} + "#, + ); + } + #[test] + fn not_applicable_both_false_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => false, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_both_true_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => true, + _ => true + } +} + "#, + ); + } + + #[test] + fn convert_simple_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(_val) => true, + _ => false + } +} +"#, + r#" +fn foo(a: Option) -> bool { + matches!(a, Some(_val)) +} +"#, + ); + } + + #[test] + fn convert_simple_invert_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(_val) => false, + _ => true + } +} +"#, + r#" +fn foo(a: Option) -> bool { + !matches!(a, Some(_val)) +} +"#, + ); + } + + #[test] + fn convert_with_guard_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) if val > 3 => true, + _ => false + } +} +"#, + r#" +fn foo(a: Option) -> bool { + matches!(a, Some(val) if val > 3) +} +"#, + ); + } + + #[test] + fn convert_enum_match_cases() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +enum X { A, B } + +fn foo(a: X) -> bool { + match a$0 { + X::A => true, + _ => false + } +} +"#, + r#" +enum X { A, B } + +fn foo(a: X) -> bool { + matches!(a, X::A) +} +"#, + ); + } + + #[test] + fn convert_target_simple() { + check_assist_target( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => true, + _ => false + } +} +"#, + r#"match a { + Some(val) => true, + _ => false + }"#, + ); + } + + #[test] + fn convert_target_complex() { + check_assist_target( + convert_two_arm_bool_match_to_matches_macro, + r#" +enum E { X, Y } + +fn main() { + match E::X$0 { + E::X => true, + _ => false, + } +} +"#, + "match E::X { + E::X => true, + _ => false, + }", + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index c1f57532b..dc581ff3b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -8,7 +8,7 @@ use syntax::{ TextRange, }; -use crate::assist_context::{AssistBuilder, AssistContext, Assists}; +use crate::assist_context::{AssistContext, Assists, SourceChangeBuilder}; // Assist: destructure_tuple_binding // @@ -151,7 +151,7 @@ struct TupleData { } fn edit_tuple_assignment( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, data: &TupleData, in_sub_pattern: bool, ) { @@ -195,7 +195,7 @@ fn edit_tuple_assignment( fn edit_tuple_usages( data: &TupleData, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, ctx: &AssistContext<'_>, in_sub_pattern: bool, ) { @@ -211,7 +211,7 @@ fn edit_tuple_usages( } fn edit_tuple_usage( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, usage: &FileReference, data: &TupleData, in_sub_pattern: bool, @@ -239,7 +239,7 @@ fn edit_tuple_usage( fn edit_tuple_field_usage( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, data: &TupleData, index: TupleIndex, ) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index b3c4d306a..897980c66 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -29,7 +29,7 @@ use super::remove_unused_param::range_to_remove; // Assist: extract_module // -// Extracts a selected region as seperate module. All the references, visibility and imports are +// Extracts a selected region as separate module. All the references, visibility and imports are // resolved. // // ``` @@ -105,7 +105,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti // //- Thirdly, resolving all the imports this includes removing paths from imports // outside the module, shifting/cloning them inside new module, or shifting the imports, or making - // new import statemnts + // new import statements //We are getting item usages and record_fields together, record_fields //for change_visibility and usages for first point mentioned above in the process @@ -661,7 +661,7 @@ fn check_intersection_and_push( import_path: TextRange, ) { if import_paths_to_be_removed.len() > 0 { - // Text ranges recieved here for imports are extended to the + // Text ranges received here for imports are extended to the // next/previous comma which can cause intersections among them // and later deletion of these can cause panics similar // to reported in #11766. So to mitigate it, we diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index a93648f2d..ddc2052e7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -20,7 +20,7 @@ use syntax::{ SyntaxNode, T, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; // Assist: extract_struct_from_enum_variant // @@ -101,21 +101,22 @@ pub(crate) fn extract_struct_from_enum_variant( }); } - let indent = enum_ast.indent_level(); let generic_params = enum_ast .generic_param_list() .and_then(|known_generics| extract_generic_params(&known_generics, &field_list)); let generics = generic_params.as_ref().map(|generics| generics.clone_for_update()); let def = create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast); + + let enum_ast = variant.parent_enum(); + let indent = enum_ast.indent_level(); def.reindent_to(indent); - let start_offset = &variant.parent_enum().syntax().clone(); - ted::insert_all_raw( - ted::Position::before(start_offset), + ted::insert_all( + ted::Position::before(enum_ast.syntax()), vec![ def.syntax().clone().into(), - make::tokens::whitespace(&format!("\n\n{}", indent)).into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), ], ); @@ -227,7 +228,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b } fn create_struct_def( - variant_name: ast::Name, + name: ast::Name, variant: &ast::Variant, field_list: &Either, generics: Option, @@ -269,43 +270,27 @@ fn create_struct_def( field_list.into() } }; - field_list.reindent_to(IndentLevel::single()); - let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update(); - - // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation - let attrs_and_docs = |node: &SyntaxNode| { - let mut select_next_ws = false; - node.children_with_tokens().filter(move |child| { - let accept = match child.kind() { - ATTR | COMMENT => { - select_next_ws = true; - return true; - } - WHITESPACE if select_next_ws => true, - _ => false, - }; - select_next_ws = false; - - accept - }) - }; + let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); - // copy attributes & comments from variant - let variant_attrs = attrs_and_docs(variant.syntax()) - .map(|tok| match tok.kind() { - WHITESPACE => make::tokens::single_newline().into(), - _ => tok, - }) - .collect(); - ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs); + // take comments from variant + ted::insert_all( + ted::Position::first_child_of(strukt.syntax()), + take_all_comments(variant.syntax()), + ); // copy attributes from enum ted::insert_all( ted::Position::first_child_of(strukt.syntax()), - enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(), + enum_ + .attrs() + .flat_map(|it| { + vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()] + }) + .collect(), ); + strukt } @@ -346,16 +331,48 @@ fn update_variant(variant: &ast::Variant, generics: Option Vec { + let mut remove_next_ws = false; + node.children_with_tokens() + .filter_map(move |child| match child.kind() { + COMMENT => { + remove_next_ws = true; + child.detach(); + Some(child) + } + WHITESPACE if remove_next_ws => { + remove_next_ws = false; + child.detach(); + Some(make::tokens::single_newline().into()) + } + _ => { + remove_next_ws = false; + None + } + }) + .collect() +} + fn apply_references( insert_use_cfg: InsertUseConfig, segment: ast::PathSegment, @@ -374,7 +391,7 @@ fn apply_references( fn process_references( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, visited_modules: &mut FxHashSet, enum_module_def: &ModuleDef, variant_hir_name: &Name, @@ -480,10 +497,14 @@ enum En { Var(Var) }"#, fn test_extract_struct_carries_over_attributes() { check_assist( extract_struct_from_enum_variant, - r#"#[derive(Debug)] + r#" +#[derive(Debug)] #[derive(Clone)] enum Enum { Variant{ field: u32$0 } }"#, - r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 } + r#" +#[derive(Debug)] +#[derive(Clone)] +struct Variant{ field: u32 } #[derive(Debug)] #[derive(Clone)] @@ -614,7 +635,7 @@ enum A { One(One) }"#, } #[test] - fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() { + fn test_extract_struct_move_struct_variant_comments() { check_assist( extract_struct_from_enum_variant, r#" @@ -631,19 +652,19 @@ enum A { /* comment */ // other /// comment -#[attr] struct One{ a: u32 } enum A { + #[attr] One(One) }"#, ); } #[test] - fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() { + fn test_extract_struct_move_tuple_variant_comments() { check_assist( extract_struct_from_enum_variant, r#" @@ -658,10 +679,10 @@ enum A { /* comment */ // other /// comment -#[attr] struct One(u32, u32); enum A { + #[attr] One(One) }"#, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index af584cdb4..03aa8601d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -171,6 +171,25 @@ fn collect_used_generics<'gp>( ast::Type::RefType(ref_) => generics.extend( ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), + ast::Type::ArrayType(ar) => { + if let Some(expr) = ar.expr() { + if let ast::Expr::PathExpr(p) = expr { + if let Some(path) = p.path() { + if let Some(name_ref) = path.as_single_name_ref() { + if let Some(param) = known_generics.iter().find(|gp| { + if let ast::GenericParam::ConstParam(cp) = gp { + cp.name().map_or(false, |n| n.text() == name_ref.text()) + } else { + false + } + }) { + generics.push(param); + } + } + } + } + } + } _ => (), }); // stable resort to lifetime, type, const @@ -357,4 +376,29 @@ impl<'outer, Outer, const OUTER: usize> () { "#, ); } + + #[test] + fn issue_11197() { + check_assist( + extract_type_alias, + r#" +struct Foo +where + [T; N]: Sized, +{ + arr: $0[T; N]$0, +} + "#, + r#" +type $0Type = [T; N]; + +struct Foo +where + [T; N]: Sized, +{ + arr: Type, +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index b9637ee8d..b48463512 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -8,7 +8,7 @@ use syntax::{ }; use crate::{ - assist_context::{AssistBuilder, AssistContext, Assists}, + assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::generate_trait_impl_text, AssistId, AssistKind, }; @@ -120,7 +120,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() } fn generate_edit( - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: ast::Struct, field_type_syntax: &SyntaxNode, field_name: impl Display, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs index 4461fbd5a..35cd42908 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,8 +1,8 @@ -use hir::{HasSource, InFile}; +use hir::{HasSource, HirDisplay, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, edit::IndentLevel}, - AstNode, TextSize, + ast::{self, make, HasArgList}, + match_ast, AstNode, SyntaxNode, }; use crate::assist_context::{AssistContext, Assists}; @@ -32,8 +32,8 @@ use crate::assist_context::{AssistContext, Assists}; // } // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; - let path = path_expr.path()?; + let path: ast::Path = ctx.find_node_at_offset()?; + let parent = path_parent(&path)?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -50,26 +50,71 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) ctx.sema.resolve_path(&path.qualifier()?) { let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref); + return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent); } None } +#[derive(Debug)] +enum PathParent { + PathExpr(ast::PathExpr), + RecordExpr(ast::RecordExpr), + PathPat(ast::PathPat), + UseTree(ast::UseTree), +} + +impl PathParent { + fn syntax(&self) -> &SyntaxNode { + match self { + PathParent::PathExpr(it) => it.syntax(), + PathParent::RecordExpr(it) => it.syntax(), + PathParent::PathPat(it) => it.syntax(), + PathParent::UseTree(it) => it.syntax(), + } + } + + fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option { + let scope = ctx.sema.scope(self.syntax())?; + + match self { + PathParent::PathExpr(it) => { + if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) { + make_tuple_field_list(call_expr, ctx, &scope) + } else { + None + } + } + PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), + PathParent::UseTree(_) | PathParent::PathPat(_) => None, + } + } +} + +fn path_parent(path: &ast::Path) -> Option { + let parent = path.syntax().parent()?; + + match_ast! { + match parent { + ast::PathExpr(it) => Some(PathParent::PathExpr(it)), + ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::PathPat(it) => Some(PathParent::PathPat(it)), + ast::UseTree(it) => Some(PathParent::UseTree(it)), + _ => None + } + } +} + fn add_variant_to_accumulator( acc: &mut Assists, ctx: &AssistContext<'_>, target: syntax::TextRange, adt: hir::Enum, name_ref: &ast::NameRef, + parent: PathParent, ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; - let enum_indent = IndentLevel::from_node(&enum_node.syntax()); - - let variant_list = enum_node.variant_list()?; - let offset = variant_list.syntax().text_range().end() - TextSize::of('}'); - let empty_enum = variant_list.variants().next().is_none(); acc.add( AssistId("generate_enum_variant", AssistKind::Generate), @@ -77,18 +122,80 @@ fn add_variant_to_accumulator( target, |builder| { builder.edit_file(file_id.original_file(db)); - let text = format!( - "{maybe_newline}{indent_1}{name},\n{enum_indent}", - maybe_newline = if empty_enum { "\n" } else { "" }, - indent_1 = IndentLevel(1), - name = name_ref, - enum_indent = enum_indent - ); - builder.insert(offset, text) + let node = builder.make_mut(enum_node); + let variant = make_variant(ctx, name_ref, parent); + node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) } +fn make_variant( + ctx: &AssistContext<'_>, + name_ref: &ast::NameRef, + parent: PathParent, +) -> ast::Variant { + let field_list = parent.make_field_list(ctx); + make::variant(make::name(&name_ref.text()), field_list) +} + +fn make_record_field_list( + record: &ast::RecordExpr, + ctx: &AssistContext<'_>, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let fields = record.record_expr_field_list()?.fields(); + let record_fields = fields.map(|field| { + let name = name_from_field(&field); + + let ty = field + .expr() + .and_then(|it| expr_ty(ctx, it, scope)) + .unwrap_or_else(make::ty_placeholder); + + make::record_field(None, name, ty) + }); + Some(make::record_field_list(record_fields).into()) +} + +fn name_from_field(field: &ast::RecordExprField) -> ast::Name { + let text = match field.name_ref() { + Some(it) => it.to_string(), + None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()), + }; + make::name(&text) +} + +fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option { + let path = match field.expr()? { + ast::Expr::PathExpr(path_expr) => path_expr.path(), + _ => None, + }?; + Some(path.as_single_name_ref()?.to_string()) +} + +fn make_tuple_field_list( + call_expr: ast::CallExpr, + ctx: &AssistContext<'_>, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let args = call_expr.arg_list()?.args(); + let tuple_fields = args.map(|arg| { + let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder); + make::tuple_field(None, ty) + }); + Some(make::tuple_field_list(tuple_fields).into()) +} + +fn expr_ty( + ctx: &AssistContext<'_>, + arg: ast::Expr, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?; + let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?; + Some(make::ty(&text)) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -221,6 +328,236 @@ mod m { fn main() { m::Foo::Baz } +", + ) + } + + #[test] + fn associated_single_element_tuple() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(true) +} +", + r" +enum Foo { + Bar(bool), +} +fn main() { + Foo::Bar(true) +} +", + ) + } + + #[test] + fn associated_single_element_tuple_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(x) +} +", + r" +enum Foo { + Bar(_), +} +fn main() { + Foo::Bar(x) +} +", + ) + } + + #[test] + fn associated_multi_element_tuple() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::Bar$0(true, x, Struct {}) +} +", + r" +struct Struct {} +enum Foo { + Bar(bool, _, Struct), +} +fn main() { + Foo::Bar(true, x, Struct {}) +} +", + ) + } + + #[test] + fn associated_record() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: true } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + Foo::Bar { x: true } +} +", + ) + } + + #[test] + fn associated_record_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: y } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x: y } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + let x = true; + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + let x = true; + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_multiple_fields() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::$0Bar { x, y: x, s: Struct {} } +} +", + r" +struct Struct {} +enum Foo { + Bar { x: _, y: _, s: Struct }, +} +fn main() { + Foo::Bar { x, y: x, s: Struct {} } +} +", + ) + } + + #[test] + fn use_tree() { + check_assist( + generate_enum_variant, + r" +//- /main.rs +mod foo; +use foo::Foo::Bar$0; + +//- /foo.rs +enum Foo {} +", + r" +enum Foo { + Bar, +} +", + ) + } + + #[test] + fn not_applicable_for_path_type() { + check_assist_not_applicable( + generate_enum_variant, + r" +enum Foo {} +impl Foo::Bar$0 {} +", + ) + } + + #[test] + fn path_pat() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn foo(x: Foo) { + match x { + Foo::Bar$0 => + } +} +", + r" +enum Foo { + Bar, +} +fn foo(x: Foo) { + match x { + Foo::Bar => + } +} ", ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index d564a0540..e26c76da1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -61,56 +61,72 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } let fn_name = &*name_ref.text(); - let target_module; - let mut adt_name = None; + let TargetInfo { target_module, adt_name, target, file, insert_offset } = + fn_target_info(ctx, path, &call, fn_name)?; + let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; + let text_range = call.syntax().text_range(); + let label = format!("Generate {} function", function_builder.fn_name); + add_func_to_accumulator( + acc, + ctx, + text_range, + function_builder, + insert_offset, + file, + adt_name, + label, + ) +} + +struct TargetInfo { + target_module: Option, + adt_name: Option, + target: GeneratedFunctionTarget, + file: FileId, + insert_offset: TextSize, +} - let (target, file, insert_offset) = match path.qualifier() { +impl TargetInfo { + fn new( + target_module: Option, + adt_name: Option, + target: GeneratedFunctionTarget, + file: FileId, + insert_offset: TextSize, + ) -> Self { + Self { target_module, adt_name, target, file, insert_offset } + } +} + +fn fn_target_info( + ctx: &AssistContext<'_>, + path: ast::Path, + call: &CallExpr, + fn_name: &str, +) -> Option { + match path.qualifier() { Some(qualifier) => match ctx.sema.resolve_path(&qualifier) { Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => { - target_module = Some(module); - get_fn_target(ctx, &target_module, call.clone())? + get_fn_target_info(ctx, &Some(module), call.clone()) } Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => { if let hir::Adt::Enum(_) = adt { // Don't suggest generating function if the name starts with an uppercase letter - if name_ref.text().starts_with(char::is_uppercase) { + if fn_name.starts_with(char::is_uppercase) { return None; } } - let current_module = ctx.sema.scope(call.syntax())?.module(); - let module = adt.module(ctx.sema.db); - target_module = if current_module == module { None } else { Some(module) }; - if current_module.krate() != module.krate() { - return None; - } - let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; - let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; - adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - (target, file, insert_offset) + assoc_fn_target_info(ctx, call, adt, fn_name) } - _ => { - return None; + Some(hir::PathResolution::SelfType(impl_)) => { + let adt = impl_.self_ty(ctx.db()).as_adt()?; + assoc_fn_target_info(ctx, call, adt, fn_name) } + _ => None, }, - _ => { - target_module = None; - get_fn_target(ctx, &target_module, call.clone())? - } - }; - let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; - let text_range = call.syntax().text_range(); - let label = format!("Generate {} function", function_builder.fn_name); - add_func_to_accumulator( - acc, - ctx, - text_range, - function_builder, - insert_offset, - file, - adt_name, - label, - ) + _ => get_fn_target_info(ctx, &None, call.clone()), + } } fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -366,6 +382,15 @@ fn make_return_type( (ret_type, should_focus_return_type) } +fn get_fn_target_info( + ctx: &AssistContext<'_>, + target_module: &Option, + call: CallExpr, +) -> Option { + let (target, file, insert_offset) = get_fn_target(ctx, target_module, call)?; + Some(TargetInfo::new(*target_module, None, target, file, insert_offset)) +} + fn get_fn_target( ctx: &AssistContext<'_>, target_module: &Option, @@ -399,6 +424,24 @@ fn get_method_target( Some((target.clone(), get_insert_offset(&target))) } +fn assoc_fn_target_info( + ctx: &AssistContext<'_>, + call: &CallExpr, + adt: hir::Adt, + fn_name: &str, +) -> Option { + let current_module = ctx.sema.scope(call.syntax())?.module(); + let module = adt.module(ctx.sema.db); + let target_module = if current_module == module { None } else { Some(module) }; + if current_module.krate() != module.krate() { + return None; + } + let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; + let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; + let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; + Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset)) +} + fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize { match &target { GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(), @@ -1633,6 +1676,33 @@ fn bar() ${0:-> _} { ) } + #[test] + fn create_static_method_within_an_impl_with_self_syntax() { + check_assist( + generate_function, + r" +struct S; +impl S { + fn foo(&self) { + Self::bar$0(); + } +} +", + r" +struct S; +impl S { + fn foo(&self) { + Self::bar(); + } + + fn bar() ${0:-> _} { + todo!() + } +} +", + ) + } + #[test] fn no_panic_on_invalid_global_path() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 80d3b9255..9f51cdaf8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -7,13 +7,14 @@ use ide_db::{ imports::insert_use::remove_path_if_in_use_stmt, path_transform::PathTransform, search::{FileReference, SearchScope}, + source_change::SourceChangeBuilder, syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref}, RootDatabase, }; use itertools::{izip, Itertools}; use syntax::{ ast::{self, edit_in_place::Indent, HasArgList, PathExpr}, - ted, AstNode, + ted, AstNode, NodeOrToken, SyntaxKind, }; use crate::{ @@ -100,18 +101,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> builder.edit_file(file_id); let count = refs.len(); // The collects are required as we are otherwise iterating while mutating 🙅â€â™€ï¸ðŸ™…â€â™‚ï¸ - let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs - .into_iter() - .filter_map(|file_ref| match file_ref.name { - ast::NameLike::NameRef(name_ref) => Some(name_ref), - _ => None, - }) - .partition_map(|name_ref| { - match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) { - Some(use_tree) => Either::Right(builder.make_mut(use_tree)), - None => Either::Left(name_ref), - } - }); + let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some); let call_infos: Vec<_> = name_refs .into_iter() .filter_map(CallInfo::from_name_ref) @@ -130,11 +120,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> .count(); if replaced + name_refs_use.len() == count { // we replaced all usages in this file, so we can remove the imports - name_refs_use.into_iter().for_each(|use_tree| { - if let Some(path) = use_tree.path() { - remove_path_if_in_use_stmt(&path); - } - }) + name_refs_use.iter().for_each(remove_path_if_in_use_stmt); } else { remove_def = false; } @@ -153,6 +139,23 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> ) } +pub(super) fn split_refs_and_uses( + builder: &mut SourceChangeBuilder, + iter: impl IntoIterator, + mut map_ref: impl FnMut(ast::NameRef) -> Option, +) -> (Vec, Vec) { + iter.into_iter() + .filter_map(|file_ref| match file_ref.name { + ast::NameLike::NameRef(name_ref) => Some(name_ref), + _ => None, + }) + .filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) { + Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right), + None => map_ref(name_ref).map(Either::Left), + }) + .partition_map(|either| either) +} + // Assist: inline_call // // Inlines a function or method body creating a `let` statement per parameter unless the parameter @@ -311,6 +314,17 @@ fn inline( } else { fn_body.clone_for_update() }; + if let Some(imp) = body.syntax().ancestors().find_map(ast::Impl::cast) { + if !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) { + if let Some(t) = imp.self_ty() { + body.syntax() + .descendants_with_tokens() + .filter_map(NodeOrToken::into_token) + .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW) + .for_each(|tok| ted::replace(tok, t.syntax())); + } + } + } let usages_for_locals = |local| { Definition::Local(local) .usages(sema) @@ -345,6 +359,7 @@ fn inline( } }) .collect(); + if function.self_param(sema.db).is_some() { let this = || make::name_ref("this").syntax().clone_for_update(); if let Some(self_local) = params[0].2.as_local(sema.db) { @@ -1188,6 +1203,56 @@ fn bar() -> u32 { x } } +"#, + ) + } + + #[test] + fn inline_call_with_self_type() { + check_assist( + inline_call, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(114514) } +} +fn main() { + A::f$0(); +} +"#, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(114514) } +} +fn main() { + A(114514); +} +"#, + ) + } + + #[test] + fn inline_call_with_self_type_but_within_same_impl() { + check_assist( + inline_call, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(1919810) } + fn main() { + Self::f$0(); + } +} +"#, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(1919810) } + fn main() { + Self(1919810); + } +} "#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index 054663a06..353d467ed 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -1,9 +1,12 @@ // Some ideas for future improvements: // - Support replacing aliases which are used in expressions, e.g. `A::new()`. -// - "inline_alias_to_users" assist #10881. // - Remove unused aliases if there are no longer any users, see inline_call.rs. use hir::{HasSource, PathResolution}; +use ide_db::{ + defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt, + search::FileReference, +}; use itertools::Itertools; use std::collections::HashMap; use syntax::{ @@ -16,6 +19,89 @@ use crate::{ AssistId, AssistKind, }; +use super::inline_call::split_refs_and_uses; + +// Assist: inline_type_alias_uses +// +// Inline a type alias into all of its uses where possible. +// +// ``` +// type $0A = i32; +// fn id(x: A) -> A { +// x +// }; +// fn foo() { +// let _: A = 3; +// } +// ``` +// -> +// ``` +// +// fn id(x: i32) -> i32 { +// x +// }; +// fn foo() { +// let _: i32 = 3; +// } +pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let name = ctx.find_node_at_offset::()?; + let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?; + + let hir_alias = ctx.sema.to_def(&ast_alias)?; + let concrete_type = ast_alias.ty()?; + + let usages = Definition::TypeAlias(hir_alias).usages(&ctx.sema); + if !usages.at_least_one() { + return None; + } + + // until this is ok + + acc.add( + AssistId("inline_type_alias_uses", AssistKind::RefactorInline), + "Inline type alias into all uses", + name.syntax().text_range(), + |builder| { + let usages = usages.all(); + let mut definition_deleted = false; + + let mut inline_refs_for_file = |file_id, refs: Vec| { + builder.edit_file(file_id); + + let (path_types, path_type_uses) = + split_refs_and_uses(builder, refs, |path_type| { + path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) + }); + + path_type_uses + .iter() + .flat_map(ast_to_remove_for_path_in_use_stmt) + .for_each(|x| builder.delete(x.syntax().text_range())); + for (target, replacement) in path_types.into_iter().filter_map(|path_type| { + let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); + let target = path_type.syntax().text_range(); + Some((target, replacement)) + }) { + builder.replace(target, replacement); + } + + if file_id == ctx.file_id() { + builder.delete(ast_alias.syntax().text_range()); + definition_deleted = true; + } + }; + + for (file_id, refs) in usages.into_iter() { + inline_refs_for_file(file_id, refs); + } + if !definition_deleted { + builder.edit_file(ctx.file_id()); + builder.delete(ast_alias.syntax().text_range()); + } + }, + ) +} + // Assist: inline_type_alias // // Replace a type alias with its concrete type. @@ -36,11 +122,6 @@ use crate::{ // } // ``` pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - enum Replacement { - Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap }, - Plain, - } - let alias_instance = ctx.find_node_at_offset::()?; let concrete_type; let replacement; @@ -59,23 +140,7 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O _ => { let alias = get_type_alias(&ctx, &alias_instance)?; concrete_type = alias.ty()?; - - replacement = if let Some(alias_generics) = alias.generic_param_list() { - if alias_generics.generic_params().next().is_none() { - cov_mark::hit!(no_generics_params); - return None; - } - - let instance_args = - alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast); - - Replacement::Generic { - lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?, - const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?, - } - } else { - Replacement::Plain - }; + replacement = inline(&alias, &alias_instance)?; } } @@ -85,19 +150,45 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O AssistId("inline_type_alias", AssistKind::RefactorInline), "Inline type alias", target, - |builder| { - let replacement_text = match replacement { - Replacement::Generic { lifetime_map, const_and_type_map } => { - create_replacement(&lifetime_map, &const_and_type_map, &concrete_type) - } - Replacement::Plain => concrete_type.to_string(), - }; - - builder.replace(target, replacement_text); - }, + |builder| builder.replace(target, replacement.to_text(&concrete_type)), ) } +impl Replacement { + fn to_text(&self, concrete_type: &ast::Type) -> String { + match self { + Replacement::Generic { lifetime_map, const_and_type_map } => { + create_replacement(&lifetime_map, &const_and_type_map, &concrete_type) + } + Replacement::Plain => concrete_type.to_string(), + } + } +} + +enum Replacement { + Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap }, + Plain, +} + +fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option { + let repl = if let Some(alias_generics) = alias_def.generic_param_list() { + if alias_generics.generic_params().next().is_none() { + cov_mark::hit!(no_generics_params); + return None; + } + let instance_args = + alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast); + + Replacement::Generic { + lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?, + const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?, + } + } else { + Replacement::Plain + }; + Some(repl) +} + struct LifetimeMap(HashMap); impl LifetimeMap { @@ -835,4 +926,95 @@ trait Tr { "#, ); } + + mod inline_type_alias_uses { + use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist}; + + #[test] + fn inline_uses() { + check_assist( + inline_type_alias_uses, + r#" +type $0A = u32; + +fn foo() { + let _: A = 3; + let _: A = 4; +} +"#, + r#" + + +fn foo() { + let _: u32 = 3; + let _: u32 = 4; +} +"#, + ); + } + + #[test] + fn inline_uses_across_files() { + check_assist( + inline_type_alias_uses, + r#" +//- /lib.rs +mod foo; +type $0T = Vec; +fn f() -> T<&str> { + vec!["hello"] +} + +//- /foo.rs +use super::T; +fn foo() { + let _: T = Vec::new(); +} +"#, + r#" +//- /lib.rs +mod foo; + +fn f() -> Vec<&str> { + vec!["hello"] +} + +//- /foo.rs + +fn foo() { + let _: Vec = Vec::new(); +} +"#, + ); + } + + #[test] + fn inline_uses_across_files_2() { + check_assist( + inline_type_alias_uses, + r#" +//- /lib.rs +mod foo; +type $0I = i32; + +//- /foo.rs +use super::I; +fn foo() { + let _: I = 0; +} +"#, + r#" +//- /lib.rs +mod foo; + + +//- /foo.rs + +fn foo() { + let _: i32 = 0; +} +"#, + ); + } + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs index ce91dd237..2fc754e3e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs @@ -5,7 +5,7 @@ use syntax::{ AstNode, TextRange, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; static ASSIST_NAME: &str = "introduce_named_lifetime"; static ASSIST_LABEL: &str = "Introduce named lifetime"; @@ -140,7 +140,7 @@ enum NeedsLifetime { } impl NeedsLifetime { - fn make_mut(self, builder: &mut AssistBuilder) -> Self { + fn make_mut(self, builder: &mut SourceChangeBuilder) -> Self { match self { Self::SelfParam(it) => Self::SelfParam(builder.make_mut(it)), Self::RefType(it) => Self::RefType(builder.make_mut(it)), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 7e102ceba..2bdbec93b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,6 +1,10 @@ use either::Either; use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior}; -use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode}; +use syntax::{ + algo::neighbor, + ast::{self, edit_in_place::Removable}, + match_ast, ted, AstNode, SyntaxElement, SyntaxNode, +}; use crate::{ assist_context::{AssistContext, Assists}, @@ -76,7 +80,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio .collect(); for edit in edits_mut { match edit { - Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove), + Remove(it) => it.as_ref().either(Removable::remove, Removable::remove), Replace(old, new) => ted::replace(old, new), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs index 176a3bf58..1dd376ac3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,5 +1,9 @@ use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds}, + ast::{ + self, + edit_in_place::{GenericParamsOwnerEdit, Removable}, + make, AstNode, HasName, HasTypeBounds, + }, match_ast, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs index 59ea94ea1..bd2e8fbe3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs @@ -8,7 +8,8 @@ use syntax::{ use SyntaxKind::WHITESPACE; use crate::{ - assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, + assist_context::SourceChangeBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, + Assists, }; // Assist: remove_unused_param @@ -88,7 +89,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> fn process_usages( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, file_id: FileId, references: Vec, arg_to_remove: usize, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index bd50208da..d139f78a6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -10,7 +10,7 @@ use syntax::{ }; use crate::{ - assist_context::{AssistBuilder, AssistContext, Assists}, + assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::{ add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, @@ -224,7 +224,7 @@ fn impl_def_from_trait( } fn update_attribute( - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs new file mode 100644 index 000000000..7d91be621 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs @@ -0,0 +1,364 @@ +use ide_db::{ + assists::{AssistId, AssistKind}, + famous_defs::FamousDefs, +}; +use syntax::{ + ast::{self, make, Expr, HasArgList}, + AstNode, +}; + +use crate::{AssistContext, Assists}; + +// Assist: replace_or_with_or_else +// +// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`. +// +// ``` +// # //- minicore:option +// fn foo() { +// let a = Some(1); +// a.unwra$0p_or(2); +// } +// ``` +// -> +// ``` +// fn foo() { +// let a = Some(1); +// a.unwrap_or_else(|| 2); +// } +// ``` +pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let call: ast::MethodCallExpr = ctx.find_node_at_offset()?; + + let kind = is_option_or_result(call.receiver()?, ctx)?; + + let (name, arg_list) = (call.name_ref()?, call.arg_list()?); + + let mut map_or = false; + + let replace = match &*name.text() { + "unwrap_or" => "unwrap_or_else".to_string(), + "or" => "or_else".to_string(), + "ok_or" if kind == Kind::Option => "ok_or_else".to_string(), + "map_or" => { + map_or = true; + "map_or_else".to_string() + } + _ => return None, + }; + + let arg = match arg_list.args().collect::>().as_slice() { + [] => make::arg_list(Vec::new()), + [first] => { + let param = into_closure(first); + make::arg_list(vec![param]) + } + [first, second] if map_or => { + let param = into_closure(first); + make::arg_list(vec![param, second.clone()]) + } + _ => return None, + }; + + acc.add( + AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite), + format!("Replace {} with {}", name.text(), replace), + call.syntax().text_range(), + |builder| { + builder.replace(name.syntax().text_range(), replace); + builder.replace_ast(arg_list, arg) + }, + ) +} + +fn into_closure(param: &Expr) -> Expr { + (|| { + if let ast::Expr::CallExpr(call) = param { + if call.arg_list()?.args().count() == 0 { + Some(call.expr()?.clone()) + } else { + None + } + } else { + None + } + })() + .unwrap_or_else(|| make::expr_closure(None, param.clone())) +} + +// Assist: replace_or_else_with_or +// +// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`. +// +// ``` +// # //- minicore:option +// fn foo() { +// let a = Some(1); +// a.unwra$0p_or_else(|| 2); +// } +// ``` +// -> +// ``` +// fn foo() { +// let a = Some(1); +// a.unwrap_or(2); +// } +// ``` +pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let call: ast::MethodCallExpr = ctx.find_node_at_offset()?; + + let kind = is_option_or_result(call.receiver()?, ctx)?; + + let (name, arg_list) = (call.name_ref()?, call.arg_list()?); + + let mut map_or = false; + let replace = match &*name.text() { + "unwrap_or_else" => "unwrap_or".to_string(), + "or_else" => "or".to_string(), + "ok_or_else" if kind == Kind::Option => "ok_or".to_string(), + "map_or_else" => { + map_or = true; + "map_or".to_string() + } + _ => return None, + }; + + let arg = match arg_list.args().collect::>().as_slice() { + [] => make::arg_list(Vec::new()), + [first] => { + let param = into_call(first); + make::arg_list(vec![param]) + } + [first, second] if map_or => { + let param = into_call(first); + make::arg_list(vec![param, second.clone()]) + } + _ => return None, + }; + + acc.add( + AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite), + format!("Replace {} with {}", name.text(), replace), + call.syntax().text_range(), + |builder| { + builder.replace(name.syntax().text_range(), replace); + builder.replace_ast(arg_list, arg) + }, + ) +} + +fn into_call(param: &Expr) -> Expr { + (|| { + if let ast::Expr::ClosureExpr(closure) = param { + if closure.param_list()?.params().count() == 0 { + Some(closure.body()?.clone()) + } else { + None + } + } else { + None + } + })() + .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new()))) +} + +#[derive(PartialEq, Eq)] +enum Kind { + Option, + Result, +} + +fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option { + let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?; + let option_enum = + FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option(); + + if let Some(option_enum) = option_enum { + if ty == option_enum { + return Some(Kind::Option); + } + } + + let result_enum = + FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result(); + + if let Some(result_enum) = result_enum { + if ty == result_enum { + return Some(Kind::Result); + } + } + + None +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn replace_or_with_or_else_simple() { + check_assist( + replace_or_with_or_else, + r#" +//- minicore: option +fn foo() { + let foo = Some(1); + return foo.unwrap_$0or(2); +} +"#, + r#" +fn foo() { + let foo = Some(1); + return foo.unwrap_or_else(|| 2); +} +"#, + ) + } + + #[test] + fn replace_or_with_or_else_call() { + check_assist( + replace_or_with_or_else, + r#" +//- minicore: option +fn foo() { + let foo = Some(1); + return foo.unwrap_$0or(x()); +} +"#, + r#" +fn foo() { + let foo = Some(1); + return foo.unwrap_or_else(x); +} +"#, + ) + } + + #[test] + fn replace_or_with_or_else_block() { + check_assist( + replace_or_with_or_else, + r#" +//- minicore: option +fn foo() { + let foo = Some(1); + return foo.unwrap_$0or({ + let mut x = bar(); + for i in 0..10 { + x += i; + } + x + }); +} +"#, + r#" +fn foo() { + let foo = Some(1); + return foo.unwrap_or_else(|| { + let mut x = bar(); + for i in 0..10 { + x += i; + } + x + }); +} +"#, + ) + } + + #[test] + fn replace_or_else_with_or_simple() { + check_assist( + replace_or_else_with_or, + r#" +//- minicore: option +fn foo() { + let foo = Some(1); + return foo.unwrap_$0or_else(|| 2); +} +"#, + r#" +fn foo() { + let foo = Some(1); + return foo.unwrap_or(2); +} +"#, + ) + } + + #[test] + fn replace_or_else_with_or_call() { + check_assist( + replace_or_else_with_or, + r#" +//- minicore: option +fn foo() { + let foo = Some(1); + return foo.unwrap_$0or_else(x); +} +"#, + r#" +fn foo() { + let foo = Some(1); + return foo.unwrap_or(x()); +} +"#, + ) + } + + #[test] + fn replace_or_else_with_or_result() { + check_assist( + replace_or_else_with_or, + r#" +//- minicore: result +fn foo() { + let foo = Ok(1); + return foo.unwrap_$0or_else(x); +} +"#, + r#" +fn foo() { + let foo = Ok(1); + return foo.unwrap_or(x()); +} +"#, + ) + } + + #[test] + fn replace_or_else_with_or_map() { + check_assist( + replace_or_else_with_or, + r#" +//- minicore: result +fn foo() { + let foo = Ok("foo"); + return foo.map$0_or_else(|| 42, |v| v.len()); +} +"#, + r#" +fn foo() { + let foo = Ok("foo"); + return foo.map_or(42, |v| v.len()); +} +"#, + ) + } + + #[test] + fn replace_or_else_with_or_not_applicable() { + check_assist_not_applicable( + replace_or_else_with_or, + r#" +fn foo() { + let foo = Ok(1); + return foo.unwrap_$0or_else(x); +} +"#, + ) + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 6112e0945..521447c26 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -1,5 +1,6 @@ +use hir::HirDisplay; use syntax::{ - ast::{Expr, GenericArg}, + ast::{Expr, GenericArg, GenericArgList}, ast::{LetStmt, Type::InferType}, AstNode, TextRange, }; @@ -34,21 +35,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( let initializer = let_stmt.initializer()?; - let generic_args = match &initializer { - Expr::MethodCallExpr(ce) => ce.generic_arg_list()?, - Expr::CallExpr(ce) => { - if let Expr::PathExpr(pe) = ce.expr()? { - pe.path()?.segment()?.generic_arg_list()? - } else { - cov_mark::hit!(not_applicable_if_non_path_function_call); - return None; - } - } - _ => { - cov_mark::hit!(not_applicable_if_non_function_call_initializer); - return None; - } - }; + let generic_args = generic_arg_list(&initializer)?; // Find range of ::<_> let colon2 = generic_args.coloncolon_token()?; @@ -65,7 +52,16 @@ pub(crate) fn replace_turbofish_with_explicit_type( // An improvement would be to check that this is correctly part of the return value of the // function call, or sub in the actual return type. - let turbofish_type = &turbofish_args[0]; + let returned_type = match ctx.sema.type_of_expr(&initializer) { + Some(returned_type) if !returned_type.original.contains_unknown() => { + let module = ctx.sema.scope(let_stmt.syntax())?.module(); + returned_type.original.display_source_code(ctx.db(), module.into()).ok()? + } + _ => { + cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available); + turbofish_args[0].to_string() + } + }; let initializer_start = initializer.syntax().text_range().start(); if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start { @@ -83,12 +79,12 @@ pub(crate) fn replace_turbofish_with_explicit_type( "Replace turbofish with explicit type", TextRange::new(initializer_start, turbofish_range.end()), |builder| { - builder.insert(ident_range.end(), format!(": {}", turbofish_type)); + builder.insert(ident_range.end(), format!(": {}", returned_type)); builder.delete(turbofish_range); }, ); } else if let Some(InferType(t)) = let_stmt.ty() { - // If there's a type inferrence underscore, we can offer to replace it with the type in + // If there's a type inference underscore, we can offer to replace it with the type in // the turbofish. // let x: _ = fn::<...>(); let underscore_range = t.syntax().text_range(); @@ -98,7 +94,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( "Replace `_` with turbofish type", turbofish_range, |builder| { - builder.replace(underscore_range, turbofish_type.to_string()); + builder.replace(underscore_range, returned_type); builder.delete(turbofish_range); }, ); @@ -107,6 +103,26 @@ pub(crate) fn replace_turbofish_with_explicit_type( None } +fn generic_arg_list(expr: &Expr) -> Option { + match expr { + Expr::MethodCallExpr(expr) => expr.generic_arg_list(), + Expr::CallExpr(expr) => { + if let Expr::PathExpr(pe) = expr.expr()? { + pe.path()?.segment()?.generic_arg_list() + } else { + cov_mark::hit!(not_applicable_if_non_path_function_call); + return None; + } + } + Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?), + Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?), + _ => { + cov_mark::hit!(not_applicable_if_non_function_call_initializer); + None + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -115,6 +131,7 @@ mod tests { #[test] fn replaces_turbofish_for_vec_string() { + cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available); check_assist( replace_turbofish_with_explicit_type, r#" @@ -135,6 +152,7 @@ fn main() { #[test] fn replaces_method_calls() { // foo.make() is a method call which uses a different expr in the let initializer + cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available); check_assist( replace_turbofish_with_explicit_type, r#" @@ -237,6 +255,110 @@ fn make() -> T {} fn main() { let a = make$0::, i32>(); } +"#, + ); + } + + #[test] + fn replaces_turbofish_for_known_type() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +fn make() -> T {} +fn main() { + let a = make$0::(); +} +"#, + r#" +fn make() -> T {} +fn main() { + let a: i32 = make(); +} +"#, + ); + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option +fn make() -> T {} +fn main() { + let a = make$0::>(); +} +"#, + r#" +fn make() -> T {} +fn main() { + let a: Option = make(); +} +"#, + ); + } + + #[test] + fn replaces_turbofish_not_same_type() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option +fn make() -> Option {} +fn main() { + let a = make$0::(); +} +"#, + r#" +fn make() -> Option {} +fn main() { + let a: Option = make(); +} +"#, + ); + } + + #[test] + fn replaces_turbofish_for_type_with_defaulted_generic_param() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +struct HasDefault(T, U); +fn make() -> HasDefault {} +fn main() { + let a = make$0::(); +} +"#, + r#" +struct HasDefault(T, U); +fn make() -> HasDefault {} +fn main() { + let a: HasDefault = make(); +} +"#, + ); + } + + #[test] + fn replaces_turbofish_try_await() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option, future +struct Fut(T); +impl core::future::Future for Fut { + type Output = Option; +} +fn make() -> Fut {} +fn main() { + let a = make$0::().await?; +} +"#, + r#" +struct Fut(T); +impl core::future::Future for Fut { + type Output = Option; +} +fn make() -> Fut {} +fn main() { + let a: bool = make().await?; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs new file mode 100644 index 000000000..9565f0ee6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -0,0 +1,293 @@ +use syntax::{ + algo::neighbor, + ast::{self, edit::IndentLevel, make, AstNode}, + ted::{self, Position}, + Direction, SyntaxKind, T, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: unmerge_match_arm +// +// Splits the current match with a `|` pattern into two arms with identical bodies. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move(..) $0| Action::Stop => foo(), +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move(..) => foo(), +// Action::Stop => foo(), +// } +// } +// ``` +pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let pipe_token = ctx.find_token_syntax_at_offset(T![|])?; + let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update(); + let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; + let match_arm_body = match_arm.expr()?; + + // We don't need to check for leading pipe because it is directly under `MatchArm` + // without `OrPat`. + + let new_parent = match_arm.syntax().parent()?; + let old_parent_range = new_parent.text_range(); + + acc.add( + AssistId("unmerge_match_arm", AssistKind::RefactorRewrite), + "Unmerge match arm", + pipe_token.text_range(), + |edit| { + let pats_after = pipe_token + .siblings_with_tokens(Direction::Next) + .filter_map(|it| ast::Pat::cast(it.into_node()?)); + // FIXME: We should add a leading pipe if the original arm has one. + let new_match_arm = make::match_arm( + pats_after, + match_arm.guard().and_then(|guard| guard.condition()), + match_arm_body, + ) + .clone_for_update(); + + let mut pipe_index = pipe_token.index(); + if pipe_token + .prev_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE) + { + pipe_index -= 1; + } + or_pat.syntax().splice_children( + pipe_index..or_pat.syntax().children_with_tokens().count(), + Vec::new(), + ); + + let mut insert_after_old_arm = Vec::new(); + + // A comma can be: + // - After the arm. In this case we always want to insert a comma after the newly + // inserted arm. + // - Missing after the arm, with no arms after. In this case we want to insert a + // comma before the newly inserted arm. It can not be necessary if there arm + // body is a block, but we don't bother to check that. + // - Missing after the arm with arms after, if the arm body is a block. In this case + // we don't want to insert a comma at all. + let has_comma_after = + std::iter::successors(match_arm.syntax().last_child_or_token(), |it| { + it.prev_sibling_or_token() + }) + .map(|it| it.kind()) + .skip_while(|it| it.is_trivia()) + .next() + == Some(T![,]); + let has_arms_after = neighbor(&match_arm, Direction::Next).is_some(); + if !has_comma_after && !has_arms_after { + insert_after_old_arm.push(make::token(T![,]).into()); + } + + let indent = IndentLevel::from_node(match_arm.syntax()); + insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into()); + + insert_after_old_arm.push(new_match_arm.syntax().clone().into()); + + ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm); + + if has_comma_after { + ted::insert_raw( + Position::last_child_of(new_match_arm.syntax()), + make::token(T![,]), + ); + } + + edit.replace(old_parent_range, new_parent.to_string()); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn unmerge_match_arm_single_pipe() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B => { 1i32 } + X::C => { 2i32 } + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A => { 1i32 } + X::B => { 1i32 } + X::C => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_guard() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B if true => { 1i32 } + _ => { 2i32 } + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A if true => { 1i32 } + X::B if true => { 1i32 } + _ => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_leading_pipe() { + check_assist_not_applicable( + unmerge_match_arm, + r#" + +fn main() { + let y = match 0 { + |$0 0 => { 1i32 } + 1 => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_multiple_pipes() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C, D, E } + +fn main() { + let x = X::A; + let y = match x { + X::A | X::B |$0 X::C | X::D => 1i32, + X::E => 2i32, + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C, D, E } + +fn main() { + let x = X::A; + let y = match x { + X::A | X::B => 1i32, + X::C | X::D => 1i32, + X::E => 2i32, + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_inserts_comma_if_required() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B => 1i32 + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + let y = match x { + X::A => 1i32, + X::B => 1i32 + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_inserts_comma_if_had_after() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + match x { + X::A $0| X::B => {}, + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + match x { + X::A => {}, + X::B => {}, + } +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs index 3ce028e93..dac216b69 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, make, HasVisibility}, + ast::{self, edit_in_place::Removable, make, HasVisibility}, ted::{self, Position}, AstNode, SyntaxKind, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index fe87aa15f..e52544db5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -122,6 +122,7 @@ mod handlers { mod convert_let_else_to_match; mod convert_tuple_struct_to_named_struct; mod convert_to_guarded_return; + mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; mod destructure_tuple_binding; mod expand_glob_import; @@ -179,12 +180,14 @@ mod handlers { mod replace_try_expr_with_match; mod replace_derive_with_manual_impl; mod replace_if_let_with_match; + mod replace_or_with_or_else; mod introduce_named_generic; mod replace_let_with_if_let; mod replace_qualified_name_with_use; mod replace_string_with_char; mod replace_turbofish_with_explicit_type; mod split_import; + mod unmerge_match_arm; mod sort_items; mod toggle_ignore; mod unmerge_use; @@ -215,6 +218,7 @@ mod handlers { convert_let_else_to_match::convert_let_else_to_match, convert_to_guarded_return::convert_to_guarded_return, convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, + convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro, convert_while_to_loop::convert_while_to_loop, destructure_tuple_binding::destructure_tuple_binding, expand_glob_import::expand_glob_import, @@ -243,6 +247,7 @@ mod handlers { inline_call::inline_into_callers, inline_local_variable::inline_local_variable, inline_type_alias::inline_type_alias, + inline_type_alias::inline_type_alias_uses, introduce_named_generic::introduce_named_generic, introduce_named_lifetime::introduce_named_lifetime, invert_if::invert_if, @@ -272,11 +277,14 @@ mod handlers { replace_if_let_with_match::replace_if_let_with_match, replace_if_let_with_match::replace_match_with_if_let, replace_let_with_if_let::replace_let_with_if_let, + replace_or_with_or_else::replace_or_else_with_or, + replace_or_with_or_else::replace_or_with_or_else, replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, replace_qualified_name_with_use::replace_qualified_name_with_use, sort_items::sort_items, split_import::split_import, toggle_ignore::toggle_ignore, + unmerge_match_arm::unmerge_match_arm, unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 6eaab48a3..227e2300f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -472,6 +472,26 @@ impl Point { ) } +#[test] +fn doctest_convert_two_arm_bool_match_to_matches_macro() { + check_doc_test( + "convert_two_arm_bool_match_to_matches_macro", + r#####" +fn main() { + match scrutinee$0 { + Some(val) if val.cond() => true, + _ => false, + } +} +"#####, + r#####" +fn main() { + matches!(scrutinee, Some(val) if val.cond()) +} +"#####, + ) +} + #[test] fn doctest_convert_while_to_loop() { check_doc_test( @@ -1356,6 +1376,31 @@ fn main() { ) } +#[test] +fn doctest_inline_type_alias_uses() { + check_doc_test( + "inline_type_alias_uses", + r#####" +type $0A = i32; +fn id(x: A) -> A { + x +}; +fn foo() { + let _: A = 3; +} +"#####, + r#####" + +fn id(x: i32) -> i32 { + x +}; +fn foo() { + let _: i32 = 3; +} +"#####, + ) +} + #[test] fn doctest_introduce_named_generic() { check_doc_test( @@ -1984,6 +2029,46 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_replace_or_else_with_or() { + check_doc_test( + "replace_or_else_with_or", + r#####" +//- minicore:option +fn foo() { + let a = Some(1); + a.unwra$0p_or_else(|| 2); +} +"#####, + r#####" +fn foo() { + let a = Some(1); + a.unwrap_or(2); +} +"#####, + ) +} + +#[test] +fn doctest_replace_or_with_or_else() { + check_doc_test( + "replace_or_with_or_else", + r#####" +//- minicore:option +fn foo() { + let a = Some(1); + a.unwra$0p_or(2); +} +"#####, + r#####" +fn foo() { + let a = Some(1); + a.unwrap_or_else(|| 2); +} +"#####, + ) +} + #[test] fn doctest_replace_qualified_name_with_use() { check_doc_test( @@ -2182,6 +2267,32 @@ fn arithmetics { ) } +#[test] +fn doctest_unmerge_match_arm() { + check_doc_test( + "unmerge_match_arm", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) $0| Action::Stop => foo(), + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) => foo(), + Action::Stop => foo(), + } +} +"#####, + ) +} + #[test] fn doctest_unmerge_use() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 3e61d0741..4ab6e2627 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -12,7 +12,7 @@ use syntax::{ ast::{ self, edit::{self, AstNodeEdit}, - edit_in_place::AttrsOwnerEdit, + edit_in_place::{AttrsOwnerEdit, Removable}, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, }, ted, AstNode, AstToken, Direction, SmolStr, SourceFile, @@ -20,7 +20,7 @@ use syntax::{ SyntaxNode, TextRange, TextSize, T, }; -use crate::assist_context::{AssistBuilder, AssistContext}; +use crate::assist_context::{AssistContext, SourceChangeBuilder}; pub(crate) mod suggest_name; mod gen_trait_fn_body; @@ -484,7 +484,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str } pub(crate) fn add_method_to_adt( - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, adt: &ast::Adt, impl_def: Option, method: &str, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs index 779cdbc93..c521a10fc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs @@ -55,6 +55,7 @@ const USELESS_METHODS: &[&str] = &[ "iter", "into_iter", "iter_mut", + "into_future", ]; pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { @@ -75,7 +76,7 @@ pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { /// In current implementation, the function tries to get the name from /// the following sources: /// -/// * if expr is an argument to function/method, use paramter name +/// * if expr is an argument to function/method, use parameter name /// * if expr is a function/method call, use function name /// * expression type name if it exists (E.g. `()`, `fn() -> ()` or `!` do not have names) /// * fallback: `var_name` @@ -85,7 +86,7 @@ pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { /// Currently it sticks to the first name found. // FIXME: Microoptimize and return a `SmolStr` here. pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { - // `from_param` does not benifit from stripping + // `from_param` does not benefit from stripping // it need the largest context possible // so we check firstmost if let Some(name) = from_param(expr, sema) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 72579e602..55c3e2839 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -617,7 +617,6 @@ pub(super) fn complete_name_ref( dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx); item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx); - record::complete_record_expr_func_update(acc, ctx, path_ctx, expr_ctx); snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx); } PathKind::Type { location } => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index cf40ca489..02004ff7b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -19,7 +19,7 @@ pub(crate) fn complete_dot( }; // Suggest .await syntax for types that implement Future trait - if receiver_ty.impls_future(ctx.db) { + if receiver_ty.impls_into_future(ctx.db) { let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); item.detail("expr.await"); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 5d0ddaaf2..588b52cc1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -1,8 +1,10 @@ //! Completion of names from the current scope in expression position. use hir::ScopeDef; +use syntax::ast; use crate::{ + completions::record::add_default_update, context::{ExprCtx, PathCompletionCtx, Qualified}, CompletionContext, Completions, }; @@ -219,60 +221,90 @@ pub(crate) fn complete_expr_path( _ => (), }); - if is_func_update.is_none() { - let mut add_keyword = - |kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet); + match is_func_update { + Some(record_expr) => { + let ty = ctx.sema.type_of_expr(&ast::Expr::RecordExpr(record_expr.clone())); - if !in_block_expr { - add_keyword("unsafe", "unsafe {\n $0\n}"); - } - add_keyword("match", "match $1 {\n $0\n}"); - add_keyword("while", "while $1 {\n $0\n}"); - add_keyword("while let", "while let $1 = $2 {\n $0\n}"); - add_keyword("loop", "loop {\n $0\n}"); - if in_match_guard { - add_keyword("if", "if $0"); - } else { - add_keyword("if", "if $1 {\n $0\n}"); + match ty.as_ref().and_then(|t| t.original.as_adt()) { + Some(hir::Adt::Union(_)) => (), + _ => { + cov_mark::hit!(functional_update); + let missing_fields = + ctx.sema.record_literal_missing_fields(record_expr); + if !missing_fields.is_empty() { + add_default_update(acc, ctx, ty); + } + } + }; } - add_keyword("if let", "if let $1 = $2 {\n $0\n}"); - add_keyword("for", "for $1 in $2 {\n $0\n}"); - add_keyword("true", "true"); - add_keyword("false", "false"); + None => { + let mut add_keyword = |kw, snippet| { + acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet) + }; - if in_condition || in_block_expr { - add_keyword("let", "let"); - } + if !in_block_expr { + add_keyword("unsafe", "unsafe {\n $0\n}"); + } + add_keyword("match", "match $1 {\n $0\n}"); + add_keyword("while", "while $1 {\n $0\n}"); + add_keyword("while let", "while let $1 = $2 {\n $0\n}"); + add_keyword("loop", "loop {\n $0\n}"); + if in_match_guard { + add_keyword("if", "if $0"); + } else { + add_keyword("if", "if $1 {\n $0\n}"); + } + add_keyword("if let", "if let $1 = $2 {\n $0\n}"); + add_keyword("for", "for $1 in $2 {\n $0\n}"); + add_keyword("true", "true"); + add_keyword("false", "false"); - if after_if_expr { - add_keyword("else", "else {\n $0\n}"); - add_keyword("else if", "else if $1 {\n $0\n}"); - } + if in_condition || in_block_expr { + add_keyword("let", "let"); + } - if wants_mut_token { - add_keyword("mut", "mut "); - } + if after_if_expr { + add_keyword("else", "else {\n $0\n}"); + add_keyword("else if", "else if $1 {\n $0\n}"); + } - if in_loop_body { - if in_block_expr { - add_keyword("continue", "continue;"); - add_keyword("break", "break;"); - } else { - add_keyword("continue", "continue"); - add_keyword("break", "break"); + if wants_mut_token { + add_keyword("mut", "mut "); + } + + if in_loop_body { + if in_block_expr { + add_keyword("continue", "continue;"); + add_keyword("break", "break;"); + } else { + add_keyword("continue", "continue"); + add_keyword("break", "break"); + } } - } - if let Some(ty) = innermost_ret_ty { - add_keyword( - "return", - match (in_block_expr, ty.is_unit()) { - (true, true) => "return ;", - (true, false) => "return;", - (false, true) => "return $0", - (false, false) => "return", - }, - ); + if let Some(ret_ty) = innermost_ret_ty { + add_keyword( + "return", + match (ret_ty.is_unit(), in_block_expr) { + (true, true) => { + cov_mark::hit!(return_unit_block); + "return;" + } + (true, false) => { + cov_mark::hit!(return_unit_no_block); + "return" + } + (false, true) => { + cov_mark::hit!(return_value_block); + "return $0;" + } + (false, false) => { + cov_mark::hit!(return_value_no_block); + "return $0" + } + }, + ); + } } } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index e9256803c..785db6fde 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -233,7 +233,8 @@ fn add_type_alias_impl( type_alias: hir::TypeAlias, ) { let alias_name = type_alias.name(ctx.db); - let (alias_name, escaped_name) = (alias_name.to_smol_str(), alias_name.escaped().to_smol_str()); + let (alias_name, escaped_name) = + (alias_name.unescaped().to_smol_str(), alias_name.to_smol_str()); let label = format!("type {} =", alias_name); let replacement = format!("type {} = ", escaped_name); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 3989a451b..1d03c8cc5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -75,16 +75,17 @@ impl Future for A {} fn foo(a: A) { a.$0 } "#, expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + kw await expr.await + me into_future() (as IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr "#]], ); @@ -98,18 +99,45 @@ fn foo() { } "#, expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + kw await expr.await + me into_future() (use core::future::IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr "#]], - ) + ); + } + + #[test] + fn test_completion_await_impls_into_future() { + check( + r#" +//- minicore: future +use core::future::*; +struct A {} +impl IntoFuture for A {} +fn foo(a: A) { a.$0 } +"#, + expect![[r#" + kw await expr.await + me into_future() (as IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + "#]], + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index 9c975b929..950731eb4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -53,6 +53,7 @@ pub(crate) fn complete_mod( let existing_mod_declarations = current_module .children(ctx.db) .filter_map(|module| Some(module.name(ctx.db)?.to_string())) + .filter(|module| module != ctx.original_token.text()) .collect::>(); let module_declaration_file = @@ -351,4 +352,23 @@ fn ignored_bar() {} "#]], ); } + + #[test] + fn semi_colon_completion() { + check( + r#" +//- /lib.rs +mod foo; +//- /foo.rs +mod bar { + mod baz$0 +} +//- /foo/bar/baz.rs +fn baz() {} +"#, + expect![[r#" + md baz; + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs index 6b94347e0..b273a4cb5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs @@ -173,7 +173,7 @@ impl FormatStrParser { } } (State::Expr, ':') if chars.peek().copied() == Some(':') => { - // path seperator + // path separator current_expr.push_str("::"); chars.next(); } @@ -185,7 +185,7 @@ impl FormatStrParser { current_expr = String::new(); self.state = State::FormatOpts; } else { - // We're inside of braced expression, assume that it's a struct field name/value delimeter. + // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 1c9042390..5d96fbd30 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -3,7 +3,7 @@ use ide_db::SymbolKind; use syntax::ast::{self, Expr}; use crate::{ - context::{DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, PatternContext, Qualified}, + context::{DotAccess, DotAccessKind, PatternContext}, CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, Completions, }; @@ -14,7 +14,24 @@ pub(crate) fn complete_record_pattern_fields( pattern_ctx: &PatternContext, ) { if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx { - complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat)); + let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone())); + let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) { + Some(hir::Adt::Union(un)) => { + // ctx.sema.record_pat_missing_fields will always return + // an empty Vec on a union literal. This is normally + // reasonable, but here we'd like to present the full list + // of fields if the literal is empty. + let were_fields_specified = + record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some(); + + match were_fields_specified { + false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), + true => return, + } + } + _ => ctx.sema.record_pattern_missing_fields(record_pat), + }; + complete_fields(acc, ctx, missing_fields); } } @@ -42,8 +59,13 @@ pub(crate) fn complete_record_expr_fields( } _ => { let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); + + if !missing_fields.is_empty() { + cov_mark::hit!(functional_update_field); + add_default_update(acc, ctx, ty); + } if dot_prefix { + cov_mark::hit!(functional_update_one_dot); let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); item.insert_text("."); @@ -56,41 +78,18 @@ pub(crate) fn complete_record_expr_fields( complete_fields(acc, ctx, missing_fields); } -// FIXME: This should probably be part of complete_path_expr -pub(crate) fn complete_record_expr_func_update( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &ExprCtx, -) { - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx { - let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); - - match ty.as_ref().and_then(|t| t.original.as_adt()) { - Some(hir::Adt::Union(_)) => (), - _ => { - let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); - } - }; - } -} - -fn add_default_update( +pub(crate) fn add_default_update( acc: &mut Completions, ctx: &CompletionContext<'_>, ty: Option, - missing_fields: &[(hir::Field, hir::Type)], ) { let default_trait = ctx.famous_defs().core_default_Default(); - let impl_default_trait = default_trait + let impls_default_trait = default_trait .zip(ty.as_ref()) .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[])); - if impl_default_trait && !missing_fields.is_empty() { + if impls_default_trait { // FIXME: This should make use of scope_def like completions so we get all the other goodies + // that is we should handle this like actually completing the default function let completion_text = "..Default::default()"; let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); let completion_text = @@ -130,7 +129,7 @@ mod tests { #[test] fn literal_struct_completion_edit() { check_edit( - "FooDesc {…}", + "FooDesc{}", r#" struct FooDesc { pub bar: bool } @@ -155,7 +154,7 @@ fn baz() { #[test] fn literal_struct_impl_self_completion() { check_edit( - "Self {…}", + "Self{}", r#" struct Foo { bar: u64, @@ -181,7 +180,7 @@ impl Foo { ); check_edit( - "Self(…)", + "Self()", r#" mod submod { pub struct Foo(pub u64); @@ -210,7 +209,7 @@ impl submod::Foo { #[test] fn literal_struct_completion_from_sub_modules() { check_edit( - "submod::Struct {…}", + "submod::Struct{}", r#" mod submod { pub struct Struct { @@ -239,7 +238,7 @@ fn f() -> submod::Struct { #[test] fn literal_struct_complexion_module() { check_edit( - "FooDesc {…}", + "FooDesc{}", r#" mod _69latrick { pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index e35f79d2b..a5e854b74 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -64,8 +64,11 @@ pub(crate) struct PathCompletionCtx { pub(super) qualified: Qualified, /// The parent of the path we are completing. pub(super) parent: Option, + #[allow(dead_code)] /// The path of which we are completing the segment pub(super) path: ast::Path, + /// The path of which we are completing the segment in the original file + pub(crate) original_path: Option, pub(super) kind: PathKind, /// Whether the path segment has type args or not. pub(super) has_type_args: bool, @@ -134,6 +137,7 @@ pub(crate) struct ExprCtx { pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, pub(crate) ref_expr_parent: Option, + /// The surrounding RecordExpression we are completing a functional update pub(crate) is_func_update: Option, pub(crate) self_param: Option, pub(crate) innermost_ret_ty: Option, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 22ec7cead..01dd9a234 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -588,12 +588,15 @@ impl<'a> CompletionContext<'a> { }; let path = segment.parent_path(); + let original_path = find_node_in_file_compensated(sema, original_file, &path); + let mut path_ctx = PathCompletionCtx { has_call_parens: false, has_macro_bang: false, qualified: Qualified::No, parent: None, path: path.clone(), + original_path, kind: PathKind::Item { kind: ItemListKind::SourceFile }, has_type_args: false, use_tree_parent: false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 946134b0f..86302cb06 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -117,7 +117,7 @@ pub(crate) fn render_field( ) -> CompletionItem { let is_deprecated = ctx.is_deprecated(field); let name = field.name(ctx.db()); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), @@ -283,8 +283,8 @@ fn render_resolution_path( let name = local_name.to_smol_str(); let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution); - if local_name.escaped().is_escaped() { - item.insert_text(local_name.escaped().to_smol_str()); + if local_name.is_escaped() { + item.insert_text(local_name.to_smol_str()); } // Add `<>` for generic types let type_path_no_ty_args = matches!( @@ -306,7 +306,7 @@ fn render_resolution_path( item.lookup_by(name.clone()) .label(SmolStr::from_iter([&name, "<…>"])) .trigger_call_info() - .insert_snippet(cap, format!("{}<$0>", local_name.escaped())); + .insert_snippet(cap, format!("{}<$0>", local_name)); } } } @@ -323,9 +323,7 @@ fn render_resolution_path( ..CompletionRelevance::default() }); - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } + path_ref_match(completion, path_ctx, &ty, &mut item); }; item } @@ -342,7 +340,8 @@ fn render_resolution_simple_( let ctx = ctx.import_to_add(import_to_add); let kind = res_to_kind(resolution); - let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str()); + let mut item = + CompletionItem::new(kind, ctx.source_range(), local_name.unescaped().to_smol_str()); item.set_relevance(ctx.completion_relevance()) .set_documentation(scope_def_docs(db, resolution)) .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); @@ -452,6 +451,29 @@ fn compute_ref_match( None } +fn path_ref_match( + completion: &CompletionContext<'_>, + path_ctx: &PathCompletionCtx, + ty: &hir::Type, + item: &mut Builder, +) { + if let Some(original_path) = &path_ctx.original_path { + // At least one char was typed by the user already, in that case look for the original path + if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) { + if let Some(ref_match) = compute_ref_match(completion, ty) { + item.ref_match(ref_match, original_path.syntax().text_range().start()); + } + } + } else { + // completion requested on an empty identifier, there is no path here yet. + // FIXME: This might create inconsistent completions where we show a ref match in macro inputs + // as long as nothing was typed yet + if let Some(ref_match) = compute_ref_match(completion, ty) { + item.ref_match(ref_match, completion.position.offset); + } + } +} + #[cfg(test)] mod tests { use std::cmp; @@ -564,6 +586,7 @@ fn main() { Foo::Fo$0 } kind: SymbolKind( Variant, ), + lookup: "Foo{}", detail: "Foo { x: i32, y: i32 }", }, ] @@ -590,6 +613,7 @@ fn main() { Foo::Fo$0 } kind: SymbolKind( Variant, ), + lookup: "Foo()", detail: "Foo(i32, i32)", }, ] @@ -706,7 +730,7 @@ fn main() { let _: m::Spam = S$0 } kind: SymbolKind( Variant, ), - lookup: "Spam::Bar(…)", + lookup: "Spam::Bar()", detail: "m::Spam::Bar(i32)", relevance: CompletionRelevance { exact_name_match: false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs index a810eef18..93ea825e0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs @@ -13,7 +13,7 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option { let db = ctx.db(); let name = const_.name(db)?; - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let detail = const_.display(db).to_string(); let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 4b5535718..376120846 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -52,10 +52,10 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format!("{}.{}", receiver, &name).into(), - format!("{}.{}", receiver.escaped(), name.escaped()).into(), + format!("{}.{}", receiver.unescaped(), name.unescaped()).into(), + format!("{}.{}", receiver, name).into(), ), - _ => (name.to_smol_str(), name.escaped().to_smol_str()), + _ => (name.unescaped().to_smol_str(), name.to_smol_str()), }; let mut item = CompletionItem::new( if func.self_param(db).is_some() { @@ -79,24 +79,24 @@ fn render( ..ctx.completion_relevance() }); - if let Some(ref_match) = compute_ref_match(completion, &ret_type) { - match func_kind { - FuncKind::Function(path_ctx) => { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } - FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { - if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { + match func_kind { + FuncKind::Function(path_ctx) => { + super::path_ref_match(completion, path_ctx, &ret_type, &mut item); + } + FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { + if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { + if let Some(ref_match) = compute_ref_match(completion, &ret_type) { item.ref_match(ref_match, original_expr.syntax().text_range().start()); } } - _ => (), } + _ => (), } item.set_documentation(ctx.docs(func)) .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func)) .detail(detail(db, func)) - .lookup_by(name.to_smol_str()); + .lookup_by(name.unescaped().to_smol_str()); match ctx.completion.config.snippet_cap { Some(cap) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index 91a253f8f..0c791ac57 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -2,16 +2,15 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind}; use ide_db::SymbolKind; -use syntax::AstNode; use crate::{ context::{CompletionContext, PathCompletionCtx, PathKind}, item::{Builder, CompletionItem}, render::{ - compute_ref_match, compute_type_match, + compute_type_match, variant::{ - format_literal_label, render_record_lit, render_tuple_lit, visible_fields, - RenderedLiteral, + format_literal_label, format_literal_lookup, render_record_lit, render_tuple_lit, + visible_fields, RenderedLiteral, }, RenderContext, }, @@ -73,7 +72,7 @@ fn render( None => (name.clone().into(), name.into(), false), }; let (qualified_name, escaped_qualified_name) = - (qualified_name.to_string(), qualified_name.escaped().to_string()); + (qualified_name.unescaped().to_string(), qualified_name.to_string()); let snippet_cap = ctx.snippet_cap(); let mut rendered = match kind { @@ -97,13 +96,20 @@ fn render( if !should_add_parens { kind = StructKind::Unit; } + let label = format_literal_label(&qualified_name, kind); + let lookup = if qualified { + format_literal_lookup(&short_qualified_name.to_string(), kind) + } else { + format_literal_lookup(&qualified_name, kind) + }; let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(thing.symbol_kind()), ctx.source_range(), - format_literal_label(&qualified_name, kind), + label, ); + item.lookup_by(lookup); item.detail(rendered.detail); match snippet_cap { @@ -111,9 +117,6 @@ fn render( None => item.insert_text(rendered.literal), }; - if qualified { - item.lookup_by(format_literal_label(&short_qualified_name.to_string(), kind)); - } item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx)); let ty = thing.ty(db); @@ -121,9 +124,8 @@ fn render( type_match: compute_type_match(ctx.completion, &ty), ..ctx.completion_relevance() }); - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } + + super::path_ref_match(completion, path_ctx, &ty, &mut item); if let Some(import_to_add) = ctx.import_to_add { item.add_import(import_to_add); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs index ca2269f13..eabd0bd17 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs @@ -46,7 +46,7 @@ fn render( ctx.source_range() }; - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let docs = ctx.docs(macro_); let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default(); let is_fn_like = macro_.is_fn_like(completion.db); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 34a384f2f..c845ff21a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -8,7 +8,7 @@ use syntax::SmolStr; use crate::{ context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext}, render::{ - variant::{format_literal_label, visible_fields}, + variant::{format_literal_label, format_literal_lookup, visible_fields}, RenderContext, }, CompletionItem, CompletionItemKind, @@ -31,12 +31,13 @@ pub(crate) fn render_struct_pat( } let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let kind = strukt.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind); + let lookup = format_literal_lookup(name.as_str(), kind); let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - Some(build_completion(ctx, label, pat, strukt)) + Some(build_completion(ctx, label, lookup, pat, strukt)) } pub(crate) fn render_variant_pat( @@ -53,18 +54,21 @@ pub(crate) fn render_variant_pat( let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; let (name, escaped_name) = match path { - Some(path) => (path.to_string().into(), path.escaped().to_string().into()), + Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), None => { let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); - (name.to_smol_str(), name.escaped().to_smol_str()) + (name.unescaped().to_smol_str(), name.to_smol_str()) } }; - let (label, pat) = match path_ctx { - Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()), + let (label, lookup, pat) = match path_ctx { + Some(PathCompletionCtx { has_call_parens: true, .. }) => { + (name.clone(), name, escaped_name.to_string()) + } _ => { let kind = variant.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind); + let lookup = format_literal_lookup(name.as_str(), kind); let pat = render_pat( &ctx, pattern_ctx, @@ -73,16 +77,17 @@ pub(crate) fn render_variant_pat( &visible_fields, fields_omitted, )?; - (label, pat) + (label, lookup, pat) } }; - Some(build_completion(ctx, label, pat, variant)) + Some(build_completion(ctx, label, lookup, pat, variant)) } fn build_completion( ctx: RenderContext<'_>, label: SmolStr, + lookup: SmolStr, pat: String, def: impl HasAttrs + Copy, ) -> CompletionItem { @@ -90,6 +95,7 @@ fn build_completion( item.set_documentation(ctx.docs(def)) .set_deprecated(ctx.is_deprecated(def)) .detail(&pat) + .lookup_by(lookup) .set_relevance(ctx.completion_relevance()); match ctx.snippet_cap() { Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), @@ -146,7 +152,7 @@ fn render_record_as_pat( format!( "{name} {{ {}{} }}", fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db).escaped(), idx + 1)) + f(&format_args!("{}${}", field.name(db), idx + 1)) }), if fields_omitted { ", .." } else { "" }, name = name @@ -155,7 +161,7 @@ fn render_record_as_pat( None => { format!( "{name} {{ {}{} }}", - fields.map(|field| field.name(db).escaped().to_smol_str()).format(", "), + fields.map(|field| field.name(db).to_smol_str()).format(", "), if fields_omitted { ", .." } else { "" }, name = name ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs index f1b23c76e..de919429f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs @@ -32,11 +32,11 @@ fn render( let name = type_alias.name(db); let (name, escaped_name) = if with_eq { ( + SmolStr::from_iter([&name.unescaped().to_smol_str(), " = "]), SmolStr::from_iter([&name.to_smol_str(), " = "]), - SmolStr::from_iter([&name.escaped().to_smol_str(), " = "]), ) } else { - (name.to_smol_str(), name.escaped().to_smol_str()) + (name.unescaped().to_smol_str(), name.to_smol_str()) }; let detail = type_alias.display(db).to_string(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs index 9c9540a9b..54e97dd57 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use crate::{ render::{ - variant::{format_literal_label, visible_fields}, + variant::{format_literal_label, format_literal_lookup, visible_fields}, RenderContext, }, CompletionItem, CompletionItemKind, @@ -21,16 +21,19 @@ pub(crate) fn render_union_literal( let name = local_name.unwrap_or_else(|| un.name(ctx.db())); let (qualified_name, escaped_qualified_name) = match path { - Some(p) => (p.to_string(), p.escaped().to_string()), - None => (name.to_string(), name.escaped().to_string()), + Some(p) => (p.unescaped().to_string(), p.to_string()), + None => (name.unescaped().to_string(), name.to_string()), }; - + let label = format_literal_label(&name.to_smol_str(), StructKind::Record); + let lookup = format_literal_lookup(&name.to_smol_str(), StructKind::Record); let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Union), ctx.source_range(), - format_literal_label(&name.to_smol_str(), StructKind::Record), + label, ); + item.lookup_by(lookup); + let fields = un.fields(ctx.db()); let (fields, fields_omitted) = visible_fields(ctx.completion, &fields, un)?; @@ -42,15 +45,15 @@ pub(crate) fn render_union_literal( format!( "{} {{ ${{1|{}|}}: ${{2:()}} }}$0", escaped_qualified_name, - fields.iter().map(|field| field.name(ctx.db()).escaped().to_smol_str()).format(",") + fields.iter().map(|field| field.name(ctx.db()).to_smol_str()).format(",") ) } else { format!( "{} {{ {} }}", escaped_qualified_name, - fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: ()", field.name(ctx.db()).escaped())) - }) + fields + .iter() + .format_with(", ", |field, f| { f(&format_args!("{}: ()", field.name(ctx.db()))) }) ) }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs index 003a0c11e..24e6abdc9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs @@ -24,9 +24,9 @@ pub(crate) fn render_record_lit( ) -> RenderedLiteral { let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { if snippet_cap.is_some() { - f(&format_args!("{}: ${{{}:()}}", field.name(db).escaped(), idx + 1)) + f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1)) } else { - f(&format_args!("{}: ()", field.name(db).escaped())) + f(&format_args!("{}: ()", field.name(db))) } }); @@ -94,3 +94,12 @@ pub(crate) fn format_literal_label(name: &str, kind: StructKind) -> SmolStr { StructKind::Unit => name.into(), } } + +/// Format a struct, etc. literal option for lookup used in completions filtering. +pub(crate) fn format_literal_lookup(name: &str, kind: StructKind) -> SmolStr { + match kind { + StructKind::Tuple => SmolStr::from_iter([name, "()"]), + StructKind::Record => SmolStr::from_iter([name, "{}"]), + StructKind::Unit => name.into(), + } +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 925081ebf..8e26d889f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1,7 +1,7 @@ //! Completion tests for expressions. use expect_test::{expect, Expect}; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture)); @@ -670,3 +670,78 @@ fn main() { "#]], ); } + +#[test] +fn varaiant_with_struct() { + check_empty( + r#" +pub struct YoloVariant { + pub f: usize +} + +pub enum HH { + Yolo(YoloVariant), +} + +fn brr() { + let t = HH::Yolo(Y$0); +} +"#, + expect![[r#" + en HH + fn brr() fn() + st YoloVariant + st YoloVariant {…} YoloVariant { f: usize } + bt u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} + +#[test] +fn return_unit_block() { + cov_mark::check!(return_unit_block); + check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#); +} + +#[test] +fn return_unit_no_block() { + cov_mark::check!(return_unit_no_block); + check_edit( + "return", + r#"fn f() { match () { () => $0 } }"#, + r#"fn f() { match () { () => return } }"#, + ); +} + +#[test] +fn return_value_block() { + cov_mark::check!(return_value_block); + check_edit( + "return", + r#"fn f() -> i32 { if true { $0 } }"#, + r#"fn f() -> i32 { if true { return $0; } }"#, + ); +} + +#[test] +fn return_value_no_block() { + cov_mark::check!(return_value_no_block); + check_edit( + "return", + r#"fn f() -> i32 { match () { () => $0 } }"#, + r#"fn f() -> i32 { match () { () => return $0 } }"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 0bba7f245..a63ef0068 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -159,7 +159,7 @@ pub mod some_module { pub struct ThiiiiiirdStruct; // contains all letters from the query, but not in the beginning, displayed second pub struct AfterThirdStruct; - // contains all letters from the query in the begginning, displayed first + // contains all letters from the query in the beginning, displayed first pub struct ThirdStruct; } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 30ddbe2dc..85c4dbd66 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -467,7 +467,7 @@ fn foo() { fn completes_enum_variant_pat() { cov_mark::check!(enum_variant_pattern_path); check_edit( - "RecordVariant {…}", + "RecordVariant{}", r#" enum Enum { RecordVariant { field: u32 } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs index f6accc68e..328faaa06 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs @@ -103,8 +103,9 @@ fn foo(f: Struct) { } #[test] -fn functional_update() { - // FIXME: This should filter out all completions that do not have the type `Foo` +fn in_functional_update() { + cov_mark::check!(functional_update); + check( r#" //- minicore:default @@ -116,13 +117,21 @@ impl Default for Foo { fn main() { let thing = 1; let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, $0 } + let foo2 = Foo { thing, ..$0 } } "#, expect![[r#" fd ..Default::default() - fd foo1 u32 - fd foo2 u32 + fn main() fn() + lc foo Foo + lc thing i32 + md core + st Foo + st Foo {…} Foo { foo1: u32, foo2: u32 } + tt Default + bt u32 + kw crate:: + kw self:: "#]], ); check( @@ -136,14 +145,19 @@ impl Default for Foo { fn main() { let thing = 1; let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, .$0 } + let foo2 = Foo { thing, ..Default::$0 } } "#, expect![[r#" - fd ..Default::default() - sn .. + fn default() (as Default) fn() -> Self "#]], ); +} + +#[test] +fn functional_update_no_dot() { + cov_mark::check!(functional_update_field); + // FIXME: This should filter out all completions that do not have the type `Foo` check( r#" //- minicore:default @@ -155,23 +169,20 @@ impl Default for Foo { fn main() { let thing = 1; let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, ..$0 } + let foo2 = Foo { thing, $0 } } "#, expect![[r#" fd ..Default::default() - fn main() fn() - lc foo Foo - lc thing i32 - md core - st Foo - st Foo {…} Foo { foo1: u32, foo2: u32 } - tt Default - bt u32 - kw crate:: - kw self:: + fd foo1 u32 + fd foo2 u32 "#]], ); +} + +#[test] +fn functional_update_one_dot() { + cov_mark::check!(functional_update_one_dot); check( r#" //- minicore:default @@ -183,11 +194,12 @@ impl Default for Foo { fn main() { let thing = 1; let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, ..Default::$0 } + let foo2 = Foo { thing, .$0 } } "#, expect![[r#" - fn default() (as Default) fn() -> Self + fd ..Default::default() + sn .. "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 7303ef8b7..7109c6fd1 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -12,7 +12,7 @@ use crate::RootDatabase; #[derive(Debug)] pub struct ActiveParameter { pub ty: Type, - pub pat: Either, + pub pat: Option>, } impl ActiveParameter { @@ -27,12 +27,12 @@ impl ActiveParameter { return None; } let (pat, ty) = params.swap_remove(idx); - pat.map(|pat| ActiveParameter { ty, pat }) + Some(ActiveParameter { ty, pat }) } pub fn ident(&self) -> Option { - self.pat.as_ref().right().and_then(|param| match param { - ast::Pat::IdentPat(ident) => ident.name(), + self.pat.as_ref().and_then(|param| match param { + Either::Right(ast::Pat::IdentPat(ident)) => ident.name(), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 98b0e9c94..b1ee9b58d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -20,7 +20,7 @@ impl RootDatabase { pub fn apply_change(&mut self, change: Change) { let _p = profile::span("RootDatabase::apply_change"); self.request_cancellation(); - tracing::info!("apply_change {:?}", change); + tracing::trace!("apply_change {:?}", change); if let Some(roots) = &change.roots { let mut local_roots = FxHashSet::default(); let mut library_roots = FxHashSet::default(); @@ -45,7 +45,7 @@ impl RootDatabase { // |=== // | Editor | Action Name // - // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** + // | VS Code | **rust-analyzer: Memory Usage (Clears Database)** // |=== // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index aeaca00ec..6c13c0397 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -127,10 +127,12 @@ impl Definition { } } +// FIXME: IdentClass as a name no longer fits #[derive(Debug)] pub enum IdentClass { NameClass(NameClass), NameRefClass(NameRefClass), + Operator(OperatorClass), } impl IdentClass { @@ -147,6 +149,11 @@ impl IdentClass { .map(IdentClass::NameClass) .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) }, + ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator), + ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator), + ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator), + ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator), + ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator), _ => None, } } @@ -184,6 +191,33 @@ impl IdentClass { res.push(Definition::Local(local_ref)); res.push(Definition::Field(field_ref)); } + IdentClass::Operator( + OperatorClass::Await(func) + | OperatorClass::Prefix(func) + | OperatorClass::Bin(func) + | OperatorClass::Index(func) + | OperatorClass::Try(func), + ) => res.push(Definition::Function(func)), + } + res + } + + pub fn definitions_no_ops(self) -> ArrayVec { + let mut res = ArrayVec::new(); + match self { + IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { + res.push(it) + } + IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => { + res.push(Definition::Local(local_def)); + res.push(Definition::Field(field_ref)); + } + IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it), + IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => { + res.push(Definition::Local(local_ref)); + res.push(Definition::Field(field_ref)); + } + IdentClass::Operator(_) => (), } res } @@ -332,6 +366,52 @@ impl NameClass { } } +#[derive(Debug)] +pub enum OperatorClass { + Await(Function), + Prefix(Function), + Index(Function), + Try(Function), + Bin(Function), +} + +impl OperatorClass { + pub fn classify_await( + sema: &Semantics<'_, RootDatabase>, + await_expr: &ast::AwaitExpr, + ) -> Option { + sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await) + } + + pub fn classify_prefix( + sema: &Semantics<'_, RootDatabase>, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix) + } + + pub fn classify_try( + sema: &Semantics<'_, RootDatabase>, + try_expr: &ast::TryExpr, + ) -> Option { + sema.resolve_try_expr(try_expr).map(OperatorClass::Try) + } + + pub fn classify_index( + sema: &Semantics<'_, RootDatabase>, + index_expr: &ast::IndexExpr, + ) -> Option { + sema.resolve_index_expr(index_expr).map(OperatorClass::Index) + } + + pub fn classify_bin( + sema: &Semantics<'_, RootDatabase>, + bin_expr: &ast::BinExpr, + ) -> Option { + sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin) + } +} + /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a /// reference most of the time, but there are a couple of annoying exceptions. diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index c14182279..9be1d3663 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -7,7 +7,10 @@ use std::cmp::Ordering; use hir::Semantics; use syntax::{ algo, - ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind}, + ast::{ + self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, + PathSegmentKind, + }, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, }; @@ -192,20 +195,24 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { insert_use_(scope, &path, cfg.group, use_item); } -pub fn remove_path_if_in_use_stmt(path: &ast::Path) { +pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option> { // FIXME: improve this if path.parent_path().is_some() { - return; + return None; } - if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) { - if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { - return; - } - if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { - use_.remove(); - return; - } - use_tree.remove(); + let use_tree = path.syntax().parent().and_then(ast::UseTree::cast)?; + if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { + return None; + } + if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { + return Some(Box::new(use_)); + } + Some(Box::new(use_tree)) +} + +pub fn remove_path_if_in_use_stmt(path: &ast::Path) { + if let Some(node) = ast_to_remove_for_path_in_use_stmt(path) { + node.remove(); } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 966bba616..1ec62a842 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -52,6 +52,7 @@ use hir::{ db::{AstDatabase, DefDatabase, HirDatabase}, symbols::FileSymbolKind, }; +use stdx::hash::NoHashHashSet; use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; @@ -118,7 +119,7 @@ impl FileLoader for RootDatabase { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs index 68ad07ee8..75d49ff2f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs @@ -2,7 +2,7 @@ //! representation. use std::{iter, mem}; -use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use syntax::{TextRange, TextSize}; #[derive(Clone, Debug, PartialEq, Eq)] @@ -10,7 +10,7 @@ pub struct LineIndex { /// Offset the the beginning of each line, zero-based pub(crate) newlines: Vec, /// List of non-ASCII characters on each line - pub(crate) utf16_lines: FxHashMap>, + pub(crate) utf16_lines: NoHashHashMap>, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -55,7 +55,7 @@ impl Utf16Char { impl LineIndex { pub fn new(text: &str) -> LineIndex { - let mut utf16_lines = FxHashMap::default(); + let mut utf16_lines = NoHashHashMap::default(); let mut utf16_chars = Vec::new(); let mut newlines = vec![0.into()]; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 517fe3f24..49b81265e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -82,7 +82,7 @@ impl Definition { } /// Textual range of the identifier which will change when renaming this - /// `Definition`. Note that some definitions, like buitin types, can't be + /// `Definition`. Note that some definitions, like builtin types, can't be /// renamed. pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option { let res = match self { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index bd038cdaa..7deffe8e0 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -4,12 +4,12 @@ //! get a super-set of matches. Then, we we confirm each match using precise //! name resolution. -use std::{convert::TryInto, mem, sync::Arc}; +use std::{mem, sync::Arc}; use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; use once_cell::unsync::Lazy; -use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; use crate::{ @@ -20,7 +20,7 @@ use crate::{ #[derive(Debug, Default, Clone)] pub struct UsageSearchResult { - pub references: FxHashMap>, + pub references: NoHashHashMap>, } impl UsageSearchResult { @@ -45,7 +45,7 @@ impl UsageSearchResult { impl IntoIterator for UsageSearchResult { type Item = (FileId, Vec); - type IntoIter = > as IntoIterator>::IntoIter; + type IntoIter = > as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.references.into_iter() @@ -78,17 +78,17 @@ pub enum ReferenceCategory { /// e.g. for things like local variables. #[derive(Clone, Debug)] pub struct SearchScope { - entries: FxHashMap>, + entries: NoHashHashMap>, } impl SearchScope { - fn new(entries: FxHashMap>) -> SearchScope { + fn new(entries: NoHashHashMap>) -> SearchScope { SearchScope { entries } } /// Build a search scope spanning the entire crate graph of files. fn crate_graph(db: &RootDatabase) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); let graph = db.crate_graph(); for krate in graph.iter() { @@ -102,7 +102,7 @@ impl SearchScope { /// Build a search scope spanning all the reverse dependencies of the given crate. fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); for rev_dep in of.transitive_reverse_dependencies(db) { let root_file = rev_dep.root_file(db); let source_root_id = db.file_source_root(root_file); @@ -117,14 +117,12 @@ impl SearchScope { let root_file = of.root_file(db); let source_root_id = db.file_source_root(root_file); let source_root = db.source_root(source_root_id); - SearchScope { - entries: source_root.iter().map(|id| (id, None)).collect::>(), - } + SearchScope { entries: source_root.iter().map(|id| (id, None)).collect() } } /// Build a search scope spanning the given module and all its submodules. fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); let (file_id, range) = { let InFile { file_id, value } = module.definition_source(db); @@ -157,7 +155,7 @@ impl SearchScope { /// Build an empty search scope. pub fn empty() -> SearchScope { - SearchScope::new(FxHashMap::default()) + SearchScope::new(NoHashHashMap::default()) } /// Build a empty search scope spanning the given file. @@ -402,7 +400,9 @@ impl<'a> FindUsages<'a> { .or_else(|| ty.as_builtin().map(|builtin| builtin.name())) }) }; - self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str()) + // We need to unescape the name in case it is written without "r#" in earlier + // editions of Rust where it isn't a keyword. + self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.unescaped().to_smol_str()) } }; let name = match &name { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index 8132c73ef..8e338061d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -3,16 +3,18 @@ //! //! It can be viewed as a dual for `Change`. -use std::{collections::hash_map::Entry, iter}; +use std::{collections::hash_map::Entry, iter, mem}; use base_db::{AnchoredPathBuf, FileId}; -use rustc_hash::FxHashMap; -use stdx::never; -use text_edit::TextEdit; +use stdx::{hash::NoHashHashMap, never}; +use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; +use text_edit::{TextEdit, TextEditBuilder}; + +use crate::SnippetCap; #[derive(Default, Debug, Clone)] pub struct SourceChange { - pub source_file_edits: FxHashMap, + pub source_file_edits: NoHashHashMap, pub file_system_edits: Vec, pub is_snippet: bool, } @@ -21,7 +23,7 @@ impl SourceChange { /// Creates a new SourceChange with the given label /// from the edits. pub fn from_edits( - source_file_edits: FxHashMap, + source_file_edits: NoHashHashMap, file_system_edits: Vec, ) -> Self { SourceChange { source_file_edits, file_system_edits, is_snippet: false } @@ -75,12 +77,141 @@ impl Extend for SourceChange { } } -impl From> for SourceChange { - fn from(source_file_edits: FxHashMap) -> SourceChange { +impl From> for SourceChange { + fn from(source_file_edits: NoHashHashMap) -> SourceChange { SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } } } +pub struct SourceChangeBuilder { + pub edit: TextEditBuilder, + pub file_id: FileId, + pub source_change: SourceChange, + pub trigger_signature_help: bool, + + /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. + pub mutated_tree: Option, +} + +pub struct TreeMutator { + immutable: SyntaxNode, + mutable_clone: SyntaxNode, +} + +impl TreeMutator { + pub fn new(immutable: &SyntaxNode) -> TreeMutator { + let immutable = immutable.ancestors().last().unwrap(); + let mutable_clone = immutable.clone_for_update(); + TreeMutator { immutable, mutable_clone } + } + + pub fn make_mut(&self, node: &N) -> N { + N::cast(self.make_syntax_mut(node.syntax())).unwrap() + } + + pub fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { + let ptr = SyntaxNodePtr::new(node); + ptr.to_node(&self.mutable_clone) + } +} + +impl SourceChangeBuilder { + pub fn new(file_id: FileId) -> SourceChangeBuilder { + SourceChangeBuilder { + edit: TextEdit::builder(), + file_id, + source_change: SourceChange::default(), + trigger_signature_help: false, + mutated_tree: None, + } + } + + pub fn edit_file(&mut self, file_id: FileId) { + self.commit(); + self.file_id = file_id; + } + + fn commit(&mut self) { + if let Some(tm) = self.mutated_tree.take() { + algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) + } + + let edit = mem::take(&mut self.edit).finish(); + if !edit.is_empty() { + self.source_change.insert_source_edit(self.file_id, edit); + } + } + + pub fn make_mut(&mut self, node: N) -> N { + self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node) + } + /// Returns a copy of the `node`, suitable for mutation. + /// + /// Syntax trees in rust-analyzer are typically immutable, and mutating + /// operations panic at runtime. However, it is possible to make a copy of + /// the tree and mutate the copy freely. Mutation is based on interior + /// mutability, and different nodes in the same tree see the same mutations. + /// + /// The typical pattern for an assist is to find specific nodes in the read + /// phase, and then get their mutable couterparts using `make_mut` in the + /// mutable state. + pub fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode { + self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) + } + + /// Remove specified `range` of text. + pub fn delete(&mut self, range: TextRange) { + self.edit.delete(range) + } + /// Append specified `text` at the given `offset` + pub fn insert(&mut self, offset: TextSize, text: impl Into) { + self.edit.insert(offset, text.into()) + } + /// Append specified `snippet` at the given `offset` + pub fn insert_snippet( + &mut self, + _cap: SnippetCap, + offset: TextSize, + snippet: impl Into, + ) { + self.source_change.is_snippet = true; + self.insert(offset, snippet); + } + /// Replaces specified `range` of text with a given string. + pub fn replace(&mut self, range: TextRange, replace_with: impl Into) { + self.edit.replace(range, replace_with.into()) + } + /// Replaces specified `range` of text with a given `snippet`. + pub fn replace_snippet( + &mut self, + _cap: SnippetCap, + range: TextRange, + snippet: impl Into, + ) { + self.source_change.is_snippet = true; + self.replace(range, snippet); + } + pub fn replace_ast(&mut self, old: N, new: N) { + algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) + } + pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into) { + let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; + self.source_change.push_file_system_edit(file_system_edit); + } + pub fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) { + let file_system_edit = FileSystemEdit::MoveFile { src, dst }; + self.source_change.push_file_system_edit(file_system_edit); + } + pub fn trigger_signature_help(&mut self) { + self.trigger_signature_help = true; + } + + pub fn finish(mut self) -> SourceChange { + self.commit(); + mem::take(&mut self.source_change) + } +} + #[derive(Debug, Clone)] pub enum FileSystemEdit { CreateFile { dst: AnchoredPathBuf, initial_contents: String }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs index f54ae6c92..8bc093a85 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs @@ -95,7 +95,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { AS_KW | DYN_KW | IMPL_KW | CONST_KW => { mods.push(do_ws(after, tok)); } - T![;] => { + T![;] if is_next(|it| it != R_CURLY, true) => { if indent > 0 { mods.push(do_indent(after, tok, indent)); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs index 84bde4d44..b890e2b58 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -315,7 +315,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { | ast::Expr::IndexExpr(_) | ast::Expr::Literal(_) | ast::Expr::MacroExpr(_) - | ast::Expr::MacroStmts(_) | ast::Expr::MethodCallExpr(_) | ast::Expr::ParenExpr(_) | ast::Expr::PathExpr(_) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index e221425ed..9b9e21a4d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -15,6 +15,7 @@ itertools = "0.10.3" either = "1.7.0" +serde_json = "1.0.82" profile = { path = "../profile", version = "0.0.0" } stdx = { path = "../stdx", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index d12594a4c..0c92e706b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -7,9 +7,10 @@ pub(crate) fn break_outside_of_loop( ctx: &DiagnosticsContext<'_>, d: &hir::BreakOutsideOfLoop, ) -> Diagnostic { + let construct = if d.is_break { "break" } else { "continue" }; Diagnostic::new( "break-outside-of-loop", - "break outside of loop", + format!("{construct} outside of loop"), ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, ) } @@ -19,11 +20,122 @@ mod tests { use crate::tests::check_diagnostics; #[test] - fn break_outside_of_loop() { + fn outside_of_loop() { check_diagnostics( r#" -fn foo() { break; } - //^^^^^ error: break outside of loop +fn foo() { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop +} +"#, + ); + } + + #[test] + fn try_blocks_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn async_blocks_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn closures_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn blocks_pass_through() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + { + break; + break 'a; + continue; + continue 'a; + } + } +} +"#, + ); + } + + #[test] + fn label_blocks() { + check_diagnostics( + r#" +fn foo() { + 'a: { + break; + //^^^^^ error: break outside of loop + break 'a; + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + } +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs index 97ea5c456..04918891b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -43,7 +43,7 @@ mod tests { use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; pub(crate) fn check(ra_fixture: &str) { - let config = DiagnosticsConfig::default(); + let config = DiagnosticsConfig::test_sample(); check_diagnostics_with_config(config, ra_fixture) } @@ -106,18 +106,17 @@ fn f() { #[test] fn inactive_assoc_item() { - // FIXME these currently don't work, hence the * check( r#" struct Foo; impl Foo { #[cfg(any())] pub fn f() {} - //*************************** weak: code is inactive due to #[cfg] directives + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives } trait Bar { #[cfg(any())] pub fn f() {} - //*************************** weak: code is inactive due to #[cfg] directives + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs new file mode 100644 index 000000000..a21db5b2c --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -0,0 +1,310 @@ +//! This diagnostic provides an assist for creating a struct definition from a JSON +//! example. + +use hir::{PathResolution, Semantics}; +use ide_db::{ + base_db::FileId, + helpers::mod_path_to_ast, + imports::insert_use::{insert_use, ImportScope}, + source_change::SourceChangeBuilder, + RootDatabase, +}; +use itertools::Itertools; +use stdx::{format_to, never}; +use syntax::{ + ast::{self, make}, + SyntaxKind, SyntaxNode, +}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, DiagnosticsConfig, Severity}; + +#[derive(Default)] +struct State { + result: String, + struct_counts: usize, + has_serialize: bool, + has_deserialize: bool, +} + +impl State { + fn generate_new_name(&mut self) -> ast::Name { + self.struct_counts += 1; + make::name(&format!("Struct{}", self.struct_counts)) + } + + fn serde_derive(&self) -> String { + let mut v = vec![]; + if self.has_serialize { + v.push("Serialize"); + } + if self.has_deserialize { + v.push("Deserialize"); + } + match v.as_slice() { + [] => "".to_string(), + [x] => format!("#[derive({x})]\n"), + [x, y] => format!("#[derive({x}, {y})]\n"), + _ => { + never!(); + "".to_string() + } + } + } + + fn build_struct(&mut self, value: &serde_json::Map) -> ast::Type { + let name = self.generate_new_name(); + let ty = make::ty(&name.to_string()); + let strukt = make::struct_( + None, + name, + None, + make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map( + |(name, value)| make::record_field(None, make::name(name), self.type_of(value)), + )) + .into(), + ); + format_to!(self.result, "{}{}\n", self.serde_derive(), strukt); + ty + } + + fn type_of(&mut self, value: &serde_json::Value) -> ast::Type { + match value { + serde_json::Value::Null => make::ty_unit(), + serde_json::Value::Bool(_) => make::ty("bool"), + serde_json::Value::Number(it) => make::ty(if it.is_i64() { "i64" } else { "f64" }), + serde_json::Value::String(_) => make::ty("String"), + serde_json::Value::Array(it) => { + let ty = match it.iter().next() { + Some(x) => self.type_of(x), + None => make::ty_placeholder(), + }; + make::ty(&format!("Vec<{ty}>")) + } + serde_json::Value::Object(x) => self.build_struct(x), + } + } +} + +pub(crate) fn json_in_items( + sema: &Semantics<'_, RootDatabase>, + acc: &mut Vec, + file_id: FileId, + node: &SyntaxNode, + config: &DiagnosticsConfig, +) { + (|| { + if node.kind() == SyntaxKind::ERROR + && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY) + && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY) + { + let node_string = node.to_string(); + if let Ok(it) = serde_json::from_str(&node_string) { + if let serde_json::Value::Object(it) = it { + let import_scope = ImportScope::find_insert_use_container(node, sema)?; + let range = node.text_range(); + let mut edit = TextEdit::builder(); + edit.delete(range); + let mut state = State::default(); + let semantics_scope = sema.scope(node)?; + let scope_resolve = + |it| semantics_scope.speculative_resolve(&make::path_from_text(it)); + let scope_has = |it| scope_resolve(it).is_some(); + let deserialize_resolved = scope_resolve("::serde::Deserialize"); + let serialize_resolved = scope_resolve("::serde::Serialize"); + state.has_deserialize = deserialize_resolved.is_some(); + state.has_serialize = serialize_resolved.is_some(); + state.build_struct(&it); + edit.insert(range.start(), state.result); + acc.push( + Diagnostic::new( + "json-is-not-rust", + "JSON syntax is not valid as a Rust item", + range, + ) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![{ + let mut scb = SourceChangeBuilder::new(file_id); + let scope = match import_scope.clone() { + ImportScope::File(it) => ImportScope::File(scb.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)), + }; + let current_module = semantics_scope.module(); + if !scope_has("Serialize") { + if let Some(PathResolution::Def(it)) = serialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + ) { + insert_use( + &scope, + mod_path_to_ast(&it), + &config.insert_use, + ); + } + } + } + if !scope_has("Deserialize") { + if let Some(PathResolution::Def(it)) = deserialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + ) { + insert_use( + &scope, + mod_path_to_ast(&it), + &config.insert_use, + ); + } + } + } + let mut sc = scb.finish(); + sc.insert_source_edit(file_id, edit.finish()); + fix("convert_json_to_struct", "Convert JSON to struct", sc, range) + }])), + ); + } + } + } + Some(()) + })(); +} + +#[cfg(test)] +mod tests { + use crate::{ + tests::{check_diagnostics_with_config, check_fix, check_no_fix}, + DiagnosticsConfig, + }; + + #[test] + fn diagnostic_for_simple_case() { + let mut config = DiagnosticsConfig::test_sample(); + config.disabled.insert("syntax-error".to_string()); + check_diagnostics_with_config( + config, + r#" + { "foo": "bar" } + // ^^^^^^^^^^^^^^^^ 💡 weak: JSON syntax is not valid as a Rust item +"#, + ); + } + + #[test] + fn types_of_primitives() { + check_fix( + r#" + //- /lib.rs crate:lib deps:serde + use serde::Serialize; + + fn some_garbage() { + + } + + {$0 + "foo": "bar", + "bar": 2.3, + "baz": null, + "bay": 57, + "box": true + } + //- /serde.rs crate:serde + + pub trait Serialize { + fn serialize() -> u8; + } + "#, + r#" + use serde::Serialize; + + fn some_garbage() { + + } + + #[derive(Serialize)] + struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } + + "#, + ); + } + + #[test] + fn nested_structs() { + check_fix( + r#" + {$0 + "foo": "bar", + "bar": { + "kind": "Object", + "value": {} + } + } + "#, + r#" + struct Struct3{ } + struct Struct2{ kind: String, value: Struct3 } + struct Struct1{ bar: Struct2, foo: String } + + "#, + ); + } + + #[test] + fn arrays() { + check_fix( + r#" + //- /lib.rs crate:lib deps:serde + { + "of_string": ["foo", "2", "x"], $0 + "of_object": [{ + "x": 10, + "y": 20 + }, { + "x": 10, + "y": 20 + }], + "nested": [[[2]]], + "empty": [] + } + //- /serde.rs crate:serde + + pub trait Serialize { + fn serialize() -> u8; + } + pub trait Deserialize { + fn deserialize() -> u8; + } + "#, + r#" + use serde::Serialize; + use serde::Deserialize; + + #[derive(Serialize, Deserialize)] + struct Struct2{ x: i64, y: i64 } + #[derive(Serialize, Deserialize)] + struct Struct1{ empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } + + "#, + ); + } + + #[test] + fn no_emit_outside_of_item_position() { + check_no_fix( + r#" + fn foo() { + let json = {$0 + "foo": "bar", + "bar": { + "kind": "Object", + "value": {} + } + }; + } + "#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index d6a66dc15..43ff4ed5a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -79,7 +79,7 @@ pub macro panic { #[test] fn include_macro_should_allow_empty_content() { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); // FIXME: This is a false-positive, the file is actually linked in via // `include!` macro diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 9e66fbfb7..c24430ce6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -750,7 +750,7 @@ fn main() { enum Foo { A } fn main() { // FIXME: this should not bail out but current behavior is such as the old algorithm. - // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. + // ExprValidator::validate_match(..) checks types of top level patterns incorrectly. match Foo::A { ref _x => {} Foo::A => {} @@ -947,6 +947,50 @@ fn f() { ); } + mod rust_unstable { + use super::*; + + #[test] + fn rfc_1872_exhaustive_patterns() { + check_diagnostics_no_bails( + r" +//- minicore: option, result +#![feature(exhaustive_patterns)] +enum Void {} +fn test() { + match None:: { None => () } + match Result::::Ok(2) { Ok(_) => () } + match Result::::Ok(2) { Ok(_) => () } + match (2, loop {}) {} + match Result::::Ok(loop {}) {} + match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919 + // ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty +}", + ); + } + + #[test] + fn rfc_1872_private_uninhabitedness() { + check_diagnostics_no_bails( + r" +//- minicore: option +//- /lib.rs crate:lib +#![feature(exhaustive_patterns)] +pub struct PrivatelyUninhabited { private_field: Void } +enum Void {} +fn test_local(x: Option) { + match x {} +} // ^ error: missing match arm: `None` not covered +//- /main.rs crate:main deps:lib +#![feature(exhaustive_patterns)] +fn test(x: Option) { + match x {} + // ^ error: missing match arm: `None` and `Some(_)` not covered +}", + ); + } + } + mod false_negatives { //! The implementation of match checking here is a work in progress. As we roll this out, we //! prefer false negatives to false positives (ideally there would be no false positives). This diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index e032c578f..a80299106 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -68,7 +68,7 @@ fn missing_record_expr_field_fixes( } let new_field = make::record_field( None, - make::name(&record_expr_field.field_name()?.text()), + make::name(&record_expr_field.field_name()?.ident_token()?.text()), make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), ); @@ -109,7 +109,7 @@ fn missing_record_expr_field_fixes( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix}; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; #[test] fn no_such_field_diagnostics() { @@ -277,6 +277,20 @@ struct Foo { bar: i32, pub(crate) baz: bool } +"#, + ) + } + + #[test] + fn test_tuple_field_on_record_struct() { + check_no_fix( + r#" +struct Struct {} +fn main() { + Struct { + 0$0: 0 + } +} "#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 41abaa836..61e63ea7a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -50,6 +50,7 @@ mod handlers { pub(crate) mod field_shorthand; pub(crate) mod useless_braces; pub(crate) mod unlinked_file; + pub(crate) mod json_is_not_rust; } #[cfg(test)] @@ -59,6 +60,7 @@ use hir::{diagnostics::AnyDiagnostic, InFile, Semantics}; use ide_db::{ assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, base_db::{FileId, FileRange, SourceDatabase}, + imports::insert_use::InsertUseConfig, label::Label, source_change::SourceChange, FxHashSet, RootDatabase, @@ -139,13 +141,37 @@ impl Default for ExprFillDefaultMode { } } -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct DiagnosticsConfig { pub proc_macros_enabled: bool, pub proc_attr_macros_enabled: bool, pub disable_experimental: bool, pub disabled: FxHashSet, pub expr_fill_default: ExprFillDefaultMode, + // FIXME: We may want to include a whole `AssistConfig` here + pub insert_use: InsertUseConfig, +} + +impl DiagnosticsConfig { + pub fn test_sample() -> Self { + use hir::PrefixKind; + use ide_db::imports::insert_use::ImportGranularity; + + Self { + proc_macros_enabled: Default::default(), + proc_attr_macros_enabled: Default::default(), + disable_experimental: Default::default(), + disabled: Default::default(), + expr_fill_default: Default::default(), + insert_use: InsertUseConfig { + granularity: ImportGranularity::Preserve, + enforce_granularity: false, + prefix_kind: PrefixKind::Plain, + group: false, + skip_glob_imports: false, + }, + } + } } struct DiagnosticsContext<'a> { @@ -172,9 +198,12 @@ pub fn diagnostics( }), ); - for node in parse.tree().syntax().descendants() { + let parse = sema.parse(file_id); + + for node in parse.syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); + handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config); } let module = sema.to_module_def(file_id); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 7312bca32..729619cfd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -37,7 +37,7 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { let after = trim_indent(ra_fixture_after); let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let mut conf = DiagnosticsConfig::default(); + let mut conf = DiagnosticsConfig::test_sample(); conf.expr_fill_default = ExprFillDefaultMode::Default; let diagnostic = super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id) @@ -69,7 +69,7 @@ pub(crate) fn check_no_fix(ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); let diagnostic = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_position.file_id, ) @@ -82,7 +82,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { let (db, file_id) = RootDatabase::with_single_file(ra_fixture); let diagnostics = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_id, ); @@ -91,7 +91,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { #[track_caller] pub(crate) fn check_diagnostics(ra_fixture: &str) { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("inactive-code".to_string()); check_diagnostics_with_config(config, ra_fixture) } @@ -127,7 +127,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur #[test] fn test_disabled_diagnostics() { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("unresolved-module".into()); let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); @@ -137,7 +137,7 @@ fn test_disabled_diagnostics() { let diagnostics = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_id, ); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml index d36dd02d4..73314e0f3 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml @@ -20,6 +20,7 @@ parser = { path = "../parser", version = "0.0.0" } syntax = { path = "../syntax", version = "0.0.0" } ide-db = { path = "../ide-db", version = "0.0.0" } hir = { path = "../hir", version = "0.0.0" } +stdx = { path = "../stdx", version = "0.0.0" } [dev-dependencies] test-utils = { path = "../test-utils" } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index a5e24daa9..d9834ee63 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -57,7 +57,7 @@ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Structural Search Replace** +// | VS Code | **rust-analyzer: Structural Search Replace** // |=== // // Also available as an assist, by writing a comment containing the structural @@ -86,11 +86,9 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc use crate::{errors::bail, matching::MatchFailureReason}; use hir::Semantics; -use ide_db::{ - base_db::{FileId, FilePosition, FileRange}, - FxHashMap, -}; +use ide_db::base_db::{FileId, FilePosition, FileRange}; use resolving::ResolvedRule; +use stdx::hash::NoHashHashMap; use syntax::{ast, AstNode, SyntaxNode, TextRange}; use text_edit::TextEdit; @@ -170,9 +168,9 @@ impl<'db> MatchFinder<'db> { } /// Finds matches for all added rules and returns edits for all found matches. - pub fn edits(&self) -> FxHashMap { + pub fn edits(&self) -> NoHashHashMap { use ide_db::base_db::SourceDatabaseExt; - let mut matches_by_file = FxHashMap::default(); + let mut matches_by_file = NoHashHashMap::default(); for m in self.matches().matches { matches_by_file .entry(m.range.file_id) diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index a18a6bea9..5a8cda8fb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -7,7 +7,7 @@ use ide_db::{ search::FileReference, FxIndexMap, RootDatabase, }; -use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange}; +use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange}; use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; @@ -79,7 +79,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio let file = sema.parse(file_id); let file = file.syntax(); let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - NAME => 1, + IDENT => 1, _ => 0, })?; let mut calls = CallLocations::default(); diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index 582e9fe7e..92ce26b42 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -184,10 +184,10 @@ pub(crate) fn resolve_doc_path_for_def( Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns), Definition::Macro(it) => it.resolve_doc_path(db, link, ns), Definition::Field(it) => it.resolve_doc_path(db, link, ns), + Definition::SelfType(it) => it.resolve_doc_path(db, link, ns), Definition::BuiltinAttr(_) | Definition::ToolModule(_) | Definition::BuiltinType(_) - | Definition::SelfType(_) | Definition::Local(_) | Definition::GenericParam(_) | Definition::Label(_) diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index efa8551a0..93252339c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -19,7 +19,7 @@ pub struct ExpandedMacro { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Expand macro recursively** +// | VS Code | **rust-analyzer: Expand macro recursively** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] @@ -32,7 +32,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< _ => 0, })?; - // due to how Rust Analyzer works internally, we need to special case derive attributes, + // due to how rust-analyzer works internally, we need to special case derive attributes, // otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand: // ``` // #[attr] diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index d9c97751c..36a648fe4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, mem::discriminant}; +use std::mem::discriminant; use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}; use hir::{AsAssocItem, AssocItem, Semantics}; @@ -39,7 +39,11 @@ pub(crate) fn goto_definition( | T![super] | T![crate] | T![Self] - | COMMENT => 2, + | COMMENT => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, + T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, })?; @@ -1628,6 +1632,156 @@ macro_rules! foo { } foo!(bar$0); +"#, + ); + } + + #[test] + fn goto_await_poll() { + check( + r#" +//- minicore: future + +struct MyFut; + +impl core::future::Future for MyFut { + type Output = (); + + fn poll( + //^^^^ + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_> + ) -> std::task::Poll + { + () + } +} + +fn f() { + MyFut.await$0; +} +"#, + ); + } + + #[test] + fn goto_await_into_future_poll() { + check( + r#" +//- minicore: future + +struct Futurable; + +impl core::future::IntoFuture for Futurable { + type IntoFuture = MyFut; +} + +struct MyFut; + +impl core::future::Future for MyFut { + type Output = (); + + fn poll( + //^^^^ + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_> + ) -> std::task::Poll + { + () + } +} + +fn f() { + Futurable.await$0; +} +"#, + ); + } + + #[test] + fn goto_try_op() { + check( + r#" +//- minicore: try + +struct Struct; + +impl core::ops::Try for Struct { + fn branch( + //^^^^^^ + self + ) {} +} + +fn f() { + Struct?$0; +} +"#, + ); + } + + #[test] + fn goto_index_op() { + check( + r#" +//- minicore: index + +struct Struct; + +impl core::ops::Index for Struct { + fn index( + //^^^^^ + self + ) {} +} + +fn f() { + Struct[0]$0; +} +"#, + ); + } + + #[test] + fn goto_prefix_op() { + check( + r#" +//- minicore: deref + +struct Struct; + +impl core::ops::Deref for Struct { + fn deref( + //^^^^^ + self + ) {} +} + +fn f() { + $0*Struct; +} +"#, + ); + } + + #[test] + fn goto_bin_op() { + check( + r#" +//- minicore: add + +struct Struct; + +impl core::ops::Add for Struct { + fn add( + //^^^ + self + ) {} +} + +fn f() { + Struct +$0 Struct; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 04b51c839..b3f711b6b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -30,7 +30,7 @@ pub(crate) fn goto_implementation( let original_token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind { - IDENT | T![self] => 1, + IDENT | T![self] | INT_NUMBER => 1, _ => 0, })?; let range = original_token.text_range(); diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index f2d7029ea..f190da326 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -333,7 +333,8 @@ fn cover_range(r0: Option, r1: Option) -> Option, token: SyntaxToken) -> FxHashSet { sema.descend_into_macros(token) .into_iter() - .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions)) + .filter_map(|token| IdentClass::classify_token(sema, &token)) + .map(IdentClass::definitions_no_ops) .flatten() .collect() } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 59c97f2dc..3687b597f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -9,7 +9,7 @@ use either::Either; use hir::{HasSource, Semantics}; use ide_db::{ base_db::FileRange, - defs::{Definition, IdentClass}, + defs::{Definition, IdentClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, FxIndexSet, RootDatabase, @@ -27,6 +27,7 @@ use crate::{ pub struct HoverConfig { pub links_in_hover: bool, pub documentation: Option, + pub keywords: bool, } impl HoverConfig { @@ -101,7 +102,10 @@ pub(crate) fn hover( let offset = range.start(); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3, + IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, @@ -116,6 +120,8 @@ pub(crate) fn hover( } let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); + // prefer descending the same token kind in attribute expansions, in normal macros text + // equivalency is more important let descended = if in_attr { [sema.descend_into_macros_with_kind_preference(original_token.clone())].into() } else { @@ -136,6 +142,11 @@ pub(crate) fn hover( .filter_map(|token| { let node = token.parent()?; let class = IdentClass::classify_token(sema, token)?; + if let IdentClass::Operator(OperatorClass::Await(_)) = class { + // It's better for us to fall back to the keyword hover here, + // rendering poll is very confusing + return None; + } Some(class.definitions().into_iter().zip(iter::once(node).cycle())) }) .flatten() @@ -232,10 +243,12 @@ fn hover_type_fallback( token: &SyntaxToken, original_token: &SyntaxToken, ) -> Option> { - let node = token - .parent_ancestors() - .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?; + let node = + token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| { + ast::Expr::can_cast(n.kind()) + || ast::Pat::can_cast(n.kind()) + || ast::Type::can_cast(n.kind()) + })?; let expr_or_pat = match_ast! { match node { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 6c50a4e6a..c5c50d88d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -2,12 +2,13 @@ use std::fmt::Display; use either::Either; -use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo}; +use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo}; use ide_db::{ base_db::SourceDatabase, defs::Definition, famous_defs::FamousDefs, generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, + syntax_helpers::insert_whitespace_into_node, RootDatabase, }; use itertools::Itertools; @@ -230,7 +231,7 @@ pub(super) fn keyword( config: &HoverConfig, token: &SyntaxToken, ) -> Option { - if !token.kind().is_keyword() || !config.documentation.is_some() { + if !token.kind().is_keyword() || !config.documentation.is_some() || !config.keywords { return None; } let parent = token.parent()?; @@ -350,10 +351,24 @@ pub(super) fn definition( let body = it.eval(db); match body { Ok(x) => Some(format!("{}", x)), - Err(_) => it.value(db).map(|x| format!("{}", x)), + Err(_) => { + let source = it.source(db)?; + let mut body = source.value.body()?.syntax().clone(); + if source.file_id.is_macro() { + body = insert_whitespace_into_node::insert_ws_into(body); + } + Some(body.to_string()) + } + } + }), + Definition::Static(it) => label_value_and_docs(db, it, |it| { + let source = it.source(db)?; + let mut body = source.value.body()?.syntax().clone(); + if source.file_id.is_macro() { + body = insert_whitespace_into_node::insert_ws_into(body); } + Some(body.to_string()) }), - Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)), Definition::Trait(it) => label_and_docs(db, it), Definition::TypeAlias(it) => label_and_docs(db, it), Definition::BuiltinType(it) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 867d1f54d..4b8b47783 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -8,7 +8,11 @@ fn check_hover_no_result(ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap(); @@ -20,7 +24,11 @@ fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -37,7 +45,11 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -54,7 +66,11 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::PlainText) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::PlainText), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -71,7 +87,11 @@ fn check_actions(ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id, range: position.range_or_empty() }, ) .unwrap() @@ -83,7 +103,11 @@ fn check_hover_range(ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, range, ) .unwrap() @@ -95,7 +119,11 @@ fn check_hover_range_no_results(ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, range, ) .unwrap(); @@ -5051,3 +5079,95 @@ fn f() { ```"#]], ); } + +#[test] +fn hover_deref() { + check( + r#" +//- minicore: deref + +struct Struct(usize); + +impl core::ops::Deref for Struct { + type Target = usize; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn f() { + $0*Struct(0); +} +"#, + expect![[r#" + *** + + ```rust + test::Struct + ``` + + ```rust + fn deref(&self) -> &Self::Target + ``` + "#]], + ); +} + +#[test] +fn static_const_macro_expanded_body() { + check( + r#" +macro_rules! m { + () => { + pub const V: i8 = { + let e = 123; + f(e) // Prevent const eval from evaluating this constant, we want to print the body's code. + }; + }; +} +m!(); +fn main() { $0V; } +"#, + expect![[r#" + *V* + + ```rust + test + ``` + + ```rust + pub const V: i8 = { + let e = 123; + f(e) + } + ``` + "#]], + ); + check( + r#" +macro_rules! m { + () => { + pub static V: i8 = { + let e = 123; + }; + }; +} +m!(); +fn main() { $0V; } +"#, + expect![[r#" + *V* + + ```rust + test + ``` + + ```rust + pub static V: i8 = { + let e = 123; + } + ``` + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 5aae669aa..d1b1d2c33 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -1,3 +1,5 @@ +use std::fmt; + use either::Either; use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo}; use ide_db::{ @@ -69,7 +71,7 @@ pub enum InlayKind { pub struct InlayHint { pub range: TextRange, pub kind: InlayKind, - pub label: String, + pub label: InlayHintLabel, pub tooltip: Option, } @@ -80,6 +82,83 @@ pub enum InlayTooltip { HoverOffset(FileId, TextSize), } +pub struct InlayHintLabel { + pub parts: Vec, +} + +impl InlayHintLabel { + pub fn as_simple_str(&self) -> Option<&str> { + match &*self.parts { + [part] => part.as_simple_str(), + _ => None, + } + } + + pub fn prepend_str(&mut self, s: &str) { + match &mut *self.parts { + [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text), + _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }), + } + } + + pub fn append_str(&mut self, s: &str) { + match &mut *self.parts { + [.., part] if part.as_simple_str().is_some() => part.text.push_str(s), + _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }), + } + } +} + +impl From for InlayHintLabel { + fn from(s: String) -> Self { + Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] } + } +} + +impl fmt::Display for InlayHintLabel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.parts.iter().map(|part| &part.text).format("")) + } +} + +impl fmt::Debug for InlayHintLabel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(&self.parts).finish() + } +} + +pub struct InlayHintLabelPart { + pub text: String, + /// Source location represented by this label part. The client will use this to fetch the part's + /// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location + /// refers to (not necessarily the location itself). + /// When setting this, no tooltip must be set on the containing hint, or VS Code will display + /// them both. + pub linked_location: Option, +} + +impl InlayHintLabelPart { + pub fn as_simple_str(&self) -> Option<&str> { + match self { + Self { text, linked_location: None } => Some(text), + _ => None, + } + } +} + +impl fmt::Debug for InlayHintLabelPart { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.as_simple_str() { + Some(string) => string.fmt(f), + None => f + .debug_struct("InlayHintLabelPart") + .field("text", &self.text) + .field("linked_location", &self.linked_location) + .finish(), + } + } +} + // Feature: Inlay Hints // // rust-analyzer shows additional information inline with the source code. @@ -100,7 +179,7 @@ pub enum InlayTooltip { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Toggle inlay hints* +// | VS Code | **rust-analyzer: Toggle inlay hints* // |=== // // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] @@ -192,10 +271,10 @@ fn closing_brace_hints( ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; - let name = |it: ast::Name| it.syntax().text_range().start(); + let name = |it: ast::Name| it.syntax().text_range(); let mut closing_token; - let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { + let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { closing_token = item_list.r_curly_token()?; let parent = item_list.syntax().parent()?; @@ -205,11 +284,11 @@ fn closing_brace_hints( let imp = sema.to_def(&imp)?; let ty = imp.self_ty(sema.db); let trait_ = imp.trait_(sema.db); - - (match trait_ { + let hint_text = match trait_ { Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)), None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), - }, None) + }; + (hint_text, None) }, ast::Trait(tr) => { (format!("trait {}", tr.name()?), tr.name().map(name)) @@ -253,7 +332,7 @@ fn closing_brace_hints( ( format!("{}!", mac.path()?), - mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()), + mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()), ) } else { return None; @@ -278,11 +357,12 @@ fn closing_brace_hints( return None; } + let linked_location = name_range.map(|range| FileRange { file_id, range }); acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBraceHint, - label, - tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)), + label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] }, + tooltip: None, // provided by label part location }); None @@ -311,7 +391,7 @@ fn implicit_static_hints( acc.push(InlayHint { range: t.text_range(), kind: InlayKind::LifetimeHint, - label: "'static".to_owned(), + label: "'static".to_owned().into(), tooltip: Some(InlayTooltip::String("Elided static lifetime".into())), }); } @@ -329,10 +409,10 @@ fn fn_lifetime_fn_hints( return None; } - let mk_lt_hint = |t: SyntaxToken, label| InlayHint { + let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { range: t.text_range(), kind: InlayKind::LifetimeHint, - label, + label: label.into(), tooltip: Some(InlayTooltip::String("Elided lifetime".into())), }; @@ -486,7 +566,8 @@ fn fn_lifetime_fn_hints( "{}{}", allocated_lifetimes.iter().format(", "), if is_empty { "" } else { ", " } - ), + ) + .into(), tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), }); } @@ -535,7 +616,8 @@ fn closure_ret_hints( range: param_list.syntax().text_range(), kind: InlayKind::ClosureReturnTypeHint, label: hint_iterator(sema, &famous_defs, config, &ty) - .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()), + .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()) + .into(), tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())), }); Some(()) @@ -562,7 +644,7 @@ fn reborrow_hints( acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ImplicitReborrowHint, - label: label.to_string(), + label: label.to_string().into(), tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())), }); Some(()) @@ -620,9 +702,9 @@ fn chaining_hints( acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ChainingHint, - label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| { - ty.display_truncated(sema.db, config.max_length).to_string() - }), + label: hint_iterator(sema, &famous_defs, config, &ty) + .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()) + .into(), tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())), }); } @@ -674,7 +756,7 @@ fn param_name_hints( InlayHint { range, kind: InlayKind::ParameterHint, - label: param_name, + label: param_name.into(), tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())), } }); @@ -705,7 +787,7 @@ fn binding_mode_hints( acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, - label: r.to_string(), + label: r.to_string().into(), tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); @@ -720,7 +802,7 @@ fn binding_mode_hints( acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, - label: bm.to_string(), + label: bm.to_string().into(), tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); } @@ -772,7 +854,7 @@ fn bind_pat_hints( None => pat.syntax().text_range(), }, kind: InlayKind::TypeHint, - label, + label: label.into(), tooltip: pat .name() .map(|it| it.syntax().text_range()) @@ -1910,7 +1992,7 @@ impl Vec { pub struct Box {} trait Display {} -trait Sync {} +auto trait Sync {} fn main() { // The block expression wrapping disables the constructor hint hiding logic @@ -2223,7 +2305,9 @@ fn main() { InlayHint { range: 147..172, kind: ChainingHint, - label: "B", + label: [ + "B", + ], tooltip: Some( HoverRanged( FileId( @@ -2236,7 +2320,9 @@ fn main() { InlayHint { range: 147..154, kind: ChainingHint, - label: "A", + label: [ + "A", + ], tooltip: Some( HoverRanged( FileId( @@ -2294,7 +2380,9 @@ fn main() { InlayHint { range: 143..190, kind: ChainingHint, - label: "C", + label: [ + "C", + ], tooltip: Some( HoverRanged( FileId( @@ -2307,7 +2395,9 @@ fn main() { InlayHint { range: 143..179, kind: ChainingHint, - label: "B", + label: [ + "B", + ], tooltip: Some( HoverRanged( FileId( @@ -2350,7 +2440,9 @@ fn main() { InlayHint { range: 246..283, kind: ChainingHint, - label: "B>", + label: [ + "B>", + ], tooltip: Some( HoverRanged( FileId( @@ -2363,7 +2455,9 @@ fn main() { InlayHint { range: 246..265, kind: ChainingHint, - label: "A>", + label: [ + "A>", + ], tooltip: Some( HoverRanged( FileId( @@ -2408,7 +2502,9 @@ fn main() { InlayHint { range: 174..241, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2421,7 +2517,9 @@ fn main() { InlayHint { range: 174..224, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2434,7 +2532,9 @@ fn main() { InlayHint { range: 174..206, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2447,7 +2547,9 @@ fn main() { InlayHint { range: 174..189, kind: ChainingHint, - label: "&mut MyIter", + label: [ + "&mut MyIter", + ], tooltip: Some( HoverRanged( FileId( @@ -2489,7 +2591,9 @@ fn main() { InlayHint { range: 124..130, kind: TypeHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2502,7 +2606,9 @@ fn main() { InlayHint { range: 145..185, kind: ChainingHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2515,7 +2621,9 @@ fn main() { InlayHint { range: 145..168, kind: ChainingHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2528,7 +2636,9 @@ fn main() { InlayHint { range: 222..228, kind: ParameterHint, - label: "self", + label: [ + "self", + ], tooltip: Some( HoverOffset( FileId( diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs index 08621adde..edc48e84d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs @@ -28,7 +28,7 @@ pub struct JoinLinesConfig { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Join lines** +// | VS Code | **rust-analyzer: Join lines** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index dd108fa79..055233081 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -82,12 +82,12 @@ pub use crate::{ highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{ - ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, - LifetimeElisionHints, ReborrowHints, + ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, + InlayTooltip, LifetimeElisionHints, ReborrowHints, }, join_lines::JoinLinesConfig, markup::Markup, - moniker::{MonikerKind, MonikerResult, PackageInformation}, + moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation}, move_item::Direction, navigation_target::NavigationTarget, prime_caches::ParallelPrimeCachesProgress, @@ -98,7 +98,7 @@ pub use crate::{ static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData}, syntax_highlighting::{ tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, - HlRange, + HighlightConfig, HlRange, }, }; pub use hir::{Documentation, Semantics}; @@ -517,8 +517,12 @@ impl Analysis { } /// Computes syntax highlighting for the given file - pub fn highlight(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) + pub fn highlight( + &self, + highlight_config: HighlightConfig, + file_id: FileId, + ) -> Cancellable> { + self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None)) } /// Computes all ranges to highlight for a given item in a file. @@ -533,9 +537,13 @@ impl Analysis { } /// Computes syntax highlighting for the given file range. - pub fn highlight_range(&self, frange: FileRange) -> Cancellable> { + pub fn highlight_range( + &self, + highlight_config: HighlightConfig, + frange: FileRange, + ) -> Cancellable> { self.with_db(|db| { - syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) + syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range)) }) } diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs index da70cecdd..6e8a6d020 100644 --- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Find matching brace** +// | VS Code | **rust-analyzer: Find matching brace** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 6bab9fa1e..600a52630 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -13,17 +13,39 @@ use syntax::{AstNode, SyntaxKind::*, T}; use crate::{doc_links::token_as_doc_comment, RangeInfo}; +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum MonikerDescriptorKind { + Namespace, + Type, + Term, + Method, + TypeParameter, + Parameter, + Macro, + Meta, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MonikerDescriptor { + pub name: Name, + pub desc: MonikerDescriptorKind, +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonikerIdentifier { - crate_name: String, - path: Vec, + pub crate_name: String, + pub description: Vec, } impl ToString for MonikerIdentifier { fn to_string(&self) -> String { match self { - MonikerIdentifier { path, crate_name } => { - format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::")) + MonikerIdentifier { description, crate_name } => { + format!( + "{}::{}", + crate_name, + description.iter().map(|x| x.name.to_string()).join("::") + ) } } } @@ -42,6 +64,12 @@ pub struct MonikerResult { pub package_information: PackageInformation, } +impl MonikerResult { + pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option { + def_to_moniker(db, def, from_crate) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PackageInformation { pub name: String, @@ -90,7 +118,7 @@ pub(crate) fn moniker( .descend_into_macros(original_token.clone()) .into_iter() .filter_map(|token| { - IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { + IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| { it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate)) }) }) @@ -105,13 +133,23 @@ pub(crate) fn def_to_moniker( def: Definition, from_crate: Crate, ) -> Option { - if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) { + if matches!( + def, + Definition::GenericParam(_) + | Definition::Label(_) + | Definition::DeriveHelper(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) + ) { return None; } + let module = def.module(db)?; let krate = module.krate(); - let mut path = vec![]; - path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db))); + let mut description = vec![]; + description.extend(module.path_to_root(db).into_iter().filter_map(|x| { + Some(MonikerDescriptor { name: x.name(db)?, desc: MonikerDescriptorKind::Namespace }) + })); // Handle associated items within a trait if let Some(assoc) = def.as_assoc_item(db) { @@ -120,31 +158,98 @@ pub(crate) fn def_to_moniker( AssocItemContainer::Trait(trait_) => { // Because different traits can have functions with the same name, // we have to include the trait name as part of the moniker for uniqueness. - path.push(trait_.name(db)); + description.push(MonikerDescriptor { + name: trait_.name(db), + desc: MonikerDescriptorKind::Type, + }); } AssocItemContainer::Impl(impl_) => { // Because a struct can implement multiple traits, for implementations // we add both the struct name and the trait name to the path if let Some(adt) = impl_.self_ty(db).as_adt() { - path.push(adt.name(db)); + description.push(MonikerDescriptor { + name: adt.name(db), + desc: MonikerDescriptorKind::Type, + }); } if let Some(trait_) = impl_.trait_(db) { - path.push(trait_.name(db)); + description.push(MonikerDescriptor { + name: trait_.name(db), + desc: MonikerDescriptorKind::Type, + }); } } } } if let Definition::Field(it) = def { - path.push(it.parent_def(db).name(db)); + description.push(MonikerDescriptor { + name: it.parent_def(db).name(db), + desc: MonikerDescriptorKind::Type, + }); } - path.push(def.name(db)?); + let name_desc = match def { + // These are handled by top-level guard (for performance). + Definition::GenericParam(_) + | Definition::Label(_) + | Definition::DeriveHelper(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) => return None, + + Definition::Local(local) => { + if !local.is_param(db) { + return None; + } + + MonikerDescriptor { name: local.name(db), desc: MonikerDescriptorKind::Parameter } + } + Definition::Macro(m) => { + MonikerDescriptor { name: m.name(db), desc: MonikerDescriptorKind::Macro } + } + Definition::Function(f) => { + MonikerDescriptor { name: f.name(db), desc: MonikerDescriptorKind::Method } + } + Definition::Variant(v) => { + MonikerDescriptor { name: v.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::Const(c) => { + MonikerDescriptor { name: c.name(db)?, desc: MonikerDescriptorKind::Term } + } + Definition::Trait(trait_) => { + MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::TypeAlias(ta) => { + MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter } + } + Definition::Module(m) => { + MonikerDescriptor { name: m.name(db)?, desc: MonikerDescriptorKind::Namespace } + } + Definition::BuiltinType(b) => { + MonikerDescriptor { name: b.name(), desc: MonikerDescriptorKind::Type } + } + Definition::SelfType(imp) => MonikerDescriptor { + name: imp.self_ty(db).as_adt()?.name(db), + desc: MonikerDescriptorKind::Type, + }, + Definition::Field(it) => { + MonikerDescriptor { name: it.name(db), desc: MonikerDescriptorKind::Term } + } + Definition::Adt(adt) => { + MonikerDescriptor { name: adt.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::Static(s) => { + MonikerDescriptor { name: s.name(db), desc: MonikerDescriptorKind::Meta } + } + }; + + description.push(name_desc); + Some(MonikerResult { identifier: MonikerIdentifier { crate_name: krate.display_name(db)?.crate_name().to_string(), - path, + description, }, kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import }, package_information: { diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs index 02e9fb8b5..ffc4bdd7d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs @@ -19,8 +19,8 @@ pub enum Direction { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Move item up** -// | VS Code | **Rust Analyzer: Move item down** +// | VS Code | **rust-analyzer: Move item up** +// | VS Code | **rust-analyzer: Move item down** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs index 9b1f48044..8f3cc8687 100644 --- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs +++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs @@ -18,7 +18,7 @@ use crate::NavigationTarget; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Locate parent module** +// | VS Code | **rust-analyzer: Locate parent module** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] diff --git a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs index 296270036..87b3ef380 100644 --- a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs @@ -12,8 +12,9 @@ use ide_db::{ salsa::{Database, ParallelDatabase, Snapshot}, Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt, }, - FxHashSet, FxIndexMap, + FxIndexMap, }; +use stdx::hash::NoHashHashSet; use crate::RootDatabase; @@ -141,7 +142,7 @@ pub(crate) fn parallel_prime_caches( } } -fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet { +fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> NoHashHashSet { // We're only interested in the workspace crates and the `ImportMap`s of their direct // dependencies, though in practice the latter also compute the `DefMap`s. // We don't prime transitive dependencies because they're generally not visible in diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 1a6beec18..99614b645 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -14,8 +14,9 @@ use ide_db::{ base_db::FileId, defs::{Definition, NameClass, NameRefClass}, search::{ReferenceCategory, SearchScope, UsageSearchResult}, - FxHashMap, RootDatabase, + RootDatabase, }; +use stdx::hash::NoHashHashMap; use syntax::{ algo::find_node_at_offset, ast::{self, HasName}, @@ -29,7 +30,7 @@ use crate::{FilePosition, NavigationTarget, TryToNav}; #[derive(Debug, Clone)] pub struct ReferenceSearchResult { pub declaration: Option, - pub references: FxHashMap)>>, + pub references: NoHashHashMap)>>, } #[derive(Debug, Clone)] diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index bec770ed9..0181c6b8e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -116,7 +116,7 @@ impl Runnable { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Run** +// | VS Code | **rust-analyzer: Run** // |=== // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { @@ -202,7 +202,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Peek related tests** +// | VS Code | **rust-analyzer: Peek related tests** // |=== pub(crate) fn related_tests( db: &RootDatabase, @@ -373,11 +373,13 @@ pub(crate) fn runnable_impl( let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.type_arguments().peekable(); let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db)))) + format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db)))) } else { String::new() }; - let test_id = TestId::Path(format!("{}{}", adt_name, params)); + let mut test_id = format!("{}{}", adt_name, params); + test_id.retain(|c| c != ' '); + let test_id = TestId::Path(test_id); Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg }) } @@ -441,10 +443,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { format_to!( path, "<{}>", - ty_args.format_with(", ", |ty, cb| cb(&ty.display(db))) + ty_args.format_with(",", |ty, cb| cb(&ty.display(db))) ); } format_to!(path, "::{}", def_name); + path.retain(|c| c != ' '); return Some(path); } } @@ -2067,13 +2070,23 @@ mod tests { $0 struct Foo; +/// ``` +/// ``` impl Foo { /// ```rust /// ```` fn t() {} } + +/// ``` +/// ``` +impl Foo, ()> { + /// ``` + /// ``` + fn t() {} +} "#, - &[DocTest], + &[DocTest, DocTest, DocTest, DocTest], expect![[r#" [ Runnable { @@ -2082,12 +2095,64 @@ impl Foo { file_id: FileId( 0, ), - full_range: 47..85, + full_range: 20..103, + focus_range: 47..56, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 63..101, + name: "t", + }, + kind: DocTest { + test_id: Path( + "Foo::t", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 105..188, + focus_range: 126..146, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo,()>", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 153..186, name: "t", }, kind: DocTest { test_id: Path( - "Foo::t", + "Foo,()>::t", ), }, cfg: None, @@ -2160,4 +2225,190 @@ macro_rules! foo { "#]], ); } + + #[test] + fn test_paths_with_raw_ident() { + check( + r#" +//- /lib.rs +$0 +mod r#mod { + #[test] + fn r#fn() {} + + /// ``` + /// ``` + fn r#for() {} + + /// ``` + /// ``` + struct r#struct(r#type); + + /// ``` + /// ``` + impl r#struct { + /// ``` + /// ``` + fn r#fn() {} + } + + enum r#enum {} + impl r#struct { + /// ``` + /// ``` + fn r#fn() {} + } + + trait r#trait {} + + /// ``` + /// ``` + impl r#trait for r#struct {} +} +"#, + &[TestMod, Test, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..461, + focus_range: 5..10, + name: "r#mod", + kind: Module, + description: "mod r#mod", + }, + kind: TestMod { + path: "r#mod", + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..41, + focus_range: 32..36, + name: "r#fn", + kind: Function, + }, + kind: Test { + test_id: Path( + "r#mod::r#fn", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 47..84, + name: "r#for", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#for", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 90..146, + name: "r#struct", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 152..266, + focus_range: 189..205, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "r#struct", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 216..260, + name: "r#fn", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct::r#fn", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 323..367, + name: "r#fn", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct::r#fn", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 401..459, + focus_range: 445..456, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "r#struct", + ), + }, + cfg: None, + }, + ] + "#]], + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs index 15cb89dcc..2d8662764 100644 --- a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs +++ b/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs @@ -12,7 +12,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Shuffle Crate Graph** +// | VS Code | **rust-analyzer: Shuffle Crate Graph** // |=== pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { let crate_graph = db.crate_graph(); diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index d74b64041..9e5eb9095 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -130,8 +130,11 @@ impl StaticIndex<'_> { syntax::NodeOrToken::Node(_) => None, syntax::NodeOrToken::Token(x) => Some(x), }); - let hover_config = - HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }; + let hover_config = HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }; let tokens = tokens.filter(|token| { matches!( token.kind(), @@ -204,7 +207,7 @@ impl StaticIndex<'_> { fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); if let Some(&[x]) = def.as_deref() { return Some(x); } else { diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs index 3191870eb..f4d038744 100644 --- a/src/tools/rust-analyzer/crates/ide/src/status.rs +++ b/src/tools/rust-analyzer/crates/ide/src/status.rs @@ -1,4 +1,4 @@ -use std::{fmt, iter::FromIterator, sync::Arc}; +use std::{fmt, sync::Arc}; use hir::{ExpandResult, MacroFile}; use ide_db::base_db::{ @@ -29,7 +29,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Status** +// | VS Code | **rust-analyzer: Status** // |=== // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 3fb49b45d..50371d620 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -14,7 +14,7 @@ mod html; mod tests; use hir::{Name, Semantics}; -use ide_db::{FxHashMap, RootDatabase}; +use ide_db::{FxHashMap, RootDatabase, SymbolKind}; use syntax::{ ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T, }; @@ -24,7 +24,7 @@ use crate::{ escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter, tags::Highlight, }, - FileId, HlMod, HlTag, + FileId, HlMod, HlOperator, HlPunct, HlTag, }; pub(crate) use html::highlight_as_html; @@ -36,6 +36,26 @@ pub struct HlRange { pub binding_hash: Option, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct HighlightConfig { + /// Whether to highlight strings + pub strings: bool, + /// Whether to highlight punctuation + pub punctuation: bool, + /// Whether to specialize punctuation highlights + pub specialize_punctuation: bool, + /// Whether to highlight operator + pub operator: bool, + /// Whether to specialize operator highlights + pub specialize_operator: bool, + /// Whether to inject highlights into doc comments + pub inject_doc_comment: bool, + /// Whether to highlight the macro call bang + pub macro_bang: bool, + /// Whether to highlight unresolved things be their syntax + pub syntactic_name_ref_highlighting: bool, +} + // Feature: Semantic Syntax Highlighting // // rust-analyzer highlights the code semantically. @@ -155,9 +175,9 @@ pub struct HlRange { // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] pub(crate) fn highlight( db: &RootDatabase, + config: HighlightConfig, file_id: FileId, range_to_highlight: Option, - syntactic_name_ref_highlighting: bool, ) -> Vec { let _p = profile::span("highlight"); let sema = Semantics::new(db); @@ -183,26 +203,18 @@ pub(crate) fn highlight( Some(it) => it.krate(), None => return hl.to_vec(), }; - traverse( - &mut hl, - &sema, - file_id, - &root, - krate, - range_to_highlight, - syntactic_name_ref_highlighting, - ); + traverse(&mut hl, &sema, config, file_id, &root, krate, range_to_highlight); hl.to_vec() } fn traverse( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, file_id: FileId, root: &SyntaxNode, krate: hir::Crate, range_to_highlight: TextRange, - syntactic_name_ref_highlighting: bool, ) { let is_unlinked = sema.to_module_def(file_id).is_none(); let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); @@ -323,9 +335,11 @@ fn traverse( Enter(it) => it, Leave(NodeOrToken::Token(_)) => continue, Leave(NodeOrToken::Node(node)) => { - // Doc comment highlighting injection, we do this when leaving the node - // so that we overwrite the highlighting of the doc comment itself. - inject::doc_comment(hl, sema, file_id, &node); + if config.inject_doc_comment { + // Doc comment highlighting injection, we do this when leaving the node + // so that we overwrite the highlighting of the doc comment itself. + inject::doc_comment(hl, sema, config, file_id, &node); + } continue; } }; @@ -400,7 +414,8 @@ fn traverse( let string_to_highlight = ast::String::cast(descended_token.clone()); if let Some((string, expanded_string)) = string.zip(string_to_highlight) { if string.is_raw() { - if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() { + if inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some() + { continue; } } @@ -421,7 +436,7 @@ fn traverse( sema, krate, &mut bindings_shadow_count, - syntactic_name_ref_highlighting, + config.syntactic_name_ref_highlighting, name_like, ), NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)), @@ -439,6 +454,29 @@ fn traverse( // something unresolvable. FIXME: There should be a way to prevent that continue; } + + // apply config filtering + match &mut highlight.tag { + HlTag::StringLiteral if !config.strings => continue, + // If punctuation is disabled, make the macro bang part of the macro call again. + tag @ HlTag::Punctuation(HlPunct::MacroBang) => { + if !config.macro_bang { + *tag = HlTag::Symbol(SymbolKind::Macro); + } else if !config.specialize_punctuation { + *tag = HlTag::Punctuation(HlPunct::Other); + } + } + HlTag::Punctuation(_) if !config.punctuation => continue, + tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { + *tag = HlTag::Punctuation(HlPunct::Other); + } + HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => continue, + tag @ HlTag::Operator(_) if !config.specialize_operator => { + *tag = HlTag::Operator(HlOperator::Other); + } + _ => (), + } + if inside_attribute { highlight |= HlMod::Attribute } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs index 9777c014c..e91fd7f12 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs @@ -5,7 +5,10 @@ use oorandom::Rand32; use stdx::format_to; use syntax::AstNode; -use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; +use crate::{ + syntax_highlighting::{highlight, HighlightConfig}, + FileId, RootDatabase, +}; pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { let parse = db.parse(file_id); @@ -20,7 +23,21 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo ) } - let hl_ranges = highlight(db, file_id, None, false); + let hl_ranges = highlight( + db, + HighlightConfig { + strings: true, + punctuation: true, + specialize_punctuation: true, + specialize_operator: true, + operator: true, + inject_doc_comment: true, + macro_bang: true, + syntactic_name_ref_highlighting: false, + }, + file_id, + None, + ); let text = parse.tree().syntax().to_string(); let mut buf = String::new(); buf.push_str(STYLE); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index f376f9fda..9139528c7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -15,13 +15,14 @@ use syntax::{ use crate::{ doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def}, - syntax_highlighting::{highlights::Highlights, injector::Injector}, + syntax_highlighting::{highlights::Highlights, injector::Injector, HighlightConfig}, Analysis, HlMod, HlRange, HlTag, RootDatabase, }; pub(super) fn ra_fixture( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, literal: &ast::String, expanded: &ast::String, ) -> Option<()> { @@ -63,7 +64,13 @@ pub(super) fn ra_fixture( let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { + for mut hl_range in analysis + .highlight( + HighlightConfig { syntactic_name_ref_highlighting: false, ..config }, + tmp_file_id, + ) + .unwrap() + { for range in inj.map_range_up(hl_range.range) { if let Some(range) = literal.map_range_up(range) { hl_range.range = range; @@ -86,6 +93,7 @@ const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, src_file_id: FileId, node: &SyntaxNode, ) { @@ -206,7 +214,14 @@ pub(super) fn doc_comment( let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) { + if let Ok(ranges) = analysis.with_db(|db| { + super::highlight( + db, + HighlightConfig { syntactic_name_ref_highlighting: true, ..config }, + tmp_file_id, + None, + ) + }) { for HlRange { range, highlight, binding_hash } in ranges { for range in inj.map_range_up(range) { hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index 5262770f3..3949f1189 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -199,7 +199,7 @@ impl fmt::Display for HlTag { } impl HlMod { - const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ + const ALL: &'static [HlMod; 19] = &[ HlMod::Associated, HlMod::Async, HlMod::Attribute, @@ -296,7 +296,7 @@ impl Highlight { Highlight { tag, mods: HlMods::default() } } pub fn is_empty(&self) -> bool { - self.tag == HlTag::None && self.mods == HlMods::default() + self.tag == HlTag::None && self.mods.is_empty() } } @@ -330,6 +330,10 @@ impl ops::BitOr for Highlight { } impl HlMods { + pub fn is_empty(&self) -> bool { + self.0 == 0 + } + pub fn contains(self, m: HlMod) -> bool { self.0 & m.mask() == m.mask() } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index a747b4bc1..eef5baea9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -56,7 +56,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd bar: bool, } -/// This is an impl with a code block. +/// This is an impl of [`Foo`] with a code block. /// /// ``` /// fn foo() { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index 99be7c664..46cc667fc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -4,7 +4,18 @@ use expect_test::{expect_file, ExpectFile}; use ide_db::SymbolKind; use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; -use crate::{fixture, FileRange, HlTag, TextRange}; +use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange}; + +const HL_CONFIG: HighlightConfig = HighlightConfig { + strings: true, + punctuation: true, + specialize_punctuation: true, + specialize_operator: true, + operator: true, + inject_doc_comment: true, + macro_bang: true, + syntactic_name_ref_highlighting: false, +}; #[test] fn attributes() { @@ -613,7 +624,7 @@ struct Foo { bar: bool, } -/// This is an impl with a code block. +/// This is an impl of [`Foo`] with a code block. /// /// ``` /// fn foo() { @@ -958,7 +969,7 @@ pub struct Struct; #[test] #[cfg_attr( - all(unix, not(target_pointer_width = "64")), + not(all(unix, target_pointer_width = "64")), ignore = "depends on `DefaultHasher` outputs" )] fn test_rainbow_highlighting() { @@ -996,7 +1007,10 @@ struct Foo { // The "x" let highlights = &analysis - .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }) + .highlight_range( + HL_CONFIG, + FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }, + ) .unwrap(); assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public"); @@ -1011,7 +1025,7 @@ macro_rules! test {} }"# .trim(), ); - let _ = analysis.highlight(file_id).unwrap(); + let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); } /// Highlights the code given by the `ra_fixture` argument, renders the @@ -1035,7 +1049,7 @@ fn benchmark_syntax_highlighting_long_struct() { let hash = { let _pt = bench("syntax highlighting long struct"); analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1061,7 +1075,7 @@ fn syntax_highlighting_not_quadratic() { let time = Instant::now(); let hash = analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1086,7 +1100,7 @@ fn benchmark_syntax_highlighting_parser() { let hash = { let _pt = bench("syntax highlighting parser"); analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs index 9003e7cd3..4256fea0f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Show Syntax Tree** +// | VS Code | **rust-analyzer: Show Syntax Tree** // |=== // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] pub(crate) fn syntax_tree( diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs index 51291a645..17a1e385b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs @@ -3,8 +3,9 @@ use std::sync::Arc; use dot::{Id, LabelText}; use ide_db::{ base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}, - FxHashSet, RootDatabase, + RootDatabase, }; +use stdx::hash::NoHashHashSet; // Feature: View Crate Graph // @@ -16,7 +17,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Crate Graph** +// | VS Code | **rust-analyzer: View Crate Graph** // |=== pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result { let crate_graph = db.crate_graph(); @@ -41,7 +42,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result, - crates_to_render: FxHashSet, + crates_to_render: NoHashHashSet, } type Edge<'a> = (CrateId, &'a Dependency); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs index 7312afe53..d2bbbf6d2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs @@ -1,4 +1,4 @@ -use hir::{Function, Semantics}; +use hir::{DefWithBody, Semantics}; use ide_db::base_db::FilePosition; use ide_db::RootDatabase; use syntax::{algo::find_node_at_offset, ast, AstNode}; @@ -8,7 +8,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode}; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Hir** +// | VS Code | **rust-analyzer: View Hir** // |=== // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { @@ -19,8 +19,12 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option { let sema = Semantics::new(db); let source_file = sema.parse(position.file_id); - let function = find_node_at_offset::(source_file.syntax(), position.offset)?; - - let function: Function = sema.to_def(&function)?; - Some(function.debug_hir(db)) + let item = find_node_at_offset::(source_file.syntax(), position.offset)?; + let def: DefWithBody = match item { + ast::Item::Fn(it) => sema.to_def(&it)?.into(), + ast::Item::Const(it) => sema.to_def(&it)?.into(), + ast::Item::Static(it) => sema.to_def(&it)?.into(), + _ => return None, + }; + Some(def.debug_hir(db)) } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs index 3dc03085d..9c1f93356 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs @@ -9,7 +9,7 @@ use ide_db::RootDatabase; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Debug ItemTree** +// | VS Code | **rust-analyzer: Debug ItemTree** // |=== pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { db.file_item_tree(file_id.into()).pretty_print() diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index 5020e9aba..c1aa14d6b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -321,7 +321,7 @@ struct MatchState<'t> { /// The KleeneOp of this sequence if we are in a repetition. sep_kind: Option, - /// Number of tokens of seperator parsed + /// Number of tokens of separator parsed sep_parsed: Option, /// Matched meta variables bindings diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index aca6ecd42..e4c56565b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -228,16 +228,7 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { } let spacing = match conv.peek().map(|next| next.kind(conv)) { - Some(kind) - if !kind.is_trivia() - && kind.is_punct() - && kind != T!['['] - && kind != T!['{'] - && kind != T!['('] - && kind != UNDERSCORE => - { - tt::Spacing::Joint - } + Some(kind) if !kind.is_trivia() => tt::Spacing::Joint, _ => tt::Spacing::Alone, }; let char = match token.to_char(conv) { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index e7402104e..dcaceade6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -564,8 +564,10 @@ fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike // test record_lit // fn foo() { // S {}; +// S { x }; // S { x, y: 32, }; // S { x, y: 32, ..Default::default() }; +// S { x: ::default() }; // TupleStruct { 0: 1 }; // } pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { @@ -582,16 +584,26 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { match p.current() { IDENT | INT_NUMBER => { - // test_err record_literal_before_ellipsis_recovery + // test_err record_literal_missing_ellipsis_recovery // fn main() { - // S { field ..S::default() } + // S { S::default() } // } - if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { - name_ref_or_index(p); - p.expect(T![:]); + if p.nth_at(1, T![::]) { + m.abandon(p); + p.expect(T![..]); + expr(p); + } else { + // test_err record_literal_before_ellipsis_recovery + // fn main() { + // S { field ..S::default() } + // } + if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { + name_ref_or_index(p); + p.expect(T![:]); + } + expr(p); + m.complete(p, RECORD_EXPR_FIELD); } - expr(p); - m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { m.abandon(p); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 8de5d33a1..5dc9c6c82 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -118,6 +118,11 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { Mode::Use => {} Mode::Type => { + // test typepathfn_with_coloncolon + // type F = Start::(Middle) -> (Middle)::End; + if p.at(T![::]) && p.nth_at(2, T!['(']) { + p.bump(T![::]); + } // test path_fn_trait_args // type F = Box ()>; if p.at(T!['(']) { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index 4cbf10306..bc1224af9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -13,6 +13,8 @@ pub(super) const PATTERN_FIRST: TokenSet = T![.], ])); +const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]])); + pub(crate) fn pattern(p: &mut Parser<'_>) { pattern_r(p, PAT_RECOVERY_SET); } @@ -75,6 +77,16 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // Some(1..) => () // } // + // match () { + // S { a: 0 } => (), + // S { a: 1.. } => (), + // } + // + // match () { + // [0] => (), + // [1..] => (), + // } + // // match (10 as u8, 5 as u8) { // (0, _) => (), // (1.., _) => () @@ -88,11 +100,27 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { let m = lhs.precede(p); p.bump(range_op); - // `0 .. =>` or `let 0 .. =` or `Some(0 .. )` - // ^ ^ ^ - if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) { + // testing if we're at one of the following positions: + // `0 .. =>` + // ^ + // `let 0 .. =` + // ^ + // `let 0..: _ =` + // ^ + // (1.., _) + // ^ + // `Some(0 .. )` + // ^ + // `S { t: 0.. }` + // ^ + // `[0..]` + // ^ + if matches!(p.current(), T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']']) { // test half_open_range_pat - // fn f() { let 0 .. = 1u32; } + // fn f() { + // let 0 .. = 1u32; + // let 0..: _ = 1u32; + // } } else { atom_pat(p, recovery_set); } @@ -202,6 +230,7 @@ fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker { // let S(_) = (); // let S(_,) = (); // let S(_, .. , x) = (); +// let S(| a) = (); // } fn tuple_pat_fields(p: &mut Parser<'_>) { assert!(p.at(T!['('])); @@ -337,6 +366,7 @@ fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker { // let (a,) = (); // let (..) = (); // let () = (); +// let (| a | a, | b) = ((),()); // } fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(p.at(T!['('])); @@ -347,13 +377,13 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { let mut has_rest = false; while !p.at(EOF) && !p.at(T![')']) { has_pat = true; - if !p.at_ts(PATTERN_FIRST) { + if !p.at_ts(PAT_TOP_FIRST) { p.error("expected a pattern"); break; } has_rest |= p.at(T![..]); - pattern(p); + pattern_top(p); if !p.at(T![')']) { has_comma = true; p.expect(T![,]); @@ -367,6 +397,7 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { // test slice_pat // fn main() { // let [a, b, ..] = []; +// let [| a, ..] = []; // } fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(p.at(T!['['])); @@ -379,12 +410,12 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { while !p.at(EOF) && !p.at(ket) { - if !p.at_ts(PATTERN_FIRST) { + if !p.at_ts(PAT_TOP_FIRST) { p.error("expected a pattern"); break; } - pattern(p); + pattern_top(p); if !p.at(ket) { p.expect(T![,]); } diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 628fa745e..c84f45f1f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -262,33 +262,117 @@ pub enum SyntaxKind { use self::SyntaxKind::*; impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW - | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW - | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW - | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW - | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW - | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW - | RAW_KW | MACRO_RULES_KW => true, - _ => false, - } + matches!( + self, + AS_KW + | ASYNC_KW + | AWAIT_KW + | BOX_KW + | BREAK_KW + | CONST_KW + | CONTINUE_KW + | CRATE_KW + | DYN_KW + | ELSE_KW + | ENUM_KW + | EXTERN_KW + | FALSE_KW + | FN_KW + | FOR_KW + | IF_KW + | IMPL_KW + | IN_KW + | LET_KW + | LOOP_KW + | MACRO_KW + | MATCH_KW + | MOD_KW + | MOVE_KW + | MUT_KW + | PUB_KW + | REF_KW + | RETURN_KW + | SELF_KW + | SELF_TYPE_KW + | STATIC_KW + | STRUCT_KW + | SUPER_KW + | TRAIT_KW + | TRUE_KW + | TRY_KW + | TYPE_KW + | UNSAFE_KW + | USE_KW + | WHERE_KW + | WHILE_KW + | YIELD_KW + | AUTO_KW + | DEFAULT_KW + | EXISTENTIAL_KW + | UNION_KW + | RAW_KW + | MACRO_RULES_KW + ) } pub fn is_punct(self) -> bool { - match self { - SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK - | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS - | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON - | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ - | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2 - | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true, - _ => false, - } + matches!( + self, + SEMICOLON + | COMMA + | L_PAREN + | R_PAREN + | L_CURLY + | R_CURLY + | L_BRACK + | R_BRACK + | L_ANGLE + | R_ANGLE + | AT + | POUND + | TILDE + | QUESTION + | DOLLAR + | AMP + | PIPE + | PLUS + | STAR + | SLASH + | CARET + | PERCENT + | UNDERSCORE + | DOT + | DOT2 + | DOT3 + | DOT2EQ + | COLON + | COLON2 + | EQ + | EQ2 + | FAT_ARROW + | BANG + | NEQ + | MINUS + | THIN_ARROW + | LTEQ + | GTEQ + | PLUSEQ + | MINUSEQ + | PIPEEQ + | AMPEQ + | CARETEQ + | SLASHEQ + | STAREQ + | PERCENTEQ + | AMP2 + | PIPE2 + | SHL + | SHR + | SHLEQ + | SHREQ + ) } pub fn is_literal(self) -> bool { - match self { - INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true, - _ => false, - } + matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING) } pub fn from_keyword(ident: &str) -> Option { let kw = match ident { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast new file mode 100644 index 000000000..0c5b618e6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast @@ -0,0 +1,43 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 19: expected DOT2 diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs new file mode 100644 index 000000000..1b594e8ab --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs @@ -0,0 +1,3 @@ +fn main() { + S { S::default() } +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast index 235a9d7f4..dff72ba88 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast @@ -37,6 +37,29 @@ SOURCE_FILE L_BRACK "[" R_BRACK "]" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + SLICE_PAT + L_BRACK "[" + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + COMMA "," + WHITESPACE " " + REST_PAT + DOT2 ".." + R_BRACK "]" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ARRAY_EXPR + L_BRACK "[" + R_BRACK "]" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs index 7955973b9..855ba89b1 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs @@ -1,3 +1,4 @@ fn main() { let [a, b, ..] = []; + let [| a, ..] = []; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast index 3cdaf32b5..55baf2fdc 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast @@ -100,6 +100,29 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_STRUCT_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + L_PAREN "(" + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs index 0dfe63629..8ec6f4ca9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs @@ -3,4 +3,5 @@ fn foo() { let S(_) = (); let S(_,) = (); let S(_, .. , x) = (); + let S(| a) = (); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast index 44c967e8d..cfef5d3f9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast @@ -172,6 +172,122 @@ SOURCE_FILE WHITESPACE "\n " R_CURLY "}" WHITESPACE "\n\n " + EXPR_STMT + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + RECORD_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_PAT_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_PAT_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "0" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + RECORD_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_PAT_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_PAT_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "1" + DOT2 ".." + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n\n " + EXPR_STMT + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + SLICE_PAT + L_BRACK "[" + LITERAL_PAT + LITERAL + INT_NUMBER "0" + R_BRACK "]" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + SLICE_PAT + L_BRACK "[" + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "1" + DOT2 ".." + R_BRACK "]" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n\n " MATCH_EXPR MATCH_KW "match" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs index 6c586a895..2411d5109 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs @@ -11,6 +11,16 @@ fn main() { Some(1..) => () } + match () { + S { a: 0 } => (), + S { a: 1.. } => (), + } + + match () { + [0] => (), + [1..] => (), + } + match (10 as u8, 5 as u8) { (0, _) => (), (1.., _) => () diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast index 9997d0ae3..00948c322 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast @@ -24,6 +24,26 @@ SOURCE_FILE R_CURLY "}" SEMICOLON ";" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT RECORD_EXPR PATH @@ -100,6 +120,35 @@ SOURCE_FILE R_CURLY "}" SEMICOLON ";" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "x" + COLON ":" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT RECORD_EXPR PATH diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs index 6285e5549..86411fbb7 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs @@ -1,6 +1,8 @@ fn foo() { S {}; + S { x }; S { x, y: 32, }; S { x, y: 32, ..Default::default() }; + S { x: ::default() }; TupleStruct { 0: 1 }; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast index cebe98c43..1a01e0f69 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast @@ -85,6 +85,46 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_PAT + L_PAREN "(" + PIPE "|" + WHITESPACE " " + OR_PAT + IDENT_PAT + NAME + IDENT "a" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + COMMA "," + WHITESPACE " " + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "b" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs index ba719879d..fbd7f48f6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs @@ -3,4 +3,5 @@ fn main() { let (a,) = (); let (..) = (); let () = (); + let (| a | a, | b) = ((),()); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast index 3d3587a70..4b401b60d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast @@ -11,7 +11,7 @@ SOURCE_FILE BLOCK_EXPR STMT_LIST L_CURLY "{" - WHITESPACE " " + WHITESPACE "\n " LET_STMT LET_KW "let" WHITESPACE " " @@ -27,6 +27,25 @@ SOURCE_FILE LITERAL INT_NUMBER "1u32" SEMICOLON ";" - WHITESPACE " " + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "0" + DOT2 ".." + COLON ":" + WHITESPACE " " + INFER_TYPE + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1u32" + SEMICOLON ";" + WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs index 1360eda05..c9386a221 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs @@ -1 +1,4 @@ -fn f() { let 0 .. = 1u32; } +fn f() { + let 0 .. = 1u32; + let 0..: _ = 1u32; +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast new file mode 100644 index 000000000..b47a5a5c1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast @@ -0,0 +1,43 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Start" + COLON2 "::" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Middle" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PAREN_TYPE + L_PAREN "(" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Middle" + R_PAREN ")" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "End" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs new file mode 100644 index 000000000..8efd93a7f --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs @@ -0,0 +1 @@ +type F = Start::(Middle) -> (Middle)::End; diff --git a/src/tools/rust-analyzer/crates/paths/src/lib.rs b/src/tools/rust-analyzer/crates/paths/src/lib.rs index 025093f4a..6ae23ac84 100644 --- a/src/tools/rust-analyzer/crates/paths/src/lib.rs +++ b/src/tools/rust-analyzer/crates/paths/src/lib.rs @@ -106,6 +106,14 @@ impl AsRef for AbsPath { } } +impl ToOwned for AbsPath { + type Owned = AbsPathBuf; + + fn to_owned(&self) -> Self::Owned { + AbsPathBuf(self.0.to_owned()) + } +} + impl<'a> TryFrom<&'a Path> for &'a AbsPath { type Error = &'a Path; fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> { diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index d7010e825..a3ea05f4a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -60,7 +60,7 @@ impl MacroDylib { let info = version::read_dylib_info(&path)?; if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info); + let msg = format!("proc-macro {} built by {:#?} is not supported by rust-analyzer, please update your Rust version.", path.display(), info); return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 8437444e1..268a03bb5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -35,10 +35,7 @@ //! as we don't have bincode in Cargo.toml yet, lets stick with serde_json for //! the time being. -use std::{ - collections::{HashMap, VecDeque}, - convert::TryInto, -}; +use std::collections::{HashMap, VecDeque}; use serde::{Deserialize, Serialize}; use tt::TokenId; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 5746eac0b..e39026ac7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -24,7 +24,6 @@ tt = { path = "../tt", version = "0.0.0" } mbe = { path = "../mbe", version = "0.0.0" } paths = { path = "../paths", version = "0.0.0" } proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" } -crossbeam = "0.8.1" [dev-dependencies] expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs index 4a07f2277..a405497f3 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs @@ -157,7 +157,7 @@ impl From for TokenStream { } /// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } @@ -165,7 +165,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let mut builder = bridge::client::TokenStreamBuilder::new(); streams.into_iter().for_each(|stream| builder.push(stream.0)); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs index ebdfca00d..b1e982f47 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs @@ -12,7 +12,6 @@ use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::{ascii, vec::IntoIter}; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs index c50a16bf4..7ab1f421d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs @@ -207,7 +207,7 @@ impl ConcatStreamsHelper { } /// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } @@ -215,7 +215,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let iter = streams.into_iter(); let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs index 05a565fbf..ed49cc759 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs @@ -12,7 +12,6 @@ use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::{ascii, vec::IntoIter}; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs deleted file mode 100644 index 9d56f0eaf..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Proc macro ABI. - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub use ra_server::TokenStream; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = - attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone())); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs deleted file mode 100644 index 48030f8d8..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut u8, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - #[inline] - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } - } -} - -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - #[inline] - pub(super) fn new() -> Self { - Self::default() - } - - #[inline] - pub(super) fn clear(&mut self) { - self.len = 0; - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - #[inline] - pub(super) fn extend_from_array(&mut self, xs: &[u8; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn push(&mut self, v: u8) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - #[inline] - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs deleted file mode 100644 index 22bda8ba5..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Client-side types. - -use super::*; - -use std::marker::PhantomData; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - _marker: PhantomData, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Span { - pub(crate) fn def_site() -> Span { - Bridge::with(|bridge| bridge.globals.def_site) - } - - pub(crate) fn call_site() -> Span { - Bridge::with(|bridge| bridge.globals.call_site) - } - - pub(crate) fn mixed_site() -> Span { - Bridge::with(|bridge| bridge.globals.mixed_site) - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut buf = bridge.cached_buffer.take(); - - buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); - - buf = bridge.dispatch.call(buf); - - let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - - bridge.cached_buffer = buf; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// Provided globals for this macro expansion. - globals: ExpnGlobals, -} - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut *state) - }) - }) - } -} - -impl Bridge<'_> { - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) -} - -/// A client-side RPC entry-point, which may be using a different `proc_macro` -/// from the one used by the server, but can be invoked compatibly. -/// -/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters -/// decorate the `Client` with the RPC "interface" of the entry-point, but -/// do not themselves participate in ABI, at all, only facilitate type-checking. -/// -/// E.g. `Client` is the common proc macro interface, -/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`, -/// indicating that the RPC input and output will be serialized token streams, -/// and forcing the use of APIs that take/return `S::TokenStream`, server-side. -#[repr(C)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - - pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer, - - pub(super) _marker: PhantomData O>, -} - -impl Copy for Client {} -impl Clone for Client { - fn clone(&self) -> Self { - *self - } -} - -fn maybe_install_panic_hook(force_show_panics: bool) { - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - config: BridgeConfig<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - let BridgeConfig { input: mut buf, dispatch, force_show_panics, .. } = config; - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - maybe_install_panic_hook(force_show_panics); - - let reader = &mut &buf[..]; - let (globals, input) = <(ExpnGlobals, A)>::decode(reader, &mut ()); - - // Put the buffer we used for input back in the `Bridge` for requests. - let new_state = - BridgeState::Connected(Bridge { cached_buffer: buf.take(), dispatch, globals }); - - BRIDGE_STATE.with(|state| { - state.set(new_state, || { - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - buf.clear(); - Err::<(), _>(e).encode(&mut buf, &mut ()); - }); - buf -} - -impl Client { - pub const fn expand1( - f: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - }), - _marker: PhantomData, - } - } -} - -impl Client<(super::super::TokenStream, super::super::TokenStream), super::super::TokenStream> { - pub const fn expand2( - f: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - }), - _marker: PhantomData, - } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client, - }, - - Attr { - name: &'static str, - client: Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub const fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub const fn attr( - name: &'static str, - expand: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub const fn bang( - name: &'static str, - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs deleted file mode 100644 index d371ae3ce..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -use std::marker::PhantomData; - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(*mut Env, A) -> R, - env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - // - // The `'a` lifetime parameter represents the lifetime of `Env`. - _marker: PhantomData<*mut &'a mut ()>, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs deleted file mode 100644 index c219a9465..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::{BuildHasher, Hash}; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -/// A store that associates values of type `T` with numeric handles. A value can -/// be looked up using its handle. -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -// HACK(eddyb) deterministic `std::collections::hash_map::RandomState` replacement -// that doesn't require adding any dependencies to `proc_macro` (like `rustc-hash`). -#[derive(Clone)] -struct NonRandomState; - -impl BuildHasher for NonRandomState { - type Hasher = std::collections::hash_map::DefaultHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - Self::Hasher::new() - } -} - -/// Like `OwnedStore`, but avoids storing any value more than once. -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { - owned: OwnedStore::new(counter), - interner: HashMap::with_hasher(NonRandomState), - } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs deleted file mode 100644 index ffd440793..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,493 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream - ) -> Vec>; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] -mod selfless_reify; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// Configuration for establishing an active connection between a server and a -/// client. The server creates the bridge config (`run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` field -/// of `client::Client`. The client constructs a local `Bridge` from the config -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct BridgeConfig<'a> { - /// Buffer used to pass initial input to the client. - input: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Vec { - type Unmarked = Vec; - fn mark(unmarked: Self::Unmarked) -> Self { - // Should be a no-op due to std's in-place collect optimizations. - unmarked.into_iter().map(T::mark).collect() - } -} -impl Unmark for Vec { - type Unmarked = Vec; - fn unmark(self) -> Self::Unmarked { - // Should be a no-op due to std's in-place collect optimizations. - self.into_iter().map(T::unmark).collect() - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - u8, - usize, - Delimiter, - Level, - LineColumn, - Spacing, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -macro_rules! mark_compound { - (struct $name:ident <$($T:ident),+> { $($field:ident),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - $name { - $($field: Mark::mark(unmarked.$field)),* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - $name { - $($field: Unmark::unmark(self.$field)),* - } - } - } - }; - (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - $($name::$variant $(($field))? => { - $name::$variant $((Mark::mark($field)))? - })* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - match self { - $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? - })* - } - } - } - } -} - -macro_rules! compound_traits { - ($($t:tt)*) => { - rpc_encode_decode!($($t)*); - mark_compound!($($t)*); - }; -} - -compound_traits!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -compound_traits!( - enum Option { - Some(t), - None, - } -); - -compound_traits!( - enum Result { - Ok(t), - Err(e), - } -); - -#[derive(Copy, Clone)] -pub struct DelimSpan { - pub open: Span, - pub close: Span, - pub entire: Span, -} - -impl DelimSpan { - pub fn from_single(span: Span) -> Self { - DelimSpan { open: span, close: span, entire: span } - } -} - -compound_traits!(struct DelimSpan { open, close, entire }); - -#[derive(Clone)] -pub struct Group { - pub delimiter: Delimiter, - pub stream: Option, - pub span: DelimSpan, -} - -compound_traits!(struct Group { delimiter, stream, span }); - -#[derive(Clone)] -pub struct Punct { - pub ch: u8, - pub joint: bool, - pub span: Span, -} - -compound_traits!(struct Punct { ch, joint, span }); - -#[derive(Clone)] -pub enum TokenTree { - Group(Group), - Punct(Punct), - Ident(Ident), - Literal(Literal), -} - -compound_traits!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); - -/// Globals provided alongside the initial inputs for a macro expansion. -/// Provides values such as spans which are used frequently to avoid RPC. -#[derive(Clone)] -pub struct ExpnGlobals { - pub def_site: Span, - pub call_site: Span, - pub mixed_site: Span, -} - -compound_traits!( - struct ExpnGlobals { def_site, call_site, mixed_site } -); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs deleted file mode 100644 index e9d7a46c0..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - for x in self { - x.encode(w, s); - } - } -} - -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(T::decode(r, s)); - } - vec - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index 2cde1f65a..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub const fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs deleted file mode 100644 index 907ad256e..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Abstraction for creating `fn` pointers from any callable that *effectively* -//! has the equivalent of implementing `Default`, even if the compiler neither -//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers) -//! other than those with absolutely no captures. -//! -//! More specifically, for a closure-like type to be "effectively `Default`": -//! * it must be a ZST (zero-sized type): no information contained within, so -//! that `Default`'s return value (if it were implemented) is unambiguous -//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar -//! types that would make duplicating values at will unsound -//! * combined with the ZST requirement, this confers a kind of "telecopy" -//! ability: similar to `Copy`, but without keeping the value around, and -//! instead "reconstructing" it (a noop given it's a ZST) when needed -//! * it must be *provably* inhabited: no captured uninhabited types or any -//! other types that cannot be constructed by the user of this abstraction -//! * the proof is a value of the closure-like type itself, in a sense the -//! "seed" for the "telecopy" process made possible by ZST + `Copy` -//! * this requirement is the only reason an abstraction limited to a specific -//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic -//! at the "attempted `::default()` call" time, but that doesn't guarantee -//! that the value can be soundly created, and attempting to use the typical -//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type -//! that is not proof of anything without a value (i.e. isomorphic to a -//! newtype of the type it's trying to prove the inhabitation of) -//! -//! A more flexible (and safer) solution to the general problem could exist once -//! `const`-generic parameters can have type parameters in their types: -//! -//! ```rust,ignore (needs future const-generics) -//! extern "C" fn ffi_wrapper< -//! A, R, -//! F: Fn(A) -> R, -//! const f: F, // <-- this `const`-generic is not yet allowed -//! >(arg: A) -> R { -//! f(arg) -//! } -//! ``` - -use std::mem; - -// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. -macro_rules! define_reify_functions { - ($( - fn $name:ident $(<$($param:ident),*>)? - for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )+) => { - $(pub const fn $name< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { - // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic - // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); - - $(extern $abi)? fn wrapper< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >($($arg: $arg_ty),*) -> $ret_ty { - let f = unsafe { - // SAFETY: `F` satisfies all criteria for "out of thin air" - // reconstructability (see module-level doc comment). - mem::MaybeUninit::::uninit().assume_init() - }; - f($($arg),*) - } - let _f_proof = f; - wrapper::< - $($($param,)*)? - F - > - })+ - } -} - -define_reify_functions! { - fn _reify_to_extern_c_fn_unary for extern "C" fn(arg: A) -> R; - - // HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>) - // -> T` but that doesn't work with just `reify_to_extern_c_fn_unary` - // because of the `fn` pointer type being "higher-ranked" (i.e. the - // `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R; -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs deleted file mode 100644 index 6e7a8d8c1..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs +++ /dev/null @@ -1,339 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -pub trait Types { - type FreeFunctions: 'static; - type TokenStream: 'static + Clone; - type Ident: 'static + Copy + Eq + Hash; - type Literal: 'static + Clone; - type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; - type Span: 'static + Copy + Eq + Hash; -} - -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* { - fn globals(&mut self) -> ExpnGlobals; - } - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -impl Server for MarkedTypes { - fn globals(&mut self) -> ExpnGlobals { - <_>::mark(Server::globals(&mut self.0)) - } -} - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut buf: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* - } - buf - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |buf| { - req_tx.send(buf).unwrap(); - res_rx.recv().unwrap() - }; - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let globals = dispatcher.server.globals(); - - let mut buf = Buffer::new(); - (globals, input).encode(&mut buf, &mut dispatcher.handle_store); - - buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); - - Result::decode(&mut &buf[..], &mut dispatcher.handle_store) -} - -impl client::Client { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} - -impl - client::Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs deleted file mode 100644 index 3fade2dc4..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs deleted file mode 100644 index be62c73ef..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs +++ /dev/null @@ -1,1125 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::client::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(Option); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(None) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { - Ok(stream) => Ok(TokenStream(Some(stream))), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -fn tree_to_bridge_tree( - tree: TokenTree, -) -> bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, -> { - match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) - } -} - -/// Non-generic helper for implementing `FromIterator` and -/// `Extend` with less monomorphization in calling crates. -struct ConcatStreamsHelper { - streams: Vec, -} - -impl ConcatStreamsHelper { - fn new(capacity: usize) -> Self { - ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } - } - - fn push(&mut self, stream: TokenStream) { - if let Some(stream) = stream.0 { - self.streams.push(stream); - } - } - - fn build(mut self) -> TokenStream { - if self.streams.len() <= 1 { - TokenStream(self.streams.pop()) - } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) - } - } - - fn append_to(mut self, stream: &mut TokenStream) { - if self.streams.is_empty() { - return; - } - let base = stream.0.take(); - if base.is_none() && self.streams.len() == 1 { - stream.0 = self.streams.pop(); - } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); - } - } -} - -/// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let iter = streams.into_iter(); - let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); - iter.for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter( - std::vec::IntoIter< - bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, - >, - >, - ); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) - } - } -} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -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. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::Group { - delimiter, - stream: stream.0, - span: bridge::DelimSpan::from_single(Span::call_site().0), - }) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(self.0.stream.clone()) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span.entire) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span.open) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span.close) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.span = bridge::DelimSpan::from_single(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - const LEGAL_CHARS: &[char] = &[ - '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', - ':', '#', '$', '?', '\'', - ]; - if !LEGAL_CHARS.contains(&ch) { - panic!("unsupported character `{:?}`", ch); - } - Punct(bridge::Punct { - ch: ch as u8, - joint: spacing == Spacing::Joint, - span: Span::call_site().0, - }) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.ch as char - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - if self.0.joint { - Spacing::Joint - } else { - Spacing::Alone - } - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0.span = span.0; - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs deleted file mode 100644 index 39309faa4..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(super::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(super::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(super::TokenTree::Punct(super::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(super::Spacing::Alone), - Spacing::Joint => quote!(super::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(super::TokenTree::Group(super::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(super::Delimiter::Parenthesis), - Delimiter::Brace => quote!(super::Delimiter::Brace), - Delimiter::Bracket => quote!(super::Delimiter::Bracket), - Delimiter::None => quote!(super::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(super::TokenTree::Ident(super::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(super::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(super::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs deleted file mode 100644 index 7e8e67856..000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs +++ /dev/null @@ -1,792 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = Group { - delimiter: delim_to_internal(group.delimiter), - token_trees: match group.stream { - Some(stream) => stream.into_iter().collect(), - None => Vec::new(), - }, - }; - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { - char: p.ch as char, - spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, - id: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => bridge::TokenTree::Literal(lit), - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { - bridge::TokenTree::Punct(bridge::Punct { - ch: punct.char as u8, - joint: punct.spacing == Spacing::Joint, - span: punct.id, - }) - } - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group { - delimiter: delim_to_external(subtree.delimiter), - stream: if subtree.token_trees.is_empty() { - None - } else { - Some(subtree.token_trees.into_iter().collect()) - }, - span: bridge::DelimSpan::from_single( - subtree.delimiter.map_or(Span::unspecified(), |del| del.id), - ), - }), - }) - .collect() - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> Option { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> bridge::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket, - None => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, _is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { text: string.into(), id: span }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.id - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { id: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), id: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{}f32", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{}f64", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.id - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.id = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -impl server::Server for RustAnalyzer { - fn globals(&mut self) -> bridge::ExpnGlobals { - bridge::ExpnGlobals { - def_site: Span::unspecified(), - call_site: Span::unspecified(), - mixed_site: Span::unspecified(), - } - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs index 46882845a..e4e43e97d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs @@ -20,7 +20,7 @@ use token_stream::TokenStreamBuilder; mod symbol; pub use symbol::*; -use std::{iter::FromIterator, ops::Bound}; +use std::ops::Bound; type Group = tt::Subtree; type TokenTree = tt::TokenTree; @@ -37,23 +37,6 @@ pub struct SourceFile { type Level = super::proc_macro::Level; type LineColumn = super::proc_macro::LineColumn; -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - pub struct FreeFunctions; #[derive(Default)] @@ -65,8 +48,6 @@ impl server::Types for RustAnalyzer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type SourceFile = SourceFile; - type MultiSpan = Vec; - type Diagnostic = Diagnostic; type Span = Span; type Symbol = Symbol; } @@ -90,6 +71,10 @@ impl server::FreeFunctions for RustAnalyzer { span: tt::TokenId::unspecified(), }) } + + fn emit_diagnostic(&mut self, _: bridge::Diagnostic) { + // FIXME handle diagnostic + } } impl server::TokenStream for RustAnalyzer { @@ -282,30 +267,6 @@ impl server::SourceFile for RustAnalyzer { } } -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - impl server::Span for RustAnalyzer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) @@ -372,18 +333,6 @@ impl server::Span for RustAnalyzer { } } -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - impl server::Symbol for RustAnalyzer { fn normalize_and_validate_ident(&mut self, string: &str) -> Result { // FIXME: nfc-normalize and validate idents diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs index bcf3f1184..f7d3a3091 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs @@ -5,7 +5,7 @@ //! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). //! //! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple -//! interface the rest of rust analyzer can use to talk to the macro +//! interface the rest of rust-analyzer can use to talk to the macro //! provider. //! //! # Adding a new ABI @@ -25,7 +25,6 @@ mod abi_1_58; mod abi_1_63; -mod abi_1_64; #[cfg(feature = "sysroot-abi")] mod abi_sysroot; @@ -34,12 +33,11 @@ include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); // Used by `test/utils.rs` #[cfg(test)] -pub(crate) use abi_1_64::TokenStream as TestTokenStream; +pub(crate) use abi_1_63::TokenStream as TestTokenStream; use super::dylib::LoadProcMacroDylibError; pub(crate) use abi_1_58::Abi as Abi_1_58; pub(crate) use abi_1_63::Abi as Abi_1_63; -pub(crate) use abi_1_64::Abi as Abi_1_64; #[cfg(feature = "sysroot-abi")] pub(crate) use abi_sysroot::Abi as Abi_Sysroot; use libloading::Library; @@ -58,7 +56,6 @@ impl PanicMessage { pub(crate) enum Abi { Abi1_58(Abi_1_58), Abi1_63(Abi_1_63), - Abi1_64(Abi_1_64), #[cfg(feature = "sysroot-abi")] AbiSysroot(Abi_Sysroot), } @@ -120,10 +117,6 @@ impl Abi { let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; Ok(Abi::Abi1_63(inner)) } - (1, 64..) => { - let inner = unsafe { Abi_1_64::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_64(inner)) - } _ => Err(LoadProcMacroDylibError::UnsupportedABI), } } @@ -137,7 +130,6 @@ impl Abi { match self { Self::Abi1_58(abi) => abi.expand(macro_name, macro_body, attributes), Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes), - Self::Abi1_64(abi) => abi.expand(macro_name, macro_body, attributes), #[cfg(feature = "sysroot-abi")] Self::AbiSysroot(abi) => abi.expand(macro_name, macro_body, attributes), } @@ -147,7 +139,6 @@ impl Abi { match self { Self::Abi1_58(abi) => abi.list_macros(), Self::Abi1_63(abi) => abi.list_macros(), - Self::Abi1_64(abi) => abi.list_macros(), #[cfg(feature = "sysroot-abi")] Self::AbiSysroot(abi) => abi.list_macros(), } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index 2b6c070fe..7aba74e53 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -1,7 +1,6 @@ //! Handles dynamic library loading for proc macro use std::{ - convert::TryInto, fmt, fs::File, io, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 4c205b9ca..3679bfc43 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -26,6 +26,7 @@ use std::{ ffi::OsString, fs, path::{Path, PathBuf}, + thread, time::SystemTime, }; @@ -65,18 +66,16 @@ impl ProcMacroSrv { let macro_body = task.macro_body.to_subtree(); let attributes = task.attributes.map(|it| it.to_subtree()); - // FIXME: replace this with std's scoped threads once they stabilize - // (then remove dependency on crossbeam) - let result = crossbeam::scope(|s| { - let res = match s - .builder() + let result = thread::scope(|s| { + let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) .name(task.macro_name.clone()) - .spawn(|_| { + .spawn_scoped(s, || { expander .expand(&task.macro_name, ¯o_body, attributes.as_ref()) .map(|it| FlatTree::new(&it)) - }) { + }); + let res = match thread { Ok(handle) => handle.join(), Err(e) => std::panic::resume_unwind(Box::new(e)), }; @@ -86,10 +85,6 @@ impl ProcMacroSrv { Err(e) => std::panic::resume_unwind(e), } }); - let result = match result { - Ok(result) => result, - Err(e) => std::panic::resume_unwind(e), - }; prev_env.rollback(); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 07222907f..6339d56d0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -19,7 +19,7 @@ fn test_derive_error() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 + PUNCH ! [joint] 4294967295 SUBTREE () 4294967295 LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 PUNCH ; [alone] 4294967295"##]], @@ -109,7 +109,7 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 4294967295 LITERAL 2_u32 4294967295 PUNCH , [alone] 4294967295 - PUNCH - [alone] 4294967295 + PUNCH - [joint] 4294967295 LITERAL 4i64 4294967295 PUNCH , [alone] 4294967295 LITERAL 3.14f32 4294967295 @@ -130,7 +130,7 @@ fn test_attr_macro() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 + PUNCH ! [joint] 4294967295 SUBTREE () 4294967295 LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 PUNCH ; [alone] 4294967295"##]], diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index ee7f8339a..84e772d16 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -12,6 +12,7 @@ use cargo_metadata::{camino::Utf8Path, Message}; use la_arena::ArenaMap; use paths::AbsPathBuf; use rustc_hash::FxHashMap; +use semver::Version; use serde::Deserialize; use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package}; @@ -77,9 +78,32 @@ impl WorkspaceBuildScripts { config: &CargoConfig, workspace: &CargoWorkspace, progress: &dyn Fn(String), + toolchain: &Option, ) -> io::Result { - let mut cmd = Self::build_command(config); + const RUST_1_62: Version = Version::new(1, 62, 0); + match Self::run_(Self::build_command(config), config, workspace, progress) { + Ok(WorkspaceBuildScripts { error: Some(error), .. }) + if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => + { + // building build scripts failed, attempt to build with --keep-going so + // that we potentially get more build data + let mut cmd = Self::build_command(config); + cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); + let mut res = Self::run_(cmd, config, workspace, progress)?; + res.error = Some(error); + Ok(res) + } + res => res, + } + } + + fn run_( + mut cmd: Command, + config: &CargoConfig, + workspace: &CargoWorkspace, + progress: &dyn Fn(String), + ) -> io::Result { if config.wrap_rustc_in_build_scripts { // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use // that to compile only proc macros and build scripts during the initial diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 597880c2c..eed955b42 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -19,7 +19,7 @@ use crate::{utf8_stdout, ManifestPath}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// -/// Note that internally, rust analyzer uses a different structure: +/// Note that internally, rust-analyzer uses a different structure: /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, /// while this knows about `Packages` & `Targets`: purely cargo-related /// concepts. diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index e3f83084a..b81b7432f 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -3,7 +3,7 @@ //! //! Pure model is represented by the [`base_db::CrateGraph`] from another crate. //! -//! In this crate, we are conserned with "real world" project models. +//! In this crate, we are concerned with "real world" project models. //! //! Specifically, here we have a representation for a Cargo project //! ([`CargoWorkspace`]) and for manually specified layout ([`ProjectJson`]). diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index e304a59c0..9ccb6e910 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -28,6 +28,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr rustc: None, rustc_cfg: Vec::new(), cfg_overrides, + toolchain: None, }; to_crate_graph(project_workspace) } @@ -184,10 +185,10 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 2, + 1, ): CrateData { root_file_id: FileId( - 3, + 2, ), edition: Edition2018, version: Some( @@ -196,9 +197,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -259,77 +260,85 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 4, + 2, ): CrateData { root_file_id: FileId( - 5, + 3, ), - edition: Edition2015, + edition: Edition2018, version: Some( - "0.2.98", + "0.1.0", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "libc", + "an_example", ), - canonical_name: "libc", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "feature=default", - "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", + "CARGO_CRATE_NAME": "hello_world", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_MINOR": "1", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], + dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 4, + ), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), + repo: None, }, is_proc_macro: false, }, CrateId( - 1, + 3, ): CrateData { root_file_id: FileId( - 2, + 4, ), edition: Edition2018, version: Some( @@ -338,9 +347,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "it", ), - canonical_name: "hello-world", + canonical_name: "it", }, ), cfg_options: CfgOptions( @@ -401,77 +410,69 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 3, + 4, ): CrateData { root_file_id: FileId( - 4, + 5, ), - edition: Edition2018, + edition: Edition2015, version: Some( - "0.1.0", + "0.2.98", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "it", + "libc", ), - canonical_name: "it", + canonical_name: "libc", }, ), cfg_options: CfgOptions( [ "debug_assertions", + "feature=default", + "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", + "CARGO_CRATE_NAME": "libc", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_MINOR": "2", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], + dependencies: [], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: None, + repo: Some( + "https://github.com/rust-lang/libc", + ), }, is_proc_macro: false, }, @@ -566,10 +567,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() { is_proc_macro: false, }, CrateId( - 2, + 1, ): CrateData { root_file_id: FileId( - 3, + 2, ), edition: Edition2018, version: Some( @@ -578,9 +579,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -643,77 +644,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() { is_proc_macro: false, }, CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, + 2, ): CrateData { root_file_id: FileId( - 2, + 3, ), edition: Edition2018, version: Some( @@ -722,9 +656,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "an_example", ), - canonical_name: "hello-world", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( @@ -863,92 +797,91 @@ fn cargo_hello_world_project_model_with_selective_overrides() { }, is_proc_macro: false, }, - }, - }"#]], - ) -} - -#[test] -fn cargo_hello_world_project_model() { - let crate_graph = load_cargo("hello-world-metadata.json"); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { CrateId( - 0, + 4, ): CrateData { root_file_id: FileId( - 1, + 5, ), - edition: Edition2018, + edition: Edition2015, version: Some( - "0.1.0", + "0.2.98", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "libc", ), - canonical_name: "hello-world", + canonical_name: "libc", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "test", + "feature=default", + "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "test", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", + "CARGO_CRATE_NAME": "libc", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_MINOR": "2", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], + dependencies: [], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: None, + repo: Some( + "https://github.com/rust-lang/libc", + ), }, is_proc_macro: false, }, + }, + }"#]], + ) +} + +#[test] +fn cargo_hello_world_project_model() { + let crate_graph = load_cargo("hello-world-metadata.json"); + check_crate_graph( + crate_graph, + expect![[r#" + CrateGraph { + arena: { CrateId( - 2, + 0, ): CrateData { root_file_id: FileId( - 3, + 1, ), edition: Edition2018, version: Some( @@ -957,9 +890,9 @@ fn cargo_hello_world_project_model() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -994,15 +927,6 @@ fn cargo_hello_world_project_model() { }, }, dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, Dependency { crate_id: CrateId( 4, @@ -1022,77 +946,87 @@ fn cargo_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 4, + 1, ): CrateData { root_file_id: FileId( - 5, + 2, ), - edition: Edition2015, + edition: Edition2018, version: Some( - "0.2.98", + "0.1.0", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "libc", + "hello_world", ), - canonical_name: "libc", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "feature=default", - "feature=std", + "test", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", + "test", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", + "CARGO_CRATE_NAME": "hello_world", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_MINOR": "1", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], + dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 4, + ), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), + repo: None, }, is_proc_macro: false, }, CrateId( - 1, + 2, ): CrateData { root_file_id: FileId( - 2, + 3, ), edition: Edition2018, version: Some( @@ -1101,9 +1035,9 @@ fn cargo_hello_world_project_model() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "an_example", ), - canonical_name: "hello-world", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( @@ -1242,6 +1176,73 @@ fn cargo_hello_world_project_model() { }, is_proc_macro: false, }, + CrateId( + 4, + ): CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + version: Some( + "0.2.98", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=default", + "feature=std", + ], + ), + potential_cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + ], + ), + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "libc", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [], + proc_macro: Err( + "crate has not (yet) been built", + ), + origin: CratesIo { + repo: Some( + "https://github.com/rust-lang/libc", + ), + }, + is_proc_macro: false, + }, }, }"#]], ) @@ -1300,19 +1301,53 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 10, + 1, ): CrateData { root_file_id: FileId( - 11, + 2, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "unwind", + "core", ), - canonical_name: "unwind", + canonical_name: "core", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: CfgOptions( + [], + ), + env: Env { + entries: {}, + }, + dependencies: [], + proc_macro: Err( + "no proc macro loaded for sysroot crate", + ), + origin: Lang( + Core, + ), + is_proc_macro: false, + }, + CrateId( + 2, + ): CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", }, ), cfg_options: CfgOptions( @@ -1334,19 +1369,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 7, + 3, ): CrateData { root_file_id: FileId( - 8, + 4, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "std_detect", + "panic_unwind", ), - canonical_name: "std_detect", + canonical_name: "panic_unwind", }, ), cfg_options: CfgOptions( @@ -1412,19 +1447,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 1, + 5, ): CrateData { root_file_id: FileId( - 2, + 6, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "core", + "profiler_builtins", ), - canonical_name: "core", + canonical_name: "profiler_builtins", }, ), cfg_options: CfgOptions( @@ -1441,24 +1476,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Core, + Other, ), is_proc_macro: false, }, CrateId( - 11, + 6, ): CrateData { root_file_id: FileId( - 12, + 7, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "std", ), - canonical_name: "hello_world", + canonical_name: "std", }, ), cfg_options: CfgOptions( @@ -1471,6 +1506,15 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "alloc", + ), + prelude: true, + }, Dependency { crate_id: CrateId( 1, @@ -1482,19 +1526,46 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 0, + 2, ), name: CrateName( - "alloc", + "panic_abort", ), prelude: true, }, Dependency { crate_id: CrateId( - 6, + 3, ), name: CrateName( - "std", + "panic_unwind", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 5, + ), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 7, + ), + name: CrateName( + "std_detect", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 8, + ), + name: CrateName( + "term", ), prelude: true, }, @@ -1505,31 +1576,40 @@ fn rust_project_hello_world_project_model() { name: CrateName( "test", ), - prelude: false, + prelude: true, + }, + Dependency { + crate_id: CrateId( + 10, + ), + name: CrateName( + "unwind", + ), + prelude: true, }, ], proc_macro: Err( - "no proc macro dylib present", + "no proc macro loaded for sysroot crate", + ), + origin: Lang( + Std, ), - origin: CratesIo { - repo: None, - }, is_proc_macro: false, }, CrateId( - 8, + 7, ): CrateData { root_file_id: FileId( - 9, + 8, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "term", + "std_detect", ), - canonical_name: "term", + canonical_name: "std_detect", }, ), cfg_options: CfgOptions( @@ -1551,19 +1631,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 5, + 8, ): CrateData { root_file_id: FileId( - 6, + 9, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "profiler_builtins", + "term", ), - canonical_name: "profiler_builtins", + canonical_name: "term", }, ), cfg_options: CfgOptions( @@ -1585,19 +1665,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 2, + 9, ): CrateData { root_file_id: FileId( - 3, + 10, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "panic_abort", + "test", ), - canonical_name: "panic_abort", + canonical_name: "test", }, ), cfg_options: CfgOptions( @@ -1614,24 +1694,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Other, + Test, ), is_proc_macro: false, }, CrateId( - 9, + 10, ): CrateData { root_file_id: FileId( - 10, + 11, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "test", + "unwind", ), - canonical_name: "test", + canonical_name: "unwind", }, ), cfg_options: CfgOptions( @@ -1648,24 +1728,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Test, + Other, ), is_proc_macro: false, }, CrateId( - 6, + 11, ): CrateData { root_file_id: FileId( - 7, + 12, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "std", + "hello_world", ), - canonical_name: "std", + canonical_name: "hello_world", }, ), cfg_options: CfgOptions( @@ -1678,15 +1758,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, Dependency { crate_id: CrateId( 1, @@ -1698,46 +1769,19 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 2, - ), - name: CrateName( - "panic_abort", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 3, - ), - name: CrateName( - "panic_unwind", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 5, - ), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 7, + 0, ), name: CrateName( - "std_detect", + "alloc", ), prelude: true, }, Dependency { crate_id: CrateId( - 8, + 6, ), name: CrateName( - "term", + "std", ), prelude: true, }, @@ -1748,58 +1792,15 @@ fn rust_project_hello_world_project_model() { name: CrateName( "test", ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 10, - ), - name: CrateName( - "unwind", - ), - prelude: true, + prelude: false, }, ], proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Std, - ), - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], + "no proc macro dylib present", ), - env: Env { - entries: {}, + origin: CratesIo { + repo: None, }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), is_proc_macro: false, }, }, diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index b144006b4..818bbed6a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -12,7 +12,8 @@ use base_db::{ use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::always; +use semver::Version; +use stdx::{always, hash::NoHashHashMap}; use crate::{ build_scripts::BuildScriptOutput, @@ -77,6 +78,7 @@ pub enum ProjectWorkspace { /// different target. rustc_cfg: Vec, cfg_overrides: CfgOverrides, + toolchain: Option, }, /// Project workspace was manually specified using a `rust-project.json` file. Json { project: ProjectJson, sysroot: Option, rustc_cfg: Vec }, @@ -105,6 +107,7 @@ impl fmt::Debug for ProjectWorkspace { rustc, rustc_cfg, cfg_overrides, + toolchain, } => f .debug_struct("Cargo") .field("root", &cargo.workspace_root().file_name()) @@ -116,6 +119,7 @@ impl fmt::Debug for ProjectWorkspace { ) .field("n_rustc_cfg", &rustc_cfg.len()) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("toolchain", &toolchain) .finish(), ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { let mut debug_struct = f.debug_struct("Json"); @@ -160,6 +164,9 @@ impl ProjectWorkspace { cmd.arg("--version"); cmd })?; + let toolchain = cargo_version + .get("cargo ".len()..) + .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()); let meta = CargoWorkspace::fetch_metadata( &cargo_toml, @@ -169,9 +176,9 @@ impl ProjectWorkspace { ) .with_context(|| { format!( - "Failed to read Cargo metadata from Cargo.toml file {}, {}", + "Failed to read Cargo metadata from Cargo.toml file {}, {:?}", cargo_toml.display(), - cargo_version + toolchain ) })?; let cargo = CargoWorkspace::new(meta); @@ -219,6 +226,7 @@ impl ProjectWorkspace { rustc, rustc_cfg, cfg_overrides, + toolchain, } } }; @@ -271,8 +279,8 @@ impl ProjectWorkspace { progress: &dyn Fn(String), ) -> Result { match self { - ProjectWorkspace::Cargo { cargo, .. } => { - WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| { + ProjectWorkspace::Cargo { cargo, toolchain, .. } => { + WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| { format!("Failed to run build scripts for {}", &cargo.workspace_root().display()) }) } @@ -320,6 +328,7 @@ impl ProjectWorkspace { rustc_cfg: _, cfg_overrides: _, build_scripts, + toolchain: _, } => { cargo .packages() @@ -425,6 +434,7 @@ impl ProjectWorkspace { rustc_cfg, cfg_overrides, build_scripts, + toolchain: _, } => cargo_to_crate_graph( rustc_cfg.clone(), cfg_overrides, @@ -461,7 +471,7 @@ fn project_json_to_crate_graph( .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load)); let mut cfg_cache: FxHashMap<&str, Vec> = FxHashMap::default(); - let crates: FxHashMap = project + let crates: NoHashHashMap = project .crates() .filter_map(|(crate_id, krate)| { let file_path = &krate.root_module; @@ -760,7 +770,7 @@ fn handle_rustc_crates( queue.push_back(root_pkg); while let Some(pkg) = queue.pop_front() { // Don't duplicate packages if they are dependended on a diamond pattern - // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates + // N.B. if this line is omitted, we try to analyse over 4_800_000 crates // which is not ideal if rustc_pkg_crates.contains_key(&pkg) { continue; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 07771d1b3..539258918 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -22,7 +22,8 @@ anyhow = "1.0.57" crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.3" -lsp-types = { version = "0.93.0", features = ["proposed"] } +scip = "0.1.1" +lsp-types = { version = "0.93.1", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.2.4" oorandom = "11.1.3" @@ -88,5 +89,5 @@ in-rust-tree = [ "proc-macro-srv/sysroot-abi", "sourcegen/in-rust-tree", "ide/in-rust-tree", - "syntax/in-rust-tree" + "syntax/in-rust-tree", ] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs index 0b69f75bc..298814af5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs @@ -52,7 +52,7 @@ impl Logger { // merge chalk filter to our main filter (from RA_LOG env). // // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. - // As the value should only affect chalk crates, we'd better mannually + // As the value should only affect chalk crates, we'd better manually // specify the target. And for simplicity, CHALK_DEBUG only accept the value // that specify level. let chalk_level_dir = std::env::var("CHALK_DEBUG") diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index e9de23cb3..f6a680297 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -93,6 +93,7 @@ fn try_main() -> Result<()> { flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, + flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?, } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs index 2f6d4706d..38e9c7dd7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs @@ -17,6 +17,11 @@ pub(crate) fn run_rustc_skipping_cargo_checking( rustc_executable: OsString, args: Vec, ) -> io::Result { + // `CARGO_CFG_TARGET_ARCH` is only set by cargo when executing build scripts + // We don't want to exit out checks unconditionally with success if a build + // script tries to invoke checks themselves + // See https://github.com/rust-lang/rust-analyzer/issues/12973 for context + let not_invoked_by_build_script = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_none(); let is_cargo_check = args.iter().any(|arg| { let arg = arg.to_string_lossy(); // `cargo check` invokes `rustc` with `--emit=metadata` argument. @@ -29,7 +34,7 @@ pub(crate) fn run_rustc_skipping_cargo_checking( // The default output filename is CRATE_NAME.rmeta. arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link") }); - if is_cargo_check { + if not_invoked_by_build_script && is_cargo_check { return Ok(ExitCode(Some(0))); } run_rustc(rustc_executable, args) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index 6ccdaa86d..60ba67e25 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -9,6 +9,7 @@ mod analysis_stats; mod diagnostics; mod ssr; mod lsif; +mod scip; mod progress_report; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 52511ceb5..247007db0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -43,7 +43,7 @@ impl flags::Diagnostics { println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); for diagnostic in analysis .diagnostics( - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), AssistResolveStrategy::None, file_id, ) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 19907ebdd..aa32654fb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -10,6 +10,10 @@ xflags::xflags! { src "./src/cli/flags.rs" /// LSP server for the Rust programming language. + /// + /// Subcommands and their flags do not provide any stability guarantees and may be removed or + /// changed without notice. Top-level flags that are not are marked as [Unstable] provide + /// backwards-compatibility and may be relied on. cmd rust-analyzer { /// Verbosity level, can be repeated multiple times. repeated -v, --verbose @@ -21,7 +25,7 @@ xflags::xflags! { /// Flush log records to the file immediately. optional --no-log-buffering - /// Wait until a debugger is attached to (requires debug build). + /// [Unstable] Wait until a debugger is attached to (requires debug build). optional --wait-dbg default cmd lsp-server { @@ -108,6 +112,10 @@ xflags::xflags! { cmd lsif required path: PathBuf {} + + cmd scip + required path: PathBuf + {} } } @@ -136,6 +144,7 @@ pub enum RustAnalyzerCmd { Search(Search), ProcMacro(ProcMacro), Lsif(Lsif), + Scip(Scip), } #[derive(Debug)] @@ -203,6 +212,11 @@ pub struct Lsif { pub path: PathBuf, } +#[derive(Debug)] +pub struct Scip { + pub path: PathBuf, +} + impl RustAnalyzer { pub const HELP: &'static str = Self::HELP_; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs new file mode 100644 index 000000000..65cc993c4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -0,0 +1,448 @@ +//! SCIP generator + +use std::{ + collections::{HashMap, HashSet}, + time::Instant, +}; + +use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; +use hir::Name; +use ide::{ + LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange, + TokenId, +}; +use ide_db::LineIndexDatabase; +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; +use scip::types as scip_types; +use std::env; + +use crate::cli::{ + flags, + load_cargo::{load_workspace, LoadCargoConfig}, + Result, +}; + +impl flags::Scip { + pub fn run(self) -> Result<()> { + eprintln!("Generating SCIP start..."); + let now = Instant::now(); + let cargo_config = CargoConfig::default(); + + let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s)); + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + with_proc_macro: true, + prefill_caches: true, + }; + let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path)); + let rootpath = path.normalize(); + let manifest = ProjectManifest::discover_single(&path)?; + + let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; + + let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?; + let db = host.raw_database(); + let analysis = host.analysis(); + + let si = StaticIndex::compute(&analysis); + + let mut index = scip_types::Index { + metadata: Some(scip_types::Metadata { + version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(), + tool_info: Some(scip_types::ToolInfo { + name: "rust-analyzer".to_owned(), + version: "0.1".to_owned(), + arguments: vec![], + ..Default::default() + }) + .into(), + project_root: format!( + "file://{}", + path.normalize() + .as_os_str() + .to_str() + .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? + .to_string() + ), + text_document_encoding: scip_types::TextEncoding::UTF8.into(), + ..Default::default() + }) + .into(), + ..Default::default() + }; + + let mut symbols_emitted: HashSet = HashSet::default(); + let mut tokens_to_symbol: HashMap = HashMap::new(); + + for file in si.files { + let mut local_count = 0; + let mut new_local_symbol = || { + let new_symbol = scip::types::Symbol::new_local(local_count); + local_count += 1; + + new_symbol + }; + + let StaticIndexedFile { file_id, tokens, .. } = file; + let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) { + Some(relative_path) => relative_path, + None => continue, + }; + + let line_index = LineIndex { + index: db.line_index(file_id), + encoding: OffsetEncoding::Utf8, + endings: LineEndings::Unix, + }; + + let mut doc = scip_types::Document { + relative_path, + language: "rust".to_string(), + ..Default::default() + }; + + tokens.into_iter().for_each(|(range, id)| { + let token = si.tokens.get(id).unwrap(); + + let mut occurrence = scip_types::Occurrence::default(); + occurrence.range = text_range_to_scip_range(&line_index, range); + occurrence.symbol = match tokens_to_symbol.get(&id) { + Some(symbol) => symbol.clone(), + None => { + let symbol = match &token.moniker { + Some(moniker) => moniker_to_symbol(&moniker), + None => new_local_symbol(), + }; + + let symbol = scip::symbol::format_symbol(symbol); + tokens_to_symbol.insert(id, symbol.clone()); + symbol + } + }; + + if let Some(def) = token.definition { + if def.range == range { + occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32; + } + + if !symbols_emitted.contains(&id) { + symbols_emitted.insert(id); + + let mut symbol_info = scip_types::SymbolInformation::default(); + symbol_info.symbol = occurrence.symbol.clone(); + if let Some(hover) = &token.hover { + if !hover.markup.as_str().is_empty() { + symbol_info.documentation = vec![hover.markup.as_str().to_string()]; + } + } + + doc.symbols.push(symbol_info) + } + } + + doc.occurrences.push(occurrence); + }); + + if doc.occurrences.is_empty() { + continue; + } + + index.documents.push(doc); + } + + scip::write_message_to_file("index.scip", index) + .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?; + + eprintln!("Generating SCIP finished {:?}", now.elapsed()); + Ok(()) + } +} + +fn get_relative_filepath( + vfs: &vfs::Vfs, + rootpath: &vfs::AbsPathBuf, + file_id: ide::FileId, +) -> Option { + Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string()) +} + +// SCIP Ranges have a (very large) optimization that ranges if they are on the same line +// only encode as a vector of [start_line, start_col, end_col]. +// +// This transforms a line index into the optimized SCIP Range. +fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec { + let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start()); + let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end()); + + if start_line == end_line { + vec![start_line as i32, start_col as i32, end_col as i32] + } else { + vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32] + } +} + +fn new_descriptor_str( + name: &str, + suffix: scip_types::descriptor::Suffix, +) -> scip_types::Descriptor { + scip_types::Descriptor { + name: name.to_string(), + disambiguator: "".to_string(), + suffix: suffix.into(), + ..Default::default() + } +} + +fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor { + let mut name = name.to_string(); + if name.contains("'") { + name = format!("`{}`", name); + } + + new_descriptor_str(name.as_str(), suffix) +} + +/// Loosely based on `def_to_moniker` +/// +/// Only returns a Symbol when it's a non-local symbol. +/// So if the visibility isn't outside of a document, then it will return None +fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol { + use scip_types::descriptor::Suffix::*; + + let package_name = moniker.package_information.name.clone(); + let version = moniker.package_information.version.clone(); + let descriptors = moniker + .identifier + .description + .iter() + .map(|desc| { + new_descriptor( + desc.name.clone(), + match desc.desc { + MonikerDescriptorKind::Namespace => Namespace, + MonikerDescriptorKind::Type => Type, + MonikerDescriptorKind::Term => Term, + MonikerDescriptorKind::Method => Method, + MonikerDescriptorKind::TypeParameter => TypeParameter, + MonikerDescriptorKind::Parameter => Parameter, + MonikerDescriptorKind::Macro => Macro, + MonikerDescriptorKind::Meta => Meta, + }, + ) + }) + .collect(); + + scip_types::Symbol { + scheme: "rust-analyzer".into(), + package: Some(scip_types::Package { + manager: "cargo".to_string(), + name: package_name, + version, + ..Default::default() + }) + .into(), + descriptors, + ..Default::default() + } +} + +#[cfg(test)] +mod test { + use super::*; + use hir::Semantics; + use ide::{AnalysisHost, FilePosition}; + use ide_db::defs::IdentClass; + use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token}; + use scip::symbol::format_symbol; + use syntax::SyntaxKind::*; + use syntax::{AstNode, T}; + + fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) { + let mut host = AnalysisHost::default(); + let change_fixture = ChangeFixture::parse(ra_fixture); + host.raw_database_mut().apply_change(change_fixture.change); + let (file_id, range_or_offset) = + change_fixture.file_position.expect("expected a marker ($0)"); + let offset = range_or_offset.expect_offset(); + (host, FilePosition { file_id, offset }) + } + + /// If expected == "", then assert that there are no symbols (this is basically local symbol) + #[track_caller] + fn check_symbol(ra_fixture: &str, expected: &str) { + let (host, position) = position(ra_fixture); + + let FilePosition { file_id, offset } = position; + + let db = host.raw_database(); + let sema = &Semantics::new(db); + let file = sema.parse(file_id).syntax().clone(); + let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { + IDENT + | INT_NUMBER + | LIFETIME_IDENT + | T![self] + | T![super] + | T![crate] + | T![Self] + | COMMENT => 2, + kind if kind.is_trivia() => 0, + _ => 1, + }) + .expect("OK OK"); + + let navs = sema + .descend_into_macros(original_token.clone()) + .into_iter() + .filter_map(|token| { + IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { + it.into_iter().flat_map(|def| { + let module = def.module(db).unwrap(); + let current_crate = module.krate(); + + match MonikerResult::from_def(sema.db, def, current_crate) { + Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)), + None => None, + } + }) + }) + }) + .flatten() + .collect::>(); + + if expected == "" { + assert_eq!(0, navs.len(), "must have no symbols {:?}", navs); + return; + } + + assert_eq!(1, navs.len(), "must have one symbol {:?}", navs); + + let res = navs.get(0).unwrap(); + let formatted = format_symbol(res.clone()); + assert_eq!(formatted, expected); + } + + #[test] + fn basic() { + check_symbol( + r#" +//- /lib.rs crate:main deps:foo +use foo::example_mod::func; +fn main() { + func$0(); +} +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod example_mod { + pub fn func() {} +} +"#, + "rust-analyzer cargo foo 0.1.0 example_mod/func().", + ); + } + + #[test] + fn symbol_for_trait() { + check_symbol( + r#" +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub trait MyTrait { + pub fn func$0() {} + } +} +"#, + "rust-analyzer cargo foo 0.1.0 module/MyTrait#func().", + ); + } + + #[test] + fn symbol_for_trait_constant() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + const MY_CONST$0: u8; + } + } + "#, + "rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.", + ); + } + + #[test] + fn symbol_for_trait_type() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + type MyType$0; + } + } + "#, + // "foo::module::MyTrait::MyType", + "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]", + ); + } + + #[test] + fn symbol_for_trait_impl_function() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + pub fn func() {} + } + + struct MyStruct {} + + impl MyTrait for MyStruct { + pub fn func$0() {} + } + } + "#, + // "foo::module::MyStruct::MyTrait::func", + "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().", + ); + } + + #[test] + fn symbol_for_field() { + check_symbol( + r#" + //- /lib.rs crate:main deps:foo + use foo::St; + fn main() { + let x = St { a$0: 2 }; + } + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub struct St { + pub a: i32, + } + "#, + "rust-analyzer cargo foo 0.1.0 St#a.", + ); + } + + #[test] + fn local_symbol_for_local() { + check_symbol( + r#" + //- /lib.rs crate:main deps:foo + use foo::module::func; + fn main() { + func(); + } + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub fn func() { + let x$0 = 2; + } + } + "#, + "", + ); + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index ac0fdf85a..54dcb42d9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -12,8 +12,8 @@ use std::{ffi::OsString, fmt, iter, path::PathBuf}; use flycheck::FlycheckConfig; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig, - Snippet, SnippetScope, + HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, + JoinLinesConfig, Snippet, SnippetScope, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -45,7 +45,8 @@ mod patch_old_style; // - foo_command = overrides the subcommand, foo_overrideCommand allows full overwriting, extra args only applies for foo_command // Defines the server-side configuration of the rust-analyzer. We generate -// *parts* of VS Code's `package.json` config from this. +// *parts* of VS Code's `package.json` config from this. Run `cargo test` to +// re-generate that file. // // However, editor specific config, which the server doesn't know about, should // be specified directly in `package.json`. @@ -120,6 +121,10 @@ config_data! { /// Cargo, you might also want to change /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. /// + /// If there are multiple linked projects, this command is invoked for + /// each of them, with the working directory being the project root + /// (i.e., the folder containing the `Cargo.toml`). + /// /// An example command would be: /// /// ```bash @@ -243,7 +248,10 @@ config_data! { hover_actions_run_enable: bool = "true", /// Whether to show documentation on hover. - hover_documentation_enable: bool = "true", + hover_documentation_enable: bool = "true", + /// Whether to show keyword hover popups. Only applies when + /// `#rust-analyzer.hover.documentation.enable#` is set. + hover_documentation_keywords_enable: bool = "true", /// Use markdown syntax for links in hover. hover_links_enable: bool = "true", @@ -377,6 +385,34 @@ config_data! { /// available on a nightly build. rustfmt_rangeFormatting_enable: bool = "false", + /// Inject additional highlighting into doc comments. + /// + /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra + /// doc links. + semanticHighlighting_doc_comment_inject_enable: bool = "true", + /// Use semantic tokens for operators. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when + /// they are tagged with modifiers. + semanticHighlighting_operator_enable: bool = "true", + /// Use specialized semantic tokens for operators. + /// + /// When enabled, rust-analyzer will emit special token types for operator tokens instead + /// of the generic `operator` token type. + semanticHighlighting_operator_specialization_enable: bool = "false", + /// Use semantic tokens for punctuations. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when + /// they are tagged with modifiers or have a special role. + semanticHighlighting_punctuation_enable: bool = "false", + /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro + /// calls. + semanticHighlighting_punctuation_separate_macro_bang: bool = "false", + /// Use specialized semantic tokens for punctuations. + /// + /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead + /// of the generic `punctuation` token type. + semanticHighlighting_punctuation_specialization_enable: bool = "false", /// Use semantic tokens for strings. /// /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. @@ -881,6 +917,7 @@ impl Config { ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, }, + insert_use: self.insert_use_config(), } } @@ -1162,8 +1199,19 @@ impl Config { } } - pub fn highlighting_strings(&self) -> bool { - self.data.semanticHighlighting_strings_enable + pub fn highlighting_config(&self) -> HighlightConfig { + HighlightConfig { + strings: self.data.semanticHighlighting_strings_enable, + punctuation: self.data.semanticHighlighting_punctuation_enable, + specialize_punctuation: self + .data + .semanticHighlighting_punctuation_specialization_enable, + macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang, + operator: self.data.semanticHighlighting_operator_enable, + specialize_operator: self.data.semanticHighlighting_operator_specialization_enable, + inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable, + syntactic_name_ref_highlighting: false, + } } pub fn hover(&self) -> HoverConfig { @@ -1186,6 +1234,7 @@ impl Config { HoverDocFormat::PlainText } }), + keywords: self.data.hover_documentation_keywords_enable, } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 202a01adf..f516c194d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -4,11 +4,12 @@ pub(crate) mod to_proto; use std::{mem, sync::Arc}; use ide::FileId; -use rustc_hash::{FxHashMap, FxHashSet}; +use ide_db::FxHashMap; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use crate::lsp_ext; -pub(crate) type CheckFixes = Arc>>; +pub(crate) type CheckFixes = Arc>>>; #[derive(Debug, Default, Clone)] pub struct DiagnosticsMapConfig { @@ -19,12 +20,12 @@ pub struct DiagnosticsMapConfig { #[derive(Debug, Default, Clone)] pub(crate) struct DiagnosticCollection { - // FIXME: should be FxHashMap> - pub(crate) native: FxHashMap>, + // FIXME: should be NoHashHashMap> + pub(crate) native: NoHashHashMap>, // FIXME: should be Vec - pub(crate) check: FxHashMap>, + pub(crate) check: NoHashHashMap>>, pub(crate) check_fixes: CheckFixes, - changes: FxHashSet, + changes: NoHashHashSet, } #[derive(Debug, Clone)] @@ -35,9 +36,19 @@ pub(crate) struct Fix { } impl DiagnosticCollection { - pub(crate) fn clear_check(&mut self) { + pub(crate) fn clear_check(&mut self, flycheck_id: usize) { + if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) { + it.clear(); + } + if let Some(it) = self.check.get_mut(&flycheck_id) { + self.changes.extend(it.drain().map(|(key, _value)| key)); + } + } + + pub(crate) fn clear_check_all(&mut self) { Arc::make_mut(&mut self.check_fixes).clear(); - self.changes.extend(self.check.drain().map(|(key, _value)| key)) + self.changes + .extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key))) } pub(crate) fn clear_native_for(&mut self, file_id: FileId) { @@ -47,11 +58,12 @@ impl DiagnosticCollection { pub(crate) fn add_check_diagnostic( &mut self, + flycheck_id: usize, file_id: FileId, diagnostic: lsp_types::Diagnostic, fix: Option, ) { - let diagnostics = self.check.entry(file_id).or_default(); + let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default(); for existing_diagnostic in diagnostics.iter() { if are_diagnostics_equal(existing_diagnostic, &diagnostic) { return; @@ -59,7 +71,7 @@ impl DiagnosticCollection { } let check_fixes = Arc::make_mut(&mut self.check_fixes); - check_fixes.entry(file_id).or_default().extend(fix); + check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); self.changes.insert(file_id); } @@ -89,11 +101,12 @@ impl DiagnosticCollection { file_id: FileId, ) -> impl Iterator { let native = self.native.get(&file_id).into_iter().flatten(); - let check = self.check.get(&file_id).into_iter().flatten(); + let check = + self.check.values().filter_map(move |it| it.get(&file_id)).into_iter().flatten(); native.chain(check) } - pub(crate) fn take_changes(&mut self) -> Option> { + pub(crate) fn take_changes(&mut self) -> Option> { if self.changes.is_empty() { return None; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs index cff4bd7f6..74689fd87 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -512,7 +512,7 @@ fn clippy_code_description(code: Option<&str>) -> Option, pub(crate) flycheck_receiver: Receiver, - pub(crate) vfs: Arc)>>, + pub(crate) vfs: Arc)>>, pub(crate) vfs_config_version: u32, pub(crate) vfs_progress_config_version: u32, pub(crate) vfs_progress_n_total: usize, @@ -113,8 +114,9 @@ pub(crate) struct GlobalStateSnapshot { pub(crate) check_fixes: CheckFixes, mem_docs: MemDocs, pub(crate) semantic_tokens_cache: Arc>>, - vfs: Arc)>>, + vfs: Arc)>>, pub(crate) workspaces: Arc>, + pub(crate) proc_macros_loaded: bool, } impl std::panic::UnwindSafe for GlobalStateSnapshot {} @@ -157,7 +159,7 @@ impl GlobalState { flycheck_sender, flycheck_receiver, - vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), + vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, vfs_progress_n_total: 0, @@ -176,9 +178,9 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut fs_changes = Vec::new(); // A file was added or deleted let mut has_structure_changes = false; + let mut workspace_structure_change = None; let (change, changed_files) = { let mut change = Change::new(); @@ -192,15 +194,14 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - self.fetch_workspaces_queue - .request_op(format!("vfs file change: {}", path.display())); + workspace_structure_change = Some(path); } - fs_changes.push((path, file.change_kind)); if file.is_created_or_deleted() { has_structure_changes = true; } } + // Clear native diagnostics when their file gets deleted if !file.exists() { self.diagnostics.clear_native_for(file.file_id); } @@ -226,14 +227,24 @@ impl GlobalState { self.analysis_host.apply_change(change); - let raw_database = &self.analysis_host.raw_database(); - self.proc_macro_changed = - changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { - let crates = raw_database.relevant_crates(file.file_id); - let crate_graph = raw_database.crate_graph(); + { + let raw_database = self.analysis_host.raw_database(); + // FIXME: ideally we should only trigger a workspace fetch for non-library changes + // but somethings going wrong with the source root business when we add a new local + // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 + if let Some(path) = workspace_structure_change { + self.fetch_workspaces_queue + .request_op(format!("workspace vfs file change: {}", path.display())); + } + self.proc_macro_changed = + changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { + let crates = raw_database.relevant_crates(file.file_id); + let crate_graph = raw_database.crate_graph(); + + crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) + }); + } - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - }); true } @@ -246,6 +257,7 @@ impl GlobalState { check_fixes: Arc::clone(&self.diagnostics.check_fixes), mem_docs: self.mem_docs.clone(), semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), + proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(), } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs index deb777c95..e79cf3d3f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs @@ -51,6 +51,12 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< Ok(()) } +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { + let _p = profile::span("handle_stop_flycheck"); + state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); + Ok(()) +} + pub(crate) fn handle_analyzer_status( snap: GlobalStateSnapshot, params: lsp_ext::AnalyzerStatusParams, @@ -703,10 +709,8 @@ pub(crate) fn handle_runnables( let mut res = Vec::new(); for runnable in snap.analysis.runnables(file_id)? { - if let Some(offset) = offset { - if !runnable.nav.full_range.contains_inclusive(offset) { - continue; - } + if should_skip_for_offset(&runnable, offset) { + continue; } if should_skip_target(&runnable, cargo_spec.as_ref()) { continue; @@ -772,6 +776,14 @@ pub(crate) fn handle_runnables( Ok(res) } +fn should_skip_for_offset(runnable: &Runnable, offset: Option) -> bool { + match offset { + None => false, + _ if matches!(&runnable.kind, RunnableKind::TestMod { .. }) => false, + Some(offset) => !runnable.nav.full_range.contains_inclusive(offset), + } +} + pub(crate) fn handle_related_tests( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, @@ -1094,7 +1106,9 @@ pub(crate) fn handle_code_action( } // Fixes from `cargo check`. - for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { + for fix in + snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten() + { // FIXME: this mapping is awkward and shouldn't exist. Refactor // `snap.check_fixes` to not convert to LSP prematurely. let intersect_fix_range = fix @@ -1318,8 +1332,7 @@ pub(crate) fn publish_diagnostics( .unwrap(), }), source: Some("rust-analyzer".to_string()), - // https://github.com/rust-lang/rust-analyzer/issues/11404 - message: if !d.message.is_empty() { d.message } else { " ".to_string() }, + message: d.message, related_information: None, tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None }, data: None, @@ -1349,7 +1362,7 @@ pub(crate) fn handle_inlay_hints( .map(|it| { to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) }) - .collect(), + .collect::>>()?, )) } @@ -1491,10 +1504,12 @@ pub(crate) fn handle_semantic_tokens_full( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + let mut highlight_config = snap.config.highlighting_config(); + // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. + highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded; + + let highlights = snap.analysis.highlight(highlight_config, file_id)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); // Unconditionally cache the tokens snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone()); @@ -1512,10 +1527,12 @@ pub(crate) fn handle_semantic_tokens_full_delta( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + let mut highlight_config = snap.config.highlighting_config(); + // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. + highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded; + + let highlights = snap.analysis.highlight(highlight_config, file_id)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); let mut cache = snap.semantic_tokens_cache.lock(); let cached_tokens = cache.entry(params.text_document.uri).or_default(); @@ -1543,10 +1560,8 @@ pub(crate) fn handle_semantic_tokens_range( let text = snap.analysis.file_text(frange.file_id)?; let line_index = snap.file_line_index(frange.file_id)?; - let highlights = snap.analysis.highlight_range(frange)?; - let highlight_strings = snap.config.highlighting_strings(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } @@ -1764,7 +1779,7 @@ fn run_rustfmt( let line_index = snap.file_line_index(file_id)?; - let mut rustfmt = match snap.config.rustfmt() { + let mut command = match snap.config.rustfmt() { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { let mut cmd = process::Command::new(toolchain::rustfmt()); cmd.args(extra_args); @@ -1829,12 +1844,12 @@ fn run_rustfmt( } }; - let mut rustfmt = rustfmt + let mut rustfmt = command .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() - .context(format!("Failed to spawn {:?}", rustfmt))?; + .context(format!("Failed to spawn {:?}", command))?; rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; @@ -1853,7 +1868,11 @@ fn run_rustfmt( // formatting because otherwise an error is surfaced to the user on top of the // syntax error diagnostics they're already receiving. This is especially jarring // if they have format on save enabled. - tracing::info!("rustfmt exited with status 1, assuming parse error and ignoring"); + tracing::warn!( + ?command, + %captured_stderr, + "rustfmt exited with status 1" + ); Ok(None) } _ => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 47cdd8dfc..e49a98685 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -6,8 +6,8 @@ //! code here exercise this specific completion, and thus have a fast //! edit/compile/test cycle. //! -//! Note that "Rust Analyzer: Run" action does not allow running a single test -//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" +//! Note that "rust-analyzer: Run" action does not allow running a single test +//! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line" //! which you can use to paste the command in terminal and add `--release` manually. use std::sync::Arc; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs index 5f0e10862..e61c8b643 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs @@ -129,6 +129,14 @@ pub struct ExpandedMacro { pub expansion: String, } +pub enum CancelFlycheck {} + +impl Request for CancelFlycheck { + type Params = (); + type Result = (); + const METHOD: &'static str = "rust-analyzer/cancelFlycheck"; +} + pub enum MatchingBrace {} impl Request for MatchingBrace { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 5845cf712..3cfbc2e4e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -2,13 +2,16 @@ //! requests/replies and notifications back to the client. use std::{ fmt, + ops::Deref, sync::Arc, time::{Duration, Instant}, }; use always_assert::always; use crossbeam_channel::{select, Receiver}; -use ide_db::base_db::{SourceDatabaseExt, VfsPath}; +use flycheck::FlycheckHandle; +use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath}; +use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; use vfs::{ChangeKind, FileId}; @@ -203,81 +206,14 @@ impl GlobalState { } lsp_server::Message::Response(resp) => self.complete_request(resp), }, - Event::Task(mut task) => { + Event::Task(task) => { let _p = profile::span("GlobalState::handle_event/task"); let mut prime_caches_progress = Vec::new(); - loop { - match task { - Task::Response(response) => self.respond(response), - Task::Retry(req) => self.on_request(req), - Task::Diagnostics(diagnostics_per_file) => { - for (file_id, diagnostics) in diagnostics_per_file { - self.diagnostics.set_native_diagnostics(file_id, diagnostics) - } - } - Task::PrimeCaches(progress) => match progress { - PrimeCachesProgress::Begin => prime_caches_progress.push(progress), - PrimeCachesProgress::Report(_) => { - match prime_caches_progress.last_mut() { - Some(last @ PrimeCachesProgress::Report(_)) => { - // Coalesce subsequent update events. - *last = progress; - } - _ => prime_caches_progress.push(progress), - } - } - PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress), - }, - Task::FetchWorkspace(progress) => { - let (state, msg) = match progress { - ProjectWorkspaceProgress::Begin => (Progress::Begin, None), - ProjectWorkspaceProgress::Report(msg) => { - (Progress::Report, Some(msg)) - } - ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(workspaces); - - let old = Arc::clone(&self.workspaces); - self.switch_workspaces("fetched workspace".to_string()); - let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); - if self.config.run_build_scripts() && workspaces_updated { - self.fetch_build_data_queue - .request_op(format!("workspace updated")); - } - - (Progress::End, None) - } - }; - - self.report_progress("Fetching", state, msg, None); - } - Task::FetchBuildData(progress) => { - let (state, msg) = match progress { - BuildDataProgress::Begin => (Some(Progress::Begin), None), - BuildDataProgress::Report(msg) => { - (Some(Progress::Report), Some(msg)) - } - BuildDataProgress::End(build_data_result) => { - self.fetch_build_data_queue.op_completed(build_data_result); - - self.switch_workspaces("fetched build data".to_string()); - - (Some(Progress::End), None) - } - }; - - if let Some(state) = state { - self.report_progress("Loading", state, msg, None); - } - } - } - - // Coalesce multiple task events into one loop turn - task = match self.task_pool.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - }; + self.handle_task(&mut prime_caches_progress, task); + // Coalesce multiple task events into one loop turn + while let Ok(task) = self.task_pool.receiver.try_recv() { + self.handle_task(&mut prime_caches_progress, task); } for progress in prime_caches_progress { @@ -324,118 +260,20 @@ impl GlobalState { self.report_progress("Indexing", state, message, Some(fraction)); } } - Event::Vfs(mut task) => { + Event::Vfs(message) => { let _p = profile::span("GlobalState::handle_event/vfs"); - loop { - match task { - vfs::loader::Message::Loaded { files } => { - let vfs = &mut self.vfs.write().0; - for (path, contents) in files { - let path = VfsPath::from(path); - if !self.mem_docs.contains(&path) { - vfs.set_file_contents(path, contents); - } - } - } - vfs::loader::Message::Progress { n_total, n_done, config_version } => { - always!(config_version <= self.vfs_config_version); - - self.vfs_progress_config_version = config_version; - self.vfs_progress_n_total = n_total; - self.vfs_progress_n_done = n_done; - - let state = if n_done == 0 { - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - Progress::End - }; - self.report_progress( - "Roots Scanned", - state, - Some(format!("{}/{}", n_done, n_total)), - Some(Progress::fraction(n_done, n_total)), - ) - } - } - // Coalesce many VFS event into a single loop turn - task = match self.loader.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } + self.handle_vfs_msg(message); + // Coalesce many VFS event into a single loop turn + while let Ok(message) = self.loader.receiver.try_recv() { + self.handle_vfs_msg(message); } } - Event::Flycheck(mut task) => { + Event::Flycheck(message) => { let _p = profile::span("GlobalState::handle_event/flycheck"); - loop { - match task { - flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { - let snap = self.snapshot(); - let diagnostics = - crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( - &self.config.diagnostics_map(), - &diagnostic, - &workspace_root, - &snap, - ); - for diag in diagnostics { - match url_to_file_id(&self.vfs.read().0, &diag.url) { - Ok(file_id) => self.diagnostics.add_check_diagnostic( - file_id, - diag.diagnostic, - diag.fix, - ), - Err(err) => { - tracing::error!( - "File with cargo diagnostic not found in VFS: {}", - err - ); - } - }; - } - } - - flycheck::Message::Progress { id, progress } => { - let (state, message) = match progress { - flycheck::Progress::DidStart => { - self.diagnostics.clear_check(); - (Progress::Begin, None) - } - flycheck::Progress::DidCheckCrate(target) => { - (Progress::Report, Some(target)) - } - flycheck::Progress::DidCancel => (Progress::End, None), - flycheck::Progress::DidFinish(result) => { - if let Err(err) = result { - self.show_and_log_error( - "cargo check failed".to_string(), - Some(err.to_string()), - ); - } - (Progress::End, None) - } - }; - - // When we're running multiple flychecks, we have to include a disambiguator in - // the title, or the editor complains. Note that this is a user-facing string. - let title = if self.flycheck.len() == 1 { - match self.config.flycheck() { - Some(config) => format!("{}", config), - None => "cargo check".to_string(), - } - } else { - format!("cargo check (#{})", id + 1) - }; - self.report_progress(&title, state, message, None); - } - } - // Coalesce many flycheck updates into a single loop turn - task = match self.flycheck_receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } + self.handle_flycheck_msg(message); + // Coalesce many flycheck updates into a single loop turn + while let Ok(message) = self.flycheck_receiver.try_recv() { + self.handle_flycheck_msg(message); } } } @@ -444,10 +282,13 @@ impl GlobalState { let memdocs_added_or_removed = self.mem_docs.take_changes(); if self.is_quiescent() { - if !was_quiescent { - for flycheck in &self.flycheck { - flycheck.update(); - } + let became_quiescent = !(was_quiescent + || self.fetch_workspaces_queue.op_requested() + || self.fetch_build_data_queue.op_requested()); + + if became_quiescent { + // Project has loaded properly, kick off initial flycheck + self.flycheck.iter().for_each(FlycheckHandle::restart); if self.config.prefill_caches() { self.prime_caches_queue.request_op("became quiescent".to_string()); } @@ -486,28 +327,40 @@ impl GlobalState { continue; } - let url = file_id_to_url(&self.vfs.read().0, file_id); + let uri = file_id_to_url(&self.vfs.read().0, file_id); let mut diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); - // https://github.com/rust-lang/rust-analyzer/issues/11404 - for d in &mut diagnostics { - if d.message.is_empty() { - d.message = " ".to_string(); + + // VSCode assumes diagnostic messages to be non-empty strings, so we need to patch + // empty diagnostics. Neither the docs of VSCode nor the LSP spec say whether + // diagnostic messages are actually allowed to be empty or not and patching this + // in the VSCode client does not work as the assertion happens in the protocol + // conversion. So this hack is here to stay, and will be considered a hack + // until the LSP decides to state that empty messages are allowed. + + // See https://github.com/rust-lang/rust-analyzer/issues/11404 + // See https://github.com/rust-lang/rust-analyzer/issues/13130 + let patch_empty = |message: &mut String| { + if message.is_empty() { + *message = " ".to_string(); } - if let Some(rds) = d.related_information.as_mut() { - for rd in rds { - if rd.message.is_empty() { - rd.message = " ".to_string(); - } + }; + + for d in &mut diagnostics { + patch_empty(&mut d.message); + if let Some(dri) = &mut d.related_information { + for dri in dri { + patch_empty(&mut dri.message); } } } - let version = from_proto::vfs_path(&url) + + let version = from_proto::vfs_path(&uri) .map(|path| self.mem_docs.get(&path).map(|it| it.version)) .unwrap_or_default(); self.send_notification::( - lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version }, + lsp_types::PublishDiagnosticsParams { uri, diagnostics, version }, ); } } @@ -569,11 +422,178 @@ impl GlobalState { Ok(()) } + fn handle_task(&mut self, prime_caches_progress: &mut Vec, task: Task) { + match task { + Task::Response(response) => self.respond(response), + Task::Retry(req) => self.on_request(req), + Task::Diagnostics(diagnostics_per_file) => { + for (file_id, diagnostics) in diagnostics_per_file { + self.diagnostics.set_native_diagnostics(file_id, diagnostics) + } + } + Task::PrimeCaches(progress) => match progress { + PrimeCachesProgress::Begin => prime_caches_progress.push(progress), + PrimeCachesProgress::Report(_) => { + match prime_caches_progress.last_mut() { + Some(last @ PrimeCachesProgress::Report(_)) => { + // Coalesce subsequent update events. + *last = progress; + } + _ => prime_caches_progress.push(progress), + } + } + PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress), + }, + Task::FetchWorkspace(progress) => { + let (state, msg) = match progress { + ProjectWorkspaceProgress::Begin => (Progress::Begin, None), + ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), + ProjectWorkspaceProgress::End(workspaces) => { + self.fetch_workspaces_queue.op_completed(workspaces); + + let old = Arc::clone(&self.workspaces); + self.switch_workspaces("fetched workspace".to_string()); + let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); + + if self.config.run_build_scripts() && workspaces_updated { + self.fetch_build_data_queue.request_op(format!("workspace updated")); + } + + (Progress::End, None) + } + }; + + self.report_progress("Fetching", state, msg, None); + } + Task::FetchBuildData(progress) => { + let (state, msg) = match progress { + BuildDataProgress::Begin => (Some(Progress::Begin), None), + BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)), + BuildDataProgress::End(build_data_result) => { + self.fetch_build_data_queue.op_completed(build_data_result); + + self.switch_workspaces("fetched build data".to_string()); + + (Some(Progress::End), None) + } + }; + + if let Some(state) = state { + self.report_progress("Loading", state, msg, None); + } + } + } + } + + fn handle_vfs_msg(&mut self, message: vfs::loader::Message) { + match message { + vfs::loader::Message::Loaded { files } => { + let vfs = &mut self.vfs.write().0; + for (path, contents) in files { + let path = VfsPath::from(path); + if !self.mem_docs.contains(&path) { + vfs.set_file_contents(path, contents); + } + } + } + vfs::loader::Message::Progress { n_total, n_done, config_version } => { + always!(config_version <= self.vfs_config_version); + + self.vfs_progress_config_version = config_version; + self.vfs_progress_n_total = n_total; + self.vfs_progress_n_done = n_done; + + let state = if n_done == 0 { + Progress::Begin + } else if n_done < n_total { + Progress::Report + } else { + assert_eq!(n_done, n_total); + Progress::End + }; + self.report_progress( + "Roots Scanned", + state, + Some(format!("{}/{}", n_done, n_total)), + Some(Progress::fraction(n_done, n_total)), + ) + } + } + } + + fn handle_flycheck_msg(&mut self, message: flycheck::Message) { + match message { + flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { + let snap = self.snapshot(); + let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( + &self.config.diagnostics_map(), + &diagnostic, + &workspace_root, + &snap, + ); + for diag in diagnostics { + match url_to_file_id(&self.vfs.read().0, &diag.url) { + Ok(file_id) => self.diagnostics.add_check_diagnostic( + id, + file_id, + diag.diagnostic, + diag.fix, + ), + Err(err) => { + tracing::error!("File with cargo diagnostic not found in VFS: {}", err); + } + }; + } + } + + flycheck::Message::Progress { id, progress } => { + let (state, message) = match progress { + flycheck::Progress::DidStart => { + self.diagnostics.clear_check(id); + (Progress::Begin, None) + } + flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)), + flycheck::Progress::DidCancel => (Progress::End, None), + flycheck::Progress::DidFailToRestart(err) => { + self.show_and_log_error( + "cargo check failed".to_string(), + Some(err.to_string()), + ); + return; + } + flycheck::Progress::DidFinish(result) => { + if let Err(err) = result { + self.show_and_log_error( + "cargo check failed".to_string(), + Some(err.to_string()), + ); + } + (Progress::End, None) + } + }; + + // When we're running multiple flychecks, we have to include a disambiguator in + // the title, or the editor complains. Note that this is a user-facing string. + let title = if self.flycheck.len() == 1 { + match self.config.flycheck() { + Some(config) => format!("{}", config), + None => "cargo check".to_string(), + } + } else { + format!("cargo check (#{})", id + 1) + }; + self.report_progress(&title, state, message, None); + } + } + } + + /// Registers and handles a request. This should only be called once per incoming request. fn on_new_request(&mut self, request_received: Instant, req: Request) { self.register_request(&req, request_received); self.on_request(req); } + /// Handles a request. fn on_request(&mut self, req: Request) { if self.shutdown_requested { self.respond(lsp_server::Response::new_err( @@ -602,6 +622,7 @@ impl GlobalState { .on_sync_mut::(handlers::handle_workspace_reload) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) + .on_sync_mut::(handlers::handle_cancel_flycheck) .on_sync::(handlers::handle_join_lines) .on_sync::(handlers::handle_on_enter) .on_sync::(handlers::handle_selection_range) @@ -664,6 +685,7 @@ impl GlobalState { .finish(); } + /// Handles an incoming notification. fn on_notification(&mut self, not: Notification) -> Result<()> { NotificationDispatcher { not: Some(not), global_state: self } .on::(|this, params| { @@ -734,13 +756,82 @@ impl GlobalState { Ok(()) })? .on::(|this, params| { - for flycheck in &this.flycheck { - flycheck.update(); + let mut updated = false; + if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + let (vfs, _) = &*this.vfs.read(); + + // Trigger flychecks for all workspaces that depend on the saved file + if let Some(file_id) = vfs.file_id(&vfs_path) { + let analysis = this.analysis_host.analysis(); + // Crates containing or depending on the saved file + let crate_ids: Vec<_> = analysis + .crate_for(file_id)? + .into_iter() + .flat_map(|id| { + this.analysis_host + .raw_database() + .crate_graph() + .transitive_rev_deps(id) + }) + .sorted() + .unique() + .collect(); + + let crate_root_paths: Vec<_> = crate_ids + .iter() + .filter_map(|&crate_id| { + analysis + .crate_root(crate_id) + .map(|file_id| { + vfs.file_path(file_id).as_path().map(ToOwned::to_owned) + }) + .transpose() + }) + .collect::>()?; + let crate_root_paths: Vec<_> = + crate_root_paths.iter().map(Deref::deref).collect(); + + // Find all workspaces that have at least one target containing the saved file + let workspace_ids = + this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { + project_model::ProjectWorkspace::Cargo { cargo, .. } => { + cargo.packages().any(|pkg| { + cargo[pkg].targets.iter().any(|&it| { + crate_root_paths.contains(&cargo[it].root.as_path()) + }) + }) + } + project_model::ProjectWorkspace::Json { project, .. } => project + .crates() + .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), + project_model::ProjectWorkspace::DetachedFiles { .. } => false, + }); + + // Find and trigger corresponding flychecks + for flycheck in &this.flycheck { + for (id, _) in workspace_ids.clone() { + if id == flycheck.id() { + updated = true; + flycheck.restart(); + continue; + } + } + } + } + + // Re-fetch workspaces if a workspace related file has changed + if let Some(abs_path) = vfs_path.as_path() { + if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { + this.fetch_workspaces_queue + .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + } + } } - if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { - if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { - this.fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + + // No specific flycheck was triggered, so let's trigger all of them. + if !updated { + for flycheck in &this.flycheck { + flycheck.restart(); } } Ok(()) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index eaab275bc..e47f70fff 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -196,10 +196,7 @@ impl GlobalState { } if let Err(error) = self.fetch_build_data_error() { - self.show_and_log_error( - "rust-analyzer failed to run build scripts".to_string(), - Some(error), - ); + self.show_and_log_error("failed to run build scripts".to_string(), Some(error)); } let workspaces = self @@ -222,6 +219,7 @@ impl GlobalState { cfg_overrides, build_scripts: _, + toolchain: _, } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)), _ => None, }; @@ -308,6 +306,7 @@ impl GlobalState { if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { + tracing::info!("Spawning proc-macro servers"); self.proc_macro_clients = self .workspaces .iter() @@ -315,21 +314,23 @@ impl GlobalState { let mut args = args.clone(); let mut path = path.clone(); - if let ProjectWorkspace::Cargo { sysroot, .. } = ws { - tracing::info!("Found a cargo workspace..."); + if let ProjectWorkspace::Cargo { sysroot, .. } + | ProjectWorkspace::Json { sysroot, .. } = ws + { + tracing::debug!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { - tracing::info!("Found a cargo workspace with a sysroot..."); + tracing::debug!("Found a cargo workspace with a sysroot..."); let server_path = sysroot.root().join("libexec").join(&standalone_server_name); if std::fs::metadata(&server_path).is_ok() { - tracing::info!( + tracing::debug!( "And the server exists at {}", server_path.display() ); path = server_path; args = vec![]; } else { - tracing::info!( + tracing::debug!( "And the server does not exist at {}", server_path.display() ); @@ -337,14 +338,10 @@ impl GlobalState { } } - tracing::info!( - "Using proc-macro server at {} with args {:?}", - path.display(), - args - ); + tracing::info!(?args, "Using proc-macro server at {}", path.display(),); ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( - "Failed to run proc_macro_srv from path {}, error: {:?}", + "Failed to run proc-macro server from path {}, error: {:?}", path.display(), err ); @@ -352,8 +349,8 @@ impl GlobalState { error }) }) - .collect(); - } + .collect() + }; } let watch = match files_config.watcher { @@ -458,7 +455,7 @@ impl GlobalState { Some(it) => it, None => { self.flycheck = Vec::new(); - self.diagnostics.clear_check(); + self.diagnostics.clear_check_all(); return; } }; @@ -621,7 +618,10 @@ pub(crate) fn load_proc_macro( }; let expander: Arc = if dummy_replace.iter().any(|replace| &**replace == name) { - Arc::new(DummyExpander) + match kind { + ProcMacroKind::Attr => Arc::new(IdentityExpander), + _ => Arc::new(EmptyExpander), + } } else { Arc::new(Expander(expander)) }; @@ -647,11 +647,11 @@ pub(crate) fn load_proc_macro( } } - /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user. + /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. #[derive(Debug)] - struct DummyExpander; + struct IdentityExpander; - impl ProcMacroExpander for DummyExpander { + impl ProcMacroExpander for IdentityExpander { fn expand( &self, subtree: &tt::Subtree, @@ -661,27 +661,46 @@ pub(crate) fn load_proc_macro( Ok(subtree.clone()) } } + + /// Empty expander, used for proc-macros that are deliberately ignored by the user. + #[derive(Debug)] + struct EmptyExpander; + + impl ProcMacroExpander for EmptyExpander { + fn expand( + &self, + _: &tt::Subtree, + _: Option<&tt::Subtree>, + _: &Env, + ) -> Result { + Ok(tt::Subtree::default()) + } + } } pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; - let file_name = path.file_name().unwrap_or_default(); - if file_name == "Cargo.toml" || file_name == "Cargo.lock" { + let file_name = match path.file_name().unwrap_or_default().to_str() { + Some(it) => it, + None => return false, + }; + + if let "Cargo.toml" | "Cargo.lock" = file_name { return true; } if change_kind == ChangeKind::Modify { return false; } + + // .cargo/config{.toml} if path.extension().unwrap_or_default() != "rs" { - if (file_name == "config.toml" || file_name == "config") - && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true) - { - return true; - } - return false; + let is_cargo_config = matches!(file_name, "config.toml" | "config") + && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false); + return is_cargo_config; } + if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) { return true; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs index 6c78b5df1..c48410ed5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs @@ -8,107 +8,130 @@ use lsp_types::{ }; macro_rules! define_semantic_token_types { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)* + ( + standard { + $($standard:ident),*$(,)? + } + custom { + $(($custom:ident, $string:literal)),*$(,)? + } + + ) => { + $(pub(crate) const $standard: SemanticTokenType = SemanticTokenType::$standard;)* + $(pub(crate) const $custom: SemanticTokenType = SemanticTokenType::new($string);)* pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ - SemanticTokenType::COMMENT, - SemanticTokenType::KEYWORD, - SemanticTokenType::STRING, - SemanticTokenType::NUMBER, - SemanticTokenType::REGEXP, - SemanticTokenType::OPERATOR, - SemanticTokenType::NAMESPACE, - SemanticTokenType::TYPE, - SemanticTokenType::STRUCT, - SemanticTokenType::CLASS, - SemanticTokenType::INTERFACE, - SemanticTokenType::ENUM, - SemanticTokenType::ENUM_MEMBER, - SemanticTokenType::TYPE_PARAMETER, - SemanticTokenType::FUNCTION, - SemanticTokenType::METHOD, - SemanticTokenType::PROPERTY, - SemanticTokenType::MACRO, - SemanticTokenType::VARIABLE, - SemanticTokenType::PARAMETER, - $($ident),* + $(SemanticTokenType::$standard,)* + $($custom),* ]; }; } define_semantic_token_types![ - (ANGLE, "angle"), - (ARITHMETIC, "arithmetic"), - (ATTRIBUTE, "attribute"), - (ATTRIBUTE_BRACKET, "attributeBracket"), - (BITWISE, "bitwise"), - (BOOLEAN, "boolean"), - (BRACE, "brace"), - (BRACKET, "bracket"), - (BUILTIN_ATTRIBUTE, "builtinAttribute"), - (BUILTIN_TYPE, "builtinType"), - (CHAR, "character"), - (COLON, "colon"), - (COMMA, "comma"), - (COMPARISON, "comparison"), - (CONST_PARAMETER, "constParameter"), - (DERIVE, "derive"), - (DERIVE_HELPER, "deriveHelper"), - (DOT, "dot"), - (ESCAPE_SEQUENCE, "escapeSequence"), - (FORMAT_SPECIFIER, "formatSpecifier"), - (GENERIC, "generic"), - (LABEL, "label"), - (LIFETIME, "lifetime"), - (LOGICAL, "logical"), - (MACRO_BANG, "macroBang"), - (OPERATOR, "operator"), - (PARENTHESIS, "parenthesis"), - (PUNCTUATION, "punctuation"), - (SELF_KEYWORD, "selfKeyword"), - (SELF_TYPE_KEYWORD, "selfTypeKeyword"), - (SEMICOLON, "semicolon"), - (TYPE_ALIAS, "typeAlias"), - (TOOL_MODULE, "toolModule"), - (UNION, "union"), - (UNRESOLVED_REFERENCE, "unresolvedReference"), + standard { + COMMENT, + DECORATOR, + ENUM_MEMBER, + ENUM, + FUNCTION, + INTERFACE, + KEYWORD, + MACRO, + METHOD, + NAMESPACE, + NUMBER, + OPERATOR, + PARAMETER, + PROPERTY, + STRING, + STRUCT, + TYPE_PARAMETER, + VARIABLE, + } + + custom { + (ANGLE, "angle"), + (ARITHMETIC, "arithmetic"), + (ATTRIBUTE, "attribute"), + (ATTRIBUTE_BRACKET, "attributeBracket"), + (BITWISE, "bitwise"), + (BOOLEAN, "boolean"), + (BRACE, "brace"), + (BRACKET, "bracket"), + (BUILTIN_ATTRIBUTE, "builtinAttribute"), + (BUILTIN_TYPE, "builtinType"), + (CHAR, "character"), + (COLON, "colon"), + (COMMA, "comma"), + (COMPARISON, "comparison"), + (CONST_PARAMETER, "constParameter"), + (DERIVE, "derive"), + (DERIVE_HELPER, "deriveHelper"), + (DOT, "dot"), + (ESCAPE_SEQUENCE, "escapeSequence"), + (FORMAT_SPECIFIER, "formatSpecifier"), + (GENERIC, "generic"), + (LABEL, "label"), + (LIFETIME, "lifetime"), + (LOGICAL, "logical"), + (MACRO_BANG, "macroBang"), + (PARENTHESIS, "parenthesis"), + (PUNCTUATION, "punctuation"), + (SELF_KEYWORD, "selfKeyword"), + (SELF_TYPE_KEYWORD, "selfTypeKeyword"), + (SEMICOLON, "semicolon"), + (TYPE_ALIAS, "typeAlias"), + (TOOL_MODULE, "toolModule"), + (UNION, "union"), + (UNRESOLVED_REFERENCE, "unresolvedReference"), + } ]; macro_rules! define_semantic_token_modifiers { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)* + ( + standard { + $($standard:ident),*$(,)? + } + custom { + $(($custom:ident, $string:literal)),*$(,)? + } + + ) => { + + $(pub(crate) const $standard: SemanticTokenModifier = SemanticTokenModifier::$standard;)* + $(pub(crate) const $custom: SemanticTokenModifier = SemanticTokenModifier::new($string);)* pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ - SemanticTokenModifier::DOCUMENTATION, - SemanticTokenModifier::DECLARATION, - SemanticTokenModifier::DEFINITION, - SemanticTokenModifier::STATIC, - SemanticTokenModifier::ABSTRACT, - SemanticTokenModifier::DEPRECATED, - SemanticTokenModifier::READONLY, - SemanticTokenModifier::DEFAULT_LIBRARY, - $($ident),* + $(SemanticTokenModifier::$standard,)* + $($custom),* ]; }; } define_semantic_token_modifiers![ - (ASYNC, "async"), - (ATTRIBUTE_MODIFIER, "attribute"), - (CALLABLE, "callable"), - (CONSTANT, "constant"), - (CONSUMING, "consuming"), - (CONTROL_FLOW, "controlFlow"), - (CRATE_ROOT, "crateRoot"), - (INJECTED, "injected"), - (INTRA_DOC_LINK, "intraDocLink"), - (LIBRARY, "library"), - (MUTABLE, "mutable"), - (PUBLIC, "public"), - (REFERENCE, "reference"), - (TRAIT_MODIFIER, "trait"), - (UNSAFE, "unsafe"), + standard { + DOCUMENTATION, + DECLARATION, + STATIC, + DEFAULT_LIBRARY, + } + custom { + (ASYNC, "async"), + (ATTRIBUTE_MODIFIER, "attribute"), + (CALLABLE, "callable"), + (CONSTANT, "constant"), + (CONSUMING, "consuming"), + (CONTROL_FLOW, "controlFlow"), + (CRATE_ROOT, "crateRoot"), + (INJECTED, "injected"), + (INTRA_DOC_LINK, "intraDocLink"), + (LIBRARY, "library"), + (MUTABLE, "mutable"), + (PUBLIC, "public"), + (REFERENCE, "reference"), + (TRAIT_MODIFIER, "trait"), + (UNSAFE, "unsafe"), + } ]; #[derive(Default)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs index 7f4fa57fa..e083b9d0e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs @@ -9,8 +9,9 @@ use ide::{ Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, - InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, - SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, + InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, + Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, + TextSize, }; use itertools::Itertools; use serde_json::to_value; @@ -426,9 +427,16 @@ pub(crate) fn inlay_hint( snap: &GlobalStateSnapshot, line_index: &LineIndex, render_colons: bool, - inlay_hint: InlayHint, -) -> lsp_types::InlayHint { - lsp_types::InlayHint { + mut inlay_hint: InlayHint, +) -> Result { + match inlay_hint.kind { + InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"), + InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "), + InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "), + _ => {} + } + + Ok(lsp_types::InlayHint { position: match inlay_hint.kind { // before annotated thing InlayKind::ParameterHint @@ -459,15 +467,9 @@ pub(crate) fn inlay_hint( | InlayKind::ImplicitReborrowHint | InlayKind::TypeHint | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => inlay_hint.label != "&", + InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"), InlayKind::ParameterHint | InlayKind::LifetimeHint => true, }), - label: lsp_types::InlayHintLabel::String(match inlay_hint.kind { - InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label), - InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label), - InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label), - _ => inlay_hint.label.clone(), - }), kind: match inlay_hint.kind { InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER), InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => { @@ -506,9 +508,36 @@ pub(crate) fn inlay_hint( })(), tooltip: Some(match inlay_hint.tooltip { Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s), - _ => lsp_types::InlayHintTooltip::String(inlay_hint.label), + _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()), }), - } + label: inlay_hint_label(snap, inlay_hint.label)?, + }) +} + +fn inlay_hint_label( + snap: &GlobalStateSnapshot, + label: InlayHintLabel, +) -> Result { + Ok(match label.as_simple_str() { + Some(s) => lsp_types::InlayHintLabel::String(s.into()), + None => lsp_types::InlayHintLabel::LabelParts( + label + .parts + .into_iter() + .map(|part| { + Ok(lsp_types::InlayHintLabelPart { + value: part.text, + tooltip: None, + location: part + .linked_location + .map(|range| location(snap, range)) + .transpose()?, + command: None, + }) + }) + .collect::>>()?, + ), + }) } static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); @@ -517,7 +546,6 @@ pub(crate) fn semantic_tokens( text: &str, line_index: &LineIndex, highlights: Vec, - highlight_strings: bool, ) -> lsp_types::SemanticTokens { let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); @@ -526,10 +554,8 @@ pub(crate) fn semantic_tokens( if highlight_range.highlight.is_empty() { continue; } + let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); - if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING { - continue; - } let token_index = semantic_tokens::type_index(ty); let modifier_bitset = mods.0; @@ -561,55 +587,55 @@ fn semantic_token_type_and_modifiers( let mut mods = semantic_tokens::ModifierSet::default(); let type_ = match highlight.tag { HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => semantic_tokens::ATTRIBUTE, + SymbolKind::Attribute => semantic_tokens::DECORATOR, SymbolKind::Derive => semantic_tokens::DERIVE, SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, - SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, + SymbolKind::Module => semantic_tokens::NAMESPACE, SymbolKind::Impl => semantic_tokens::TYPE_ALIAS, - SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, - SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, + SymbolKind::Field => semantic_tokens::PROPERTY, + SymbolKind::TypeParam => semantic_tokens::TYPE_PARAMETER, SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, SymbolKind::Label => semantic_tokens::LABEL, - SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, + SymbolKind::ValueParam => semantic_tokens::PARAMETER, SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD, - SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, + SymbolKind::Local => semantic_tokens::VARIABLE, SymbolKind::Function => { if highlight.mods.contains(HlMod::Associated) { - lsp_types::SemanticTokenType::METHOD + semantic_tokens::METHOD } else { - lsp_types::SemanticTokenType::FUNCTION + semantic_tokens::FUNCTION } } SymbolKind::Const => { mods |= semantic_tokens::CONSTANT; - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE + mods |= semantic_tokens::STATIC; + semantic_tokens::VARIABLE } SymbolKind::Static => { - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE + mods |= semantic_tokens::STATIC; + semantic_tokens::VARIABLE } - SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT, - SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM, - SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER, + SymbolKind::Struct => semantic_tokens::STRUCT, + SymbolKind::Enum => semantic_tokens::ENUM, + SymbolKind::Variant => semantic_tokens::ENUM_MEMBER, SymbolKind::Union => semantic_tokens::UNION, SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS, - SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, - SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, + SymbolKind::Trait => semantic_tokens::INTERFACE, + SymbolKind::Macro => semantic_tokens::MACRO, SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE, SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE, }, HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET, HlTag::BoolLiteral => semantic_tokens::BOOLEAN, HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, - HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, + HlTag::ByteLiteral | HlTag::NumericLiteral => semantic_tokens::NUMBER, HlTag::CharLiteral => semantic_tokens::CHAR, - HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, + HlTag::Comment => semantic_tokens::COMMENT, HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, - HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, + HlTag::Keyword => semantic_tokens::KEYWORD, HlTag::None => semantic_tokens::GENERIC, HlTag::Operator(op) => match op { HlOperator::Bitwise => semantic_tokens::BITWISE, @@ -618,7 +644,7 @@ fn semantic_token_type_and_modifiers( HlOperator::Comparison => semantic_tokens::COMPARISON, HlOperator::Other => semantic_tokens::OPERATOR, }, - HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, + HlTag::StringLiteral => semantic_tokens::STRING, HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, HlTag::Punctuation(punct) => match punct { HlPunct::Bracket => semantic_tokens::BRACKET, @@ -643,16 +669,16 @@ fn semantic_token_type_and_modifiers( HlMod::Consuming => semantic_tokens::CONSUMING, HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW, HlMod::CrateRoot => semantic_tokens::CRATE_ROOT, - HlMod::DefaultLibrary => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY, - HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION, - HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION, + HlMod::DefaultLibrary => semantic_tokens::DEFAULT_LIBRARY, + HlMod::Definition => semantic_tokens::DECLARATION, + HlMod::Documentation => semantic_tokens::DOCUMENTATION, HlMod::Injected => semantic_tokens::INJECTED, HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, HlMod::Library => semantic_tokens::LIBRARY, HlMod::Mutable => semantic_tokens::MUTABLE, HlMod::Public => semantic_tokens::PUBLIC, HlMod::Reference => semantic_tokens::REFERENCE, - HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, + HlMod::Static => semantic_tokens::STATIC, HlMod::Trait => semantic_tokens::TRAIT_MODIFIER, HlMod::Unsafe => semantic_tokens::UNSAFE, }; @@ -1386,7 +1412,7 @@ fn main() { #[test] #[cfg(target_os = "windows")] fn test_lowercase_drive_letter() { - use std::{convert::TryInto, path::Path}; + use std::path::Path; let url = url_from_abs_path(Path::new("C:\\Test").try_into().unwrap()); assert_eq!(url.to_string(), "file:///c:/Test"); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs index 18f95925d..58099a58d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -13,9 +13,8 @@ use xshell::cmd; fn check_code_formatting() { let sh = &Shell::new().unwrap(); sh.change_dir(sourcegen::project_root()); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); - let out = cmd!(sh, "rustfmt --version").read().unwrap(); + let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap(); if !out.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -23,9 +22,9 @@ fn check_code_formatting() { ) } - let res = cmd!(sh, "cargo fmt -- --check").run(); + let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run(); if res.is_err() { - let _ = cmd!(sh, "cargo fmt").run(); + let _ = cmd!(sh, "rustup run stable cargo fmt").run(); } res.unwrap() } diff --git a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs index ce0224ec7..4e0ee63f3 100644 --- a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs +++ b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs @@ -136,7 +136,7 @@ impl fmt::Display for Location { } fn ensure_rustfmt(sh: &Shell) { - let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default(); + let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default(); if !version.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -147,13 +147,15 @@ fn ensure_rustfmt(sh: &Shell) { pub fn reformat(text: String) -> String { let sh = Shell::new().unwrap(); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); ensure_rustfmt(&sh); let rustfmt_toml = project_root().join("rustfmt.toml"); - let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true") - .stdin(text) - .read() - .unwrap(); + let mut stdout = cmd!( + sh, + "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true" + ) + .stdin(text) + .read() + .unwrap(); if !stdout.ends_with('\n') { stdout.push('\n'); } diff --git a/src/tools/rust-analyzer/crates/stdx/src/hash.rs b/src/tools/rust-analyzer/crates/stdx/src/hash.rs new file mode 100644 index 000000000..9909d71bd --- /dev/null +++ b/src/tools/rust-analyzer/crates/stdx/src/hash.rs @@ -0,0 +1,80 @@ +//! A none hashing [`Hasher`] implementation. +use std::{ + hash::{BuildHasher, Hasher}, + marker::PhantomData, +}; + +pub type NoHashHashMap = std::collections::HashMap>; +pub type NoHashHashSet = std::collections::HashSet>; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct NoHashHasherBuilder(PhantomData); + +impl Default for NoHashHasherBuilder { + fn default() -> Self { + Self(Default::default()) + } +} + +pub trait NoHashHashable {} +impl NoHashHashable for usize {} +impl NoHashHashable for u32 {} + +pub struct NoHashHasher(u64); + +impl BuildHasher for NoHashHasherBuilder { + type Hasher = NoHashHasher; + fn build_hasher(&self) -> Self::Hasher { + NoHashHasher(0) + } +} + +impl Hasher for NoHashHasher { + fn finish(&self) -> u64 { + self.0 + } + + fn write(&mut self, _: &[u8]) { + unimplemented!("NoHashHasher should only be used for hashing primitive integers") + } + + fn write_u8(&mut self, i: u8) { + self.0 = i as u64; + } + + fn write_u16(&mut self, i: u16) { + self.0 = i as u64; + } + + fn write_u32(&mut self, i: u32) { + self.0 = i as u64; + } + + fn write_u64(&mut self, i: u64) { + self.0 = i as u64; + } + + fn write_usize(&mut self, i: usize) { + self.0 = i as u64; + } + + fn write_i8(&mut self, i: i8) { + self.0 = i as u64; + } + + fn write_i16(&mut self, i: i16) { + self.0 = i as u64; + } + + fn write_i32(&mut self, i: i32) { + self.0 = i as u64; + } + + fn write_i64(&mut self, i: i64) { + self.0 = i as u64; + } + + fn write_isize(&mut self, i: isize) { + self.0 = i as u64; + } +} diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index b4d45206c..51e109798 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -7,6 +7,7 @@ use std::{cmp::Ordering, ops, time::Instant}; use std::{io as sio, iter}; mod macros; +pub mod hash; pub mod process; pub mod panic_context; pub mod non_empty_vec; diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 62aa47839..894795435 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -343,7 +343,6 @@ Expr = | Literal | LoopExpr | MacroExpr -| MacroStmts | MatchExpr | MethodCallExpr | ParenExpr diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index e3e928aec..eadebbe8a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -11,7 +11,7 @@ use crate::{ ted::{self, Position}, AstNode, AstToken, Direction, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, - SyntaxNode, + SyntaxNode, SyntaxToken, }; use super::HasName; @@ -248,8 +248,12 @@ impl ast::WhereClause { } } -impl ast::TypeBoundList { - pub fn remove(&self) { +pub trait Removable: AstNode { + fn remove(&self); +} + +impl Removable for ast::TypeBoundList { + fn remove(&self) { match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) { Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()), None => ted::remove(self.syntax()), @@ -267,8 +271,8 @@ impl ast::PathSegment { } } -impl ast::UseTree { - pub fn remove(&self) { +impl Removable for ast::UseTree { + fn remove(&self) { for dir in [Direction::Next, Direction::Prev] { if let Some(next_use_tree) = neighbor(self, dir) { let separators = self @@ -282,7 +286,9 @@ impl ast::UseTree { } ted::remove(self.syntax()); } +} +impl ast::UseTree { pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { match self.use_tree_list() { Some(it) => it, @@ -373,8 +379,8 @@ impl ast::UseTreeList { } } -impl ast::Use { - pub fn remove(&self) { +impl Removable for ast::Use { + fn remove(&self) { let next_ws = self .syntax() .next_sibling_or_token() @@ -444,8 +450,8 @@ impl ast::Fn { } } -impl ast::MatchArm { - pub fn remove(&self) { +impl Removable for ast::MatchArm { + fn remove(&self) { if let Some(sibling) = self.syntax().prev_sibling_or_token() { if sibling.kind() == SyntaxKind::WHITESPACE { ted::remove(sibling); @@ -506,19 +512,7 @@ impl ast::RecordExprFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let comma = get_or_insert_comma_after(last_field.syntax()); Position::after(comma) } None => match self.l_curly_token() { @@ -579,19 +573,8 @@ impl ast::RecordPatFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let syntax = last_field.syntax(); + let comma = get_or_insert_comma_after(syntax); Position::after(comma) } None => match self.l_curly_token() { @@ -606,12 +589,53 @@ impl ast::RecordPatFieldList { } } } + +fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken { + let comma = match syntax + .siblings_with_tokens(Direction::Next) + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T![,]) + { + Some(it) => it, + None => { + let comma = ast::make::token(T![,]); + ted::insert(Position::after(syntax), &comma); + comma + } + }; + comma +} + impl ast::StmtList { pub fn push_front(&self, statement: ast::Stmt) { ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax()); } } +impl ast::VariantList { + pub fn add_variant(&self, variant: ast::Variant) { + let (indent, position) = match self.variants().last() { + Some(last_item) => ( + IndentLevel::from_node(last_item.syntax()), + Position::after(get_or_insert_comma_after(last_item.syntax())), + ), + None => match self.l_curly_token() { + Some(l_curly) => { + normalize_ws_between_braces(self.syntax()); + (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) + } + None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + }, + }; + let elements: Vec> = vec![ + make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(), + variant.syntax().clone().into(), + ast::make::token(T![,]).into(), + ]; + ted::insert_all(position, elements); + } +} + fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { let l = node .children_with_tokens() @@ -661,6 +685,9 @@ impl Indent for N {} mod tests { use std::fmt; + use stdx::trim_indent; + use test_utils::assert_eq_text; + use crate::SourceFile; use super::*; @@ -714,4 +741,100 @@ mod tests { }", ); } + + #[test] + fn add_variant_to_empty_enum() { + let variant = make::variant(make::name("Bar"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo {} +"#, + r#" +enum Foo { + Bar, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_to_non_empty_enum() { + let variant = make::variant(make::name("Baz"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_tuple_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once( + make::tuple_field(None, make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz(bool), +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_record_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once( + make::record_field(None, make::name("x"), make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz { x: bool }, +} +"#, + variant, + ); + } + + fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) { + let enum_ = ast_mut_from_text::(before); + enum_.variant_list().map(|it| it.add_variant(variant)); + let after = enum_.to_string(); + assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim())); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 63309a155..449402e5f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1526,7 +1526,6 @@ pub enum Expr { Literal(Literal), LoopExpr(LoopExpr), MacroExpr(MacroExpr), - MacroStmts(MacroStmts), MatchExpr(MatchExpr), MethodCallExpr(MethodCallExpr), ParenExpr(ParenExpr), @@ -3169,10 +3168,7 @@ impl From for GenericArg { } impl AstNode for GenericArg { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true, - _ => false, - } + matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3237,12 +3233,23 @@ impl From for Type { } impl AstNode for Type { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE - | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE - | SLICE_TYPE | TUPLE_TYPE => true, - _ => false, - } + matches!( + kind, + ARRAY_TYPE + | DYN_TRAIT_TYPE + | FN_PTR_TYPE + | FOR_TYPE + | IMPL_TRAIT_TYPE + | INFER_TYPE + | MACRO_TYPE + | NEVER_TYPE + | PAREN_TYPE + | PATH_TYPE + | PTR_TYPE + | REF_TYPE + | SLICE_TYPE + | TUPLE_TYPE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3334,9 +3341,6 @@ impl From for Expr { impl From for Expr { fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) } } -impl From for Expr { - fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) } -} impl From for Expr { fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } } @@ -3384,15 +3388,41 @@ impl From for Expr { } impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR - | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR - | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR - | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR - | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR - | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true, - _ => false, - } + matches!( + kind, + ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BLOCK_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MACRO_EXPR + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | RECORD_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3413,7 +3443,6 @@ impl AstNode for Expr { LITERAL => Expr::Literal(Literal { syntax }), LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }), - MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }), MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), @@ -3452,7 +3481,6 @@ impl AstNode for Expr { Expr::Literal(it) => &it.syntax, Expr::LoopExpr(it) => &it.syntax, Expr::MacroExpr(it) => &it.syntax, - Expr::MacroStmts(it) => &it.syntax, Expr::MatchExpr(it) => &it.syntax, Expr::MethodCallExpr(it) => &it.syntax, Expr::ParenExpr(it) => &it.syntax, @@ -3521,11 +3549,25 @@ impl From for Item { } impl AstNode for Item { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES - | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_CALL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3629,12 +3671,25 @@ impl From for Pat { } impl AstNode for Pat { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT - | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT - | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true, - _ => false, - } + matches!( + kind, + IDENT_PAT + | BOX_PAT + | REST_PAT + | LITERAL_PAT + | MACRO_PAT + | OR_PAT + | PAREN_PAT + | PATH_PAT + | WILDCARD_PAT + | RANGE_PAT + | RECORD_PAT + | REF_PAT + | SLICE_PAT + | TUPLE_PAT + | TUPLE_STRUCT_PAT + | CONST_BLOCK_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3686,12 +3741,7 @@ impl From for FieldList { fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) } } impl AstNode for FieldList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }), @@ -3717,12 +3767,7 @@ impl From for Adt { fn from(node: Union) -> Adt { Adt::Union(node) } } impl AstNode for Adt { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | STRUCT | UNION => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { ENUM => Adt::Enum(Enum { syntax }), @@ -3753,12 +3798,7 @@ impl From for AssocItem { fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) } } impl AstNode for AssocItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | FN | MACRO_CALL | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { CONST => AssocItem::Const(Const { syntax }), @@ -3791,12 +3831,7 @@ impl From for ExternItem { fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) } } impl AstNode for ExternItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FN | MACRO_CALL | STATIC | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { FN => ExternItem::Fn(Fn { syntax }), @@ -3827,10 +3862,7 @@ impl From for GenericParam { } impl AstNode for GenericParam { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true, - _ => false, - } + matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3856,12 +3888,7 @@ impl AnyHasArgList { } } impl AstNode for AnyHasArgList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CALL_EXPR | METHOD_CALL_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax }) } @@ -3875,76 +3902,76 @@ impl AnyHasAttrs { } impl AstNode for AnyHasAttrs { fn can_cast(kind: SyntaxKind) -> bool { - match kind { + matches!( + kind, MACRO_CALL - | SOURCE_FILE - | CONST - | ENUM - | EXTERN_BLOCK - | EXTERN_CRATE - | FN - | IMPL - | MACRO_RULES - | MACRO_DEF - | MODULE - | STATIC - | STRUCT - | TRAIT - | TYPE_ALIAS - | UNION - | USE - | ITEM_LIST - | BLOCK_EXPR - | SELF_PARAM - | PARAM - | RECORD_FIELD - | TUPLE_FIELD - | VARIANT - | ASSOC_ITEM_LIST - | EXTERN_ITEM_LIST - | CONST_PARAM - | LIFETIME_PARAM - | TYPE_PARAM - | LET_STMT - | ARRAY_EXPR - | AWAIT_EXPR - | BIN_EXPR - | BOX_EXPR - | BREAK_EXPR - | CALL_EXPR - | CAST_EXPR - | CLOSURE_EXPR - | CONTINUE_EXPR - | FIELD_EXPR - | FOR_EXPR - | IF_EXPR - | INDEX_EXPR - | LITERAL - | LOOP_EXPR - | MATCH_EXPR - | METHOD_CALL_EXPR - | PAREN_EXPR - | PATH_EXPR - | PREFIX_EXPR - | RANGE_EXPR - | REF_EXPR - | RETURN_EXPR - | TRY_EXPR - | TUPLE_EXPR - | WHILE_EXPR - | YIELD_EXPR - | LET_EXPR - | UNDERSCORE_EXPR - | STMT_LIST - | RECORD_EXPR_FIELD_LIST - | RECORD_EXPR_FIELD - | MATCH_ARM_LIST - | MATCH_ARM - | IDENT_PAT - | REST_PAT - | RECORD_PAT_FIELD => true, - _ => false, - } + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | ITEM_LIST + | BLOCK_EXPR + | SELF_PARAM + | PARAM + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + | ASSOC_ITEM_LIST + | EXTERN_ITEM_LIST + | CONST_PARAM + | LIFETIME_PARAM + | TYPE_PARAM + | LET_STMT + | ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + | STMT_LIST + | RECORD_EXPR_FIELD_LIST + | RECORD_EXPR_FIELD + | MATCH_ARM_LIST + | MATCH_ARM + | IDENT_PAT + | REST_PAT + | RECORD_PAT_FIELD + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax }) @@ -3959,12 +3986,29 @@ impl AnyHasDocComments { } impl AstNode for AnyHasDocComments { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL - | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION - | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true, - _ => false, - } + matches!( + kind, + MACRO_CALL + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax }) @@ -3979,10 +4023,7 @@ impl AnyHasGenericParams { } impl AstNode for AnyHasGenericParams { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true, - _ => false, - } + matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax }) @@ -3996,12 +4037,7 @@ impl AnyHasLoopBody { } } impl AstNode for AnyHasLoopBody { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax }) } @@ -4014,12 +4050,7 @@ impl AnyHasModuleItem { } } impl AstNode for AnyHasModuleItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax }) } @@ -4033,12 +4064,27 @@ impl AnyHasName { } impl AstNode for AnyHasName { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT - | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM - | TYPE_PARAM | IDENT_PAT => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | FN + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | RENAME + | SELF_PARAM + | RECORD_FIELD + | VARIANT + | CONST_PARAM + | TYPE_PARAM + | IDENT_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax }) @@ -4053,10 +4099,10 @@ impl AnyHasTypeBounds { } impl AstNode for AnyHasTypeBounds { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true, - _ => false, - } + matches!( + kind, + ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax }) @@ -4071,13 +4117,26 @@ impl AnyHasVisibility { } impl AstNode for AnyHasVisibility { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC - | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => { - true - } - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax }) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 5908dda8e..83f8bbac5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -25,7 +25,7 @@ pub mod ext { return from_text(&name.text()); fn from_text(text: &str) -> ast::IdentPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn ident_path(ident: &str) -> ast::Path { @@ -60,10 +60,10 @@ pub mod ext { expr_from_text("todo!()") } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::default()", ty)) + expr_from_text(&format!("{ty}::default()")) } pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::new()", ty)) + expr_from_text(&format!("{ty}::new()")) } pub fn zero_number() -> ast::Expr { @@ -92,18 +92,20 @@ pub mod ext { ty_path(ident_path("bool")) } pub fn ty_option(t: ast::Type) -> ast::Type { - ty_from_text(&format!("Option<{}>", t)) + ty_from_text(&format!("Option<{t}>")) } pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type { - ty_from_text(&format!("Result<{}, {}>", t, e)) + ty_from_text(&format!("Result<{t}, {e}>")) } } -pub fn name(text: &str) -> ast::Name { - ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text)) +pub fn name(name: &str) -> ast::Name { + let raw_escape = raw_ident_esc(name); + ast_from_text(&format!("mod {raw_escape}{name};")) } -pub fn name_ref(text: &str) -> ast::NameRef { - ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text)) +pub fn name_ref(name_ref: &str) -> ast::NameRef { + let raw_escape = raw_ident_esc(name_ref); + ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}")) } fn raw_ident_esc(ident: &str) -> &'static str { let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some(); @@ -118,10 +120,10 @@ pub fn lifetime(text: &str) -> ast::Lifetime { let mut text = text; let tmp; if never!(!text.starts_with('\'')) { - tmp = format!("'{}", text); + tmp = format!("'{text}"); text = &tmp; } - ast_from_text(&format!("fn f<{}>() {{ }}", text)) + ast_from_text(&format!("fn f<{text}>() {{ }}")) } // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la @@ -142,16 +144,16 @@ pub fn ty_tuple(types: impl IntoIterator) -> ast::Type { contents.push(','); } - ty_from_text(&format!("({})", contents)) + ty_from_text(&format!("({contents})")) } pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { - ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) + ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") }) } pub fn ty_path(path: ast::Path) -> ast::Type { ty_from_text(&path.to_string()) } fn ty_from_text(text: &str) -> ast::Type { - ast_from_text(&format!("type _T = {};", text)) + ast_from_text(&format!("type _T = {text};")) } pub fn assoc_item_list() -> ast::AssocItemList { @@ -171,7 +173,7 @@ pub fn impl_( Some(params) => params.to_string(), None => String::new(), }; - ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params)) + ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}")) } pub fn impl_trait( @@ -180,7 +182,7 @@ pub fn impl_trait( ty_params: Option, ) -> ast::Impl { let ty_params = ty_params.map_or_else(String::new, |params| params.to_string()); - ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params)) + ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}")) } pub(crate) fn generic_arg_list() -> ast::GenericArgList { @@ -188,13 +190,13 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList { } pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { - ast_from_text(&format!("type __ = {};", name_ref)) + ast_from_text(&format!("type __ = {name_ref};")) } pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option) -> ast::PathSegment { let text = match trait_ref { - Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref), - None => format!("fn f(x: <{}>) {{}}", type_ref), + Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"), + None => format!("fn f(x: <{type_ref}>) {{}}"), }; ast_from_text(&text) } @@ -212,15 +214,15 @@ pub fn path_segment_crate() -> ast::PathSegment { } pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("type __ = {};", segment)) + ast_from_text(&format!("type __ = {segment};")) } pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("{}::{}", qual, segment)) + ast_from_text(&format!("{qual}::{segment}")) } // FIXME: path concatenation operation doesn't make sense as AST op. pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { - ast_from_text(&format!("type __ = {}::{};", first, second)) + ast_from_text(&format!("type __ = {first}::{second};")) } pub fn path_from_segments( @@ -229,20 +231,20 @@ pub fn path_from_segments( ) -> ast::Path { let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::"); ast_from_text(&if is_abs { - format!("fn f(x: ::{}) {{}}", segments) + format!("fn f(x: ::{segments}) {{}}") } else { - format!("fn f(x: {}) {{}}", segments) + format!("fn f(x: {segments}) {{}}") }) } pub fn join_paths(paths: impl IntoIterator) -> ast::Path { let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::"); - ast_from_text(&format!("type __ = {};", paths)) + ast_from_text(&format!("type __ = {paths};")) } // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) + ast_from_text(&format!("fn main() {{ let test = {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { @@ -257,50 +259,50 @@ pub fn use_tree( let mut buf = "use ".to_string(); buf += &path.syntax().to_string(); if let Some(use_tree_list) = use_tree_list { - format_to!(buf, "::{}", use_tree_list); + format_to!(buf, "::{use_tree_list}"); } if add_star { buf += "::*"; } if let Some(alias) = alias { - format_to!(buf, " {}", alias); + format_to!(buf, " {alias}"); } ast_from_text(&buf) } pub fn use_tree_list(use_trees: impl IntoIterator) -> ast::UseTreeList { let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", "); - ast_from_text(&format!("use {{{}}};", use_trees)) + ast_from_text(&format!("use {{{use_trees}}};")) } pub fn use_(visibility: Option, use_tree: ast::UseTree) -> ast::Use { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{}use {};", visibility, use_tree)) + ast_from_text(&format!("{visibility}use {use_tree};")) } pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr { - ast_from_text(&format!("fn f() {{ {} {} }}", path, fields)) + ast_from_text(&format!("fn f() {{ {path} {fields} }}")) } pub fn record_expr_field_list( fields: impl IntoIterator, ) -> ast::RecordExprFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields)) + ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}")) } pub fn record_expr_field(name: ast::NameRef, expr: Option) -> ast::RecordExprField { return match expr { - Some(expr) => from_text(&format!("{}: {}", name, expr)), + Some(expr) => from_text(&format!("{name}: {expr}")), None => from_text(&name.to_string()), }; fn from_text(text: &str) -> ast::RecordExprField { - ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text)) + ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}")) } } @@ -311,9 +313,9 @@ pub fn record_field( ) -> ast::RecordField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty)) + ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}")) } // TODO @@ -323,13 +325,13 @@ pub fn block_expr( ) -> ast::BlockExpr { let mut buf = "{\n".to_string(); for stmt in stmts.into_iter() { - format_to!(buf, " {}\n", stmt); + format_to!(buf, " {stmt}\n"); } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } /// Ideally this function wouldn't exist since it involves manual indenting. @@ -343,18 +345,18 @@ pub fn hacky_block_expr_with_comments( let mut buf = "{\n".to_string(); for node_or_token in elements.into_iter() { match node_or_token { - rowan::NodeOrToken::Node(n) => format_to!(buf, " {}\n", n), + rowan::NodeOrToken::Node(n) => format_to!(buf, " {n}\n"), rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => { - format_to!(buf, " {}\n", t) + format_to!(buf, " {t}\n") } _ => (), } } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } pub fn expr_unit() -> ast::Expr { @@ -362,7 +364,7 @@ pub fn expr_unit() -> ast::Expr { } pub fn expr_literal(text: &str) -> ast::Literal { assert_eq!(text.trim(), text); - ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)) + ast_from_text(&format!("fn f() {{ let _ = {text}; }}")) } pub fn expr_empty_block() -> ast::Expr { @@ -373,41 +375,41 @@ pub fn expr_path(path: ast::Path) -> ast::Expr { } pub fn expr_continue(label: Option) -> ast::Expr { match label { - Some(label) => expr_from_text(&format!("continue {}", label)), + Some(label) => expr_from_text(&format!("continue {label}")), None => expr_from_text("continue"), } } // Consider `op: SyntaxKind` instead for nicer syntax at the call-site? pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} {} {}", lhs, op, rhs)) + expr_from_text(&format!("{lhs} {op} {rhs}")) } pub fn expr_break(label: Option, expr: Option) -> ast::Expr { let mut s = String::from("break"); if let Some(label) = label { - format_to!(s, " {}", label); + format_to!(s, " {label}"); } if let Some(expr) = expr { - format_to!(s, " {}", expr); + format_to!(s, " {expr}"); } expr_from_text(&s) } pub fn expr_return(expr: Option) -> ast::Expr { match expr { - Some(expr) => expr_from_text(&format!("return {}", expr)), + Some(expr) => expr_from_text(&format!("return {expr}")), None => expr_from_text("return"), } } pub fn expr_try(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}?", expr)) + expr_from_text(&format!("{expr}?")) } pub fn expr_await(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}.await", expr)) + expr_from_text(&format!("{expr}.await")) } pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { - expr_from_text(&format!("match {} {}", expr, match_arm_list)) + expr_from_text(&format!("match {expr} {match_arm_list}")) } pub fn expr_if( condition: ast::Expr, @@ -415,66 +417,67 @@ pub fn expr_if( else_branch: Option, ) -> ast::Expr { let else_branch = match else_branch { - Some(ast::ElseBranch::Block(block)) => format!("else {}", block), - Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr), + Some(ast::ElseBranch::Block(block)) => format!("else {block}"), + Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), None => String::new(), }; - expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch)) + expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("for {} in {} {}", pat, expr, block)) + expr_from_text(&format!("for {pat} in {expr} {block}")) } pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("loop {}", block)) + expr_from_text(&format!("loop {block}")) } pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { let token = token(op); - expr_from_text(&format!("{}{}", token, expr)) + expr_from_text(&format!("{token}{expr}")) } pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}{}", f, arg_list)) + expr_from_text(&format!("{f}{arg_list}")) } pub fn expr_method_call( receiver: ast::Expr, method: ast::NameRef, arg_list: ast::ArgList, ) -> ast::Expr { - expr_from_text(&format!("{}.{}{}", receiver, method, arg_list)) + expr_from_text(&format!("{receiver}.{method}{arg_list}")) } pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}!{}", f, arg_list)) + expr_from_text(&format!("{f}!{arg_list}")) } pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr { - expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) }) + expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") }) } pub fn expr_closure(pats: impl IntoIterator, expr: ast::Expr) -> ast::Expr { let params = pats.into_iter().join(", "); - expr_from_text(&format!("|{}| {}", params, expr)) + expr_from_text(&format!("|{params}| {expr}")) } pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr { - expr_from_text(&format!("{}.{}", receiver, field)) + expr_from_text(&format!("{receiver}.{field}")) } pub fn expr_paren(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_tuple(elements: impl IntoIterator) -> ast::Expr { let expr = elements.into_iter().format(", "); - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} = {}", lhs, rhs)) + expr_from_text(&format!("{lhs} = {rhs}")) } fn expr_from_text(text: &str) -> ast::Expr { - ast_from_text(&format!("const C: () = {};", text)) + ast_from_text(&format!("const C: () = {text};")) } pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { - ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr)) + ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) } pub fn arg_list(args: impl IntoIterator) -> ast::ArgList { - ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", "))) + let args = args.into_iter().format(", "); + ast_from_text(&format!("fn main() {{ ()({args}) }}")) } pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { @@ -485,7 +488,7 @@ pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { if mut_ { s.push_str("mut "); } - format_to!(s, "{}", name); + format_to!(s, "{name}"); s.push_str(": ())"); ast_from_text(&s) } @@ -494,7 +497,7 @@ pub fn wildcard_pat() -> ast::WildcardPat { return from_text("_"); fn from_text(text: &str) -> ast::WildcardPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -502,7 +505,7 @@ pub fn literal_pat(lit: &str) -> ast::LiteralPat { return from_text(lit); fn from_text(text: &str) -> ast::LiteralPat { - ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text)) + ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}")) } } @@ -515,10 +518,10 @@ pub fn tuple_pat(pats: impl IntoIterator) -> ast::TuplePat { if count == 1 { pats_str.push(','); } - return from_text(&format!("({})", pats_str)); + return from_text(&format!("({pats_str})")); fn from_text(text: &str) -> ast::TuplePat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -527,46 +530,46 @@ pub fn tuple_struct_pat( pats: impl IntoIterator, ) -> ast::TupleStructPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{}({})", path, pats_str)); + return from_text(&format!("{path}({pats_str})")); fn from_text(text: &str) -> ast::TupleStructPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat(path: ast::Path, pats: impl IntoIterator) -> ast::RecordPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{} {{ {} }}", path, pats_str)); + return from_text(&format!("{path} {{ {pats_str} }}")); fn from_text(text: &str) -> ast::RecordPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat { - ast_from_text(&format!("fn f({} {}: ()))", path, fields)) + ast_from_text(&format!("fn f({path} {fields}: ()))")) } pub fn record_pat_field_list( fields: impl IntoIterator, ) -> ast::RecordPatFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields)) + ast_from_text(&format!("fn f(S {{ {fields} }}: ()))")) } pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat)) + ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))")) } pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref)) + ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))")) } /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. pub fn path_pat(path: ast::Path) -> ast::Pat { return from_text(&path.to_string()); fn from_text(text: &str) -> ast::Pat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -577,12 +580,12 @@ pub fn match_arm( ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); return match guard { - Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)), - None => from_text(&format!("{} => {}", pats_str, expr)), + Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")), + None => from_text(&format!("{pats_str} => {expr}")), }; fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -592,10 +595,10 @@ pub fn match_arm_with_guard( expr: ast::Expr, ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); - return from_text(&format!("{} if {} => {}", pats_str, guard, expr)); + return from_text(&format!("{pats_str} if {guard} => {expr}")); fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -605,13 +608,14 @@ pub fn match_arm_list(arms: impl IntoIterator) -> ast::Mat .map(|arm| { let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); let comma = if needs_comma { "," } else { "" }; - format!(" {}{}\n", arm.syntax(), comma) + let arm = arm.syntax(); + format!(" {arm}{comma}\n") }) .collect::(); return from_text(&arms_str); fn from_text(text: &str) -> ast::MatchArmList { - ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}")) } } @@ -620,10 +624,10 @@ pub fn where_pred( bounds: impl IntoIterator, ) -> ast::WherePred { let bounds = bounds.into_iter().join(" + "); - return from_text(&format!("{}: {}", path, bounds)); + return from_text(&format!("{path}: {bounds}")); fn from_text(text: &str) -> ast::WherePred { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -632,7 +636,7 @@ pub fn where_clause(preds: impl IntoIterator) -> ast::Whe return from_text(preds.as_str()); fn from_text(text: &str) -> ast::WhereClause { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -642,19 +646,19 @@ pub fn let_stmt( initializer: Option, ) -> ast::LetStmt { let mut text = String::new(); - format_to!(text, "let {}", pattern); + format_to!(text, "let {pattern}"); if let Some(ty) = ty { - format_to!(text, ": {}", ty); + format_to!(text, ": {ty}"); } match initializer { - Some(it) => format_to!(text, " = {};", it), + Some(it) => format_to!(text, " = {it};"), None => format_to!(text, ";"), }; - ast_from_text(&format!("fn f() {{ {} }}", text)) + ast_from_text(&format!("fn f() {{ {text} }}")) } pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt { let semi = if expr.is_block_like() { "" } else { ";" }; - ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) + ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}")) } pub fn item_const( @@ -665,13 +669,13 @@ pub fn item_const( ) -> ast::Const { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr)) + ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};")) } pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { - ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) + ast_from_text(&format!("fn f({pat}: {ty}) {{ }}")) } pub fn self_param() -> ast::SelfParam { @@ -679,7 +683,7 @@ pub fn self_param() -> ast::SelfParam { } pub fn ret_type(ty: ast::Type) -> ast::RetType { - ast_from_text(&format!("fn f() -> {} {{ }}", ty)) + ast_from_text(&format!("fn f() -> {ty} {{ }}")) } pub fn param_list( @@ -688,30 +692,30 @@ pub fn param_list( ) -> ast::ParamList { let args = pats.into_iter().join(", "); let list = match self_param { - Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param), - Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args), - None => format!("fn f({}) {{ }}", args), + Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"), + Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"), + None => format!("fn f({args}) {{ }}"), }; ast_from_text(&list) } pub fn type_param(name: ast::Name, ty: Option) -> ast::TypeParam { let bound = match ty { - Some(it) => format!(": {}", it), + Some(it) => format!(": {it}"), None => String::new(), }; - ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) + ast_from_text(&format!("fn f<{name}{bound}>() {{ }}")) } pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam { - ast_from_text(&format!("fn f<{}>() {{ }}", lifetime)) + ast_from_text(&format!("fn f<{lifetime}>() {{ }}")) } pub fn generic_param_list( pats: impl IntoIterator, ) -> ast::GenericParamList { let args = pats.into_iter().join(", "); - ast_from_text(&format!("fn f<{}>() {{ }}", args)) + ast_from_text(&format!("fn f<{args}>() {{ }}")) } pub fn visibility_pub_crate() -> ast::Visibility { @@ -724,30 +728,33 @@ pub fn visibility_pub() -> ast::Visibility { pub fn tuple_field_list(fields: impl IntoIterator) -> ast::TupleFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f({});", fields)) + ast_from_text(&format!("struct f({fields});")) } pub fn record_field_list( fields: impl IntoIterator, ) -> ast::RecordFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f {{ {} }}", fields)) + ast_from_text(&format!("struct f {{ {fields} }}")) } pub fn tuple_field(visibility: Option, ty: ast::Type) -> ast::TupleField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct f({}{});", visibility, ty)) + ast_from_text(&format!("struct f({visibility}{ty});")) } pub fn variant(name: ast::Name, field_list: Option) -> ast::Variant { let field_list = match field_list { None => String::new(), - Some(it) => format!("{}", it), + Some(it) => match it { + ast::FieldList::RecordFieldList(record) => format!(" {record}"), + ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"), + }, }; - ast_from_text(&format!("enum f {{ {}{} }}", name, field_list)) + ast_from_text(&format!("enum f {{ {name}{field_list} }}")) } pub fn fn_( @@ -760,23 +767,22 @@ pub fn fn_( is_async: bool, ) -> ast::Fn { let type_params = match type_params { - Some(type_params) => format!("{}", type_params), + Some(type_params) => format!("{type_params}"), None => "".into(), }; let ret_type = match ret_type { - Some(ret_type) => format!("{} ", ret_type), + Some(ret_type) => format!("{ret_type} "), None => "".into(), }; let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; let async_literal = if is_async { "async " } else { "" }; ast_from_text(&format!( - "{}{}fn {}{}{} {}{}", - visibility, async_literal, fn_name, type_params, params, ret_type, body + "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}", )) } @@ -790,13 +796,10 @@ pub fn struct_( let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string()); let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!( - "{}struct {}{}{}{}", - visibility, strukt_name, type_params, field_list, semicolon - )) + ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",)) } #[track_caller] @@ -805,7 +808,8 @@ fn ast_from_text(text: &str) -> N { let node = match parse.tree().syntax().descendants().find_map(N::cast) { Some(it) => it, None => { - panic!("Failed to make ast node `{}` from text {}", std::any::type_name::(), text) + let node = std::any::type_name::(); + panic!("Failed to make ast node `{node}` from text {text}") } }; let node = node.clone_subtree(); @@ -821,7 +825,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { .descendants_with_tokens() .filter_map(|it| it.into_token()) .find(|it| it.kind() == kind) - .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) + .unwrap_or_else(|| panic!("unhandled token: {kind:?}")) } pub mod tokens { @@ -860,7 +864,7 @@ pub mod tokens { pub fn literal(text: &str) -> SyntaxToken { assert_eq!(text.trim(), text); - let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)); + let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}")); lit.syntax().first_child_or_token().unwrap().into_token().unwrap() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/operators.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/operators.rs index a687ba0b7..8f7b3fb60 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/operators.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/operators.rs @@ -111,10 +111,10 @@ impl fmt::Display for BinaryOp { BinaryOp::ArithOp(op) => fmt::Display::fmt(op, f), BinaryOp::CmpOp(op) => fmt::Display::fmt(op, f), BinaryOp::Assignment { op } => { - f.write_str("=")?; if let Some(op) = op { fmt::Display::fmt(op, f)?; } + f.write_str("=")?; Ok(()) } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index 28976d837..ba72e6442 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -322,7 +322,7 @@ impl ast::IntNumber { pub fn float_value(&self) -> Option { let (_, text, _) = self.split_into_parts(); - text.parse::().ok() + text.replace('_', "").parse::().ok() } } @@ -361,7 +361,7 @@ impl ast::FloatNumber { pub fn value(&self) -> Option { let (text, _) = self.split_into_parts(); - text.parse::().ok() + text.replace('_', "").parse::().ok() } } @@ -397,6 +397,15 @@ mod tests { assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into()); } + fn check_float_value(lit: &str, expected: impl Into> + Copy) { + assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into()); + } + + fn check_int_value(lit: &str, expected: impl Into>) { + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + } + #[test] fn test_float_number_suffix() { check_float_suffix("123.0", None); @@ -437,6 +446,14 @@ mod tests { check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); } + + #[test] + fn test_value_underscores() { + check_float_value("3.141592653589793_f64", 3.141592653589793_f64); + check_float_value("1__0.__0__f32", 10.0); + check_int_value("0b__1_0_", 2); + check_int_value("1_1_1_1_1_1", 111111); + } } impl ast::Char { diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs index 256999fe0..7c7a60d62 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs @@ -2,10 +2,7 @@ //! //! We don't normally run fuzzying, so this is hopelessly bitrotten :( -use std::{ - convert::TryInto, - str::{self, FromStr}, -}; +use std::str::{self, FromStr}; use text_edit::Indel; diff --git a/src/tools/rust-analyzer/crates/syntax/src/hacks.rs b/src/tools/rust-analyzer/crates/syntax/src/hacks.rs index a047f61fa..ec3d3d444 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/hacks.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/hacks.rs @@ -1,4 +1,4 @@ -//! Things which exist to solve practial issues, but which shouldn't exist. +//! Things which exist to solve practical issues, but which shouldn't exist. //! //! Please avoid adding new usages of the functions in this module diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index 7fa354c0c..4f5e273a5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -1,4 +1,4 @@ -//! Syntax Tree library used throughout the rust analyzer. +//! Syntax Tree library used throughout the rust-analyzer. //! //! Properties: //! - easy and fast incremental re-parsing diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs index 6d2766225..70b54843d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs @@ -169,10 +169,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { quote! { impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -253,10 +250,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| #name { syntax }) @@ -410,24 +404,17 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String { impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - #(#all_keywords)|* => true, - _ => false, - } + matches!(self, #(#all_keywords)|*) } pub fn is_punct(self) -> bool { - match self { - #(#punctuation)|* => true, - _ => false, - } + + matches!(self, #(#punctuation)|*) + } pub fn is_literal(self) -> bool { - match self { - #(#literals)|* => true, - _ => false, - } + matches!(self, #(#literals)|*) } pub fn from_keyword(ident: &str) -> Option { diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index f48d1ec66..6df29db47 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -471,6 +471,21 @@ pub mod future { #[lang = "poll"] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } + + pub trait IntoFuture { + type Output; + type IntoFuture: Future; + #[lang = "into_future"] + fn into_future(self) -> Self::IntoFuture; + } + + impl IntoFuture for F { + type Output = F::Output; + type IntoFuture = F; + fn into_future(self) -> F { + self + } + } } pub mod task { pub enum Poll { diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml index 9ee4415dc..fcc693a7d 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml +++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml @@ -14,7 +14,7 @@ tracing = "0.1.35" jod-thread = "0.1.2" walkdir = "2.3.2" crossbeam-channel = "0.5.5" -notify = "=5.0.0-pre.15" +notify = "=5.0.0-pre.16" vfs = { path = "../vfs", version = "0.0.0" } paths = { path = "../paths", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index 4d33a9afb..c95304e55 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -12,7 +12,7 @@ use std::fs; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; -use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use paths::{AbsPath, AbsPathBuf}; use vfs::loader; use walkdir::WalkDir; @@ -40,12 +40,15 @@ impl loader::Handle for NotifyHandle { .expect("failed to spawn thread"); NotifyHandle { sender, _thread: thread } } + fn set_config(&mut self, config: loader::Config) { self.sender.send(Message::Config(config)).unwrap(); } + fn invalidate(&mut self, path: AbsPathBuf) { self.sender.send(Message::Invalidate(path)).unwrap(); } + fn load_sync(&mut self, path: &AbsPath) -> Option> { read(path) } @@ -70,6 +73,7 @@ impl NotifyActor { fn new(sender: loader::Sender) -> NotifyActor { NotifyActor { sender, watched_entries: Vec::new(), watcher: None } } + fn next_event(&self, receiver: &Receiver) -> Option { let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver); select! { @@ -77,18 +81,22 @@ impl NotifyActor { recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())), } } + fn run(mut self, inbox: Receiver) { while let Some(event) = self.next_event(&inbox) { - tracing::debug!("vfs-notify event: {:?}", event); + tracing::debug!(?event, "vfs-notify event"); match event { Event::Message(msg) => match msg { Message::Config(config) => { self.watcher = None; if !config.watch.is_empty() { let (watcher_sender, watcher_receiver) = unbounded(); - let watcher = log_notify_error(RecommendedWatcher::new(move |event| { - watcher_sender.send(event).unwrap(); - })); + let watcher = log_notify_error(RecommendedWatcher::new( + move |event| { + watcher_sender.send(event).unwrap(); + }, + Config::default(), + )); self.watcher = watcher.map(|it| (it, watcher_receiver)); } diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml index c63773487..d7549a284 100644 --- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml +++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml @@ -12,6 +12,7 @@ doctest = false [dependencies] rustc-hash = "1.1.0" fst = "0.4.7" +indexmap = "1.9.1" paths = { path = "../paths", version = "0.0.0" } -indexmap = "1.9.1" +stdx = { path = "../stdx", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs index 6a89263e5..e0ef737b3 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs @@ -6,6 +6,7 @@ use std::fmt; use fst::{IntoStreamer, Streamer}; use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use crate::{AnchoredPath, FileId, Vfs, VfsPath}; @@ -13,7 +14,7 @@ use crate::{AnchoredPath, FileId, Vfs, VfsPath}; #[derive(Default, Clone, Eq, PartialEq)] pub struct FileSet { files: FxHashMap, - paths: FxHashMap, + paths: NoHashHashMap, } impl FileSet { diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs index 10fae41d0..afc9a0fa6 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs @@ -59,12 +59,19 @@ pub use paths::{AbsPath, AbsPathBuf}; /// Handle to a file in [`Vfs`] /// /// Most functions in rust-analyzer use this when they need to refer to a file. -#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct FileId(pub u32); +impl stdx::hash::NoHashHashable for FileId {} +impl std::hash::Hash for FileId { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + /// Storage for all files read by rust-analyzer. /// -/// For more informations see the [crate-level](crate) documentation. +/// For more information see the [crate-level](crate) documentation. #[derive(Default)] pub struct Vfs { interner: PathInterner, diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index 76bbd1e91..c7f152acc 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -82,7 +82,7 @@ There's **"Run Extension (Debug Build)"** launch configuration for this in VS Co In general, I use one of the following workflows for fixing bugs and implementing features: If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it. -So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. +So, I use **rust-analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect. If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`. @@ -152,11 +152,11 @@ To log all communication between the server and the client, there are two choice There are also several VS Code commands which might be of interest: -* `Rust Analyzer: Status` shows some memory-usage statistics. +* `rust-analyzer: Status` shows some memory-usage statistics. -* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. +* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection. -* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. +* `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor. You can hover over syntax nodes in the opened text file to see the appropriate rust code that it refers to and the rust editor will also highlight the proper diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md index ea4035baf..c173a239f 100644 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ b/src/tools/rust-analyzer/docs/dev/architecture.md @@ -371,7 +371,7 @@ That is, rust-analyzer requires unwinding. ### Testing -Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. +rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. @@ -485,7 +485,7 @@ Mind the code--architecture gap: at the moment, we are using fewer feature flags ### Serialization In Rust, it is easy (often too easy) to add serialization to any type by adding `#[derive(Serialize)]`. -This easiness is misleading -- serializable types impose significant backwards compatability constraints. +This easiness is misleading -- serializable types impose significant backwards compatibility constraints. If a type is serializable, then it is a part of some IPC boundary. You often don't control the other side of this boundary, so changing serializable types is hard. diff --git a/src/tools/rust-analyzer/docs/dev/guide.md b/src/tools/rust-analyzer/docs/dev/guide.md index 47ae3f3e6..808eb5d10 100644 --- a/src/tools/rust-analyzer/docs/dev/guide.md +++ b/src/tools/rust-analyzer/docs/dev/guide.md @@ -63,7 +63,7 @@ Next, let's talk about what the inputs to the `Analysis` are, precisely. ## Inputs -Rust Analyzer never does any I/O itself, all inputs get passed explicitly via +rust-analyzer never does any I/O itself, all inputs get passed explicitly via the `AnalysisHost::apply_change` method, which accepts a single argument, a `Change`. [`Change`] is a builder for a single change "transaction", so it suffices to study its methods to understand all of the diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 5040643d3..6d2c7d7b0 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ src/format.rs:52:1 - | -51 | ) -> Option { - | -------------- expected `Option` because of return type -52 | / for ann in annotations { -53 | | match (ann.range.0, ann.range.1) { -54 | | (None, None) => continue, -55 | | (Some(start), Some(end)) if start > end_index => continue, -... | -71 | | } -72 | | } - | |_____^ expected enum `std::option::Option`, found () -``` - -[Documentation][] - -[Documentation]: https://docs.rs/annotate-snippets/ - -Usage ------ - -```rust -use annotate_snippets::{ - display_list::DisplayList, - formatter::DisplayListFormatter, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -fn main() { - let snippet = Snippet { - title: Some(Annotation { - label: Some("expected type, found `22`".to_string()), - id: None, - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![ - Slice { - source: r#" -This is an example -content of the slice -which will be annotated -with the list of annotations below. - "#.to_string(), - line_start: 26, - origin: Some("examples/example.txt".to_string()), - fold: false, - annotations: vec![ - SourceAnnotation { - label: "Example error annotation".to_string(), - annotation_type: AnnotationType::Error, - range: (13, 18), - }, - SourceAnnotation { - label: "and here's a warning".to_string(), - annotation_type: AnnotationType::Warning, - range: (34, 50), - }, - ], - }, - ], - }; - - let dl = DisplayList::from(snippet); - let dlf = DisplayListFormatter::new(true, false); - println!("{}", dlf.format(&dl)); -} -``` - -Local Development ------------------ - - cargo build - cargo test - -When submitting a PR please use [`cargo fmt`][] (nightly). - -[`cargo fmt`]: https://github.com/rust-lang/rustfmt diff --git a/vendor/annotate-snippets-0.8.0/benches/simple.rs b/vendor/annotate-snippets-0.8.0/benches/simple.rs deleted file mode 100644 index 4c13a8f00..000000000 --- a/vendor/annotate-snippets-0.8.0/benches/simple.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![allow(clippy::unit_arg)] -#[macro_use] -extern crate criterion; - -use criterion::{black_box, Criterion}; - -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -fn create_snippet() { - let snippet = Snippet { - slices: vec![Slice { - source: r#") -> Option { - for ann in annotations { - match (ann.range.0, ann.range.1) { - (None, None) => continue, - (Some(start), Some(end)) if start > end_index => continue, - (Some(start), Some(end)) if start >= start_index => { - let label = if let Some(ref label) = ann.label { - format!(" {}", label) - } else { - String::from("") - }; - - return Some(format!( - "{}{}{}", - " ".repeat(start - start_index), - "^".repeat(end - start), - label - )); - } - _ => continue, - } - }"#, - line_start: 51, - origin: Some("src/format.rs"), - fold: false, - annotations: vec![ - SourceAnnotation { - label: "expected `Option` because of return type", - annotation_type: AnnotationType::Warning, - range: (5, 19), - }, - SourceAnnotation { - label: "expected enum `std::option::Option`", - annotation_type: AnnotationType::Error, - range: (26, 724), - }, - ], - }], - title: Some(Annotation { - label: Some("mismatched types"), - id: Some("E0308"), - annotation_type: AnnotationType::Error, - }), - footer: vec![], - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - - let dl = DisplayList::from(snippet); - let _result = dl.to_string(); -} - -pub fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("format", |b| b.iter(|| black_box(create_snippet()))); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/vendor/annotate-snippets-0.8.0/examples/expected_type.rs b/vendor/annotate-snippets-0.8.0/examples/expected_type.rs deleted file mode 100644 index 89f0ddc11..000000000 --- a/vendor/annotate-snippets-0.8.0/examples/expected_type.rs +++ /dev/null @@ -1,43 +0,0 @@ -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -fn main() { - let snippet = Snippet { - title: Some(Annotation { - label: Some("expected type, found `22`"), - id: None, - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![Slice { - source: r#" annotations: vec![SourceAnnotation { - label: "expected struct `annotate_snippets::snippet::Slice`, found reference" - , - range: <22, 25>,"#, - line_start: 26, - origin: Some("examples/footer.rs"), - fold: true, - annotations: vec![ - SourceAnnotation { - label: "", - annotation_type: AnnotationType::Error, - range: (205, 207), - }, - SourceAnnotation { - label: "while parsing this struct", - annotation_type: AnnotationType::Info, - range: (34, 50), - }, - ], - }], - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - - let dl = DisplayList::from(snippet); - println!("{}", dl); -} diff --git a/vendor/annotate-snippets-0.8.0/examples/footer.rs b/vendor/annotate-snippets-0.8.0/examples/footer.rs deleted file mode 100644 index f3c15c410..000000000 --- a/vendor/annotate-snippets-0.8.0/examples/footer.rs +++ /dev/null @@ -1,39 +0,0 @@ -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -fn main() { - let snippet = Snippet { - title: Some(Annotation { - label: Some("mismatched types"), - id: Some("E0308"), - annotation_type: AnnotationType::Error, - }), - footer: vec![Annotation { - label: Some( - "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", - ), - id: None, - annotation_type: AnnotationType::Note, - }], - slices: vec![Slice { - source: " slices: vec![\"A\",", - line_start: 13, - origin: Some("src/multislice.rs"), - fold: false, - annotations: vec![SourceAnnotation { - label: "expected struct `annotate_snippets::snippet::Slice`, found reference", - range: (21, 24), - annotation_type: AnnotationType::Error, - }], - }], - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - - let dl = DisplayList::from(snippet); - println!("{}", dl); -} diff --git a/vendor/annotate-snippets-0.8.0/examples/format.rs b/vendor/annotate-snippets-0.8.0/examples/format.rs deleted file mode 100644 index 98b77a140..000000000 --- a/vendor/annotate-snippets-0.8.0/examples/format.rs +++ /dev/null @@ -1,61 +0,0 @@ -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -fn main() { - let snippet = Snippet { - slices: vec![Slice { - source: r#") -> Option { - for ann in annotations { - match (ann.range.0, ann.range.1) { - (None, None) => continue, - (Some(start), Some(end)) if start > end_index => continue, - (Some(start), Some(end)) if start >= start_index => { - let label = if let Some(ref label) = ann.label { - format!(" {}", label) - } else { - String::from("") - }; - - return Some(format!( - "{}{}{}", - " ".repeat(start - start_index), - "^".repeat(end - start), - label - )); - } - _ => continue, - } - }"#, - line_start: 51, - origin: Some("src/format.rs"), - fold: false, - annotations: vec![ - SourceAnnotation { - label: "expected `Option` because of return type", - annotation_type: AnnotationType::Warning, - range: (5, 19), - }, - SourceAnnotation { - label: "expected enum `std::option::Option`", - annotation_type: AnnotationType::Error, - range: (26, 724), - }, - ], - }], - title: Some(Annotation { - label: Some("mismatched types"), - id: Some("E0308"), - annotation_type: AnnotationType::Error, - }), - footer: vec![], - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - - let dl = DisplayList::from(snippet); - println!("{}", dl); -} diff --git a/vendor/annotate-snippets-0.8.0/examples/multislice.rs b/vendor/annotate-snippets-0.8.0/examples/multislice.rs deleted file mode 100644 index 5675a07da..000000000 --- a/vendor/annotate-snippets-0.8.0/examples/multislice.rs +++ /dev/null @@ -1,38 +0,0 @@ -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet}, -}; - -fn main() { - let snippet = Snippet { - title: Some(Annotation { - label: Some("mismatched types"), - id: None, - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![ - Slice { - source: "Foo", - line_start: 51, - origin: Some("src/format.rs"), - fold: false, - annotations: vec![], - }, - Slice { - source: "Faa", - line_start: 129, - origin: Some("src/display.rs"), - fold: false, - annotations: vec![], - }, - ], - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - - let dl = DisplayList::from(snippet); - println!("{}", dl); -} diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs b/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs deleted file mode 100644 index b3ba5a3dd..000000000 --- a/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs +++ /dev/null @@ -1,517 +0,0 @@ -//! Trait for converting `Snippet` to `DisplayList`. -use super::*; -use crate::{formatter::get_term_style, snippet}; - -struct CursorLines<'a>(&'a str); - -impl<'a> CursorLines<'a> { - fn new(src: &str) -> CursorLines<'_> { - CursorLines(src) - } -} - -enum EndLine { - EOF = 0, - CRLF = 1, - LF = 2, -} - -impl<'a> Iterator for CursorLines<'a> { - type Item = (&'a str, EndLine); - - fn next(&mut self) -> Option { - if self.0.is_empty() { - None - } else { - self.0 - .find('\n') - .map(|x| { - let ret = if 0 < x { - if self.0.as_bytes()[x - 1] == b'\r' { - (&self.0[..x - 1], EndLine::LF) - } else { - (&self.0[..x], EndLine::CRLF) - } - } else { - ("", EndLine::CRLF) - }; - self.0 = &self.0[x + 1..]; - ret - }) - .or_else(|| { - let ret = Some((&self.0[..], EndLine::EOF)); - self.0 = ""; - ret - }) - } - } -} - -fn format_label( - label: Option<&str>, - style: Option, -) -> Vec> { - let mut result = vec![]; - if let Some(label) = label { - for (idx, element) in label.split("__").enumerate() { - let element_style = match style { - Some(s) => s, - None => { - if idx % 2 == 0 { - DisplayTextStyle::Regular - } else { - DisplayTextStyle::Emphasis - } - } - }; - result.push(DisplayTextFragment { - content: element, - style: element_style, - }); - } - } - result -} - -fn format_title(annotation: snippet::Annotation<'_>) -> DisplayLine<'_> { - let label = annotation.label.unwrap_or_default(); - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::from(annotation.annotation_type), - id: annotation.id, - label: format_label(Some(&label), Some(DisplayTextStyle::Emphasis)), - }, - source_aligned: false, - continuation: false, - }) -} - -fn format_annotation(annotation: snippet::Annotation<'_>) -> Vec> { - let mut result = vec![]; - let label = annotation.label.unwrap_or_default(); - for (i, line) in label.lines().enumerate() { - result.push(DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::from(annotation.annotation_type), - id: None, - label: format_label(Some(line), None), - }, - source_aligned: true, - continuation: i != 0, - })); - } - result -} - -fn format_slice( - mut slice: snippet::Slice<'_>, - is_first: bool, - has_footer: bool, -) -> Vec> { - let main_range = slice.annotations.get(0).map(|x| x.range.0); - let row = slice.line_start; - let origin = slice.origin.take(); - let mut body = format_body(slice, has_footer); - let header = format_header(origin, main_range, row, &body, is_first); - let mut result = vec![]; - - if let Some(header) = header { - result.push(header); - } - result.append(&mut body); - result -} - -fn format_header<'a>( - origin: Option<&'a str>, - main_range: Option, - mut row: usize, - body: &[DisplayLine<'_>], - is_first: bool, -) -> Option> { - let display_header = if is_first { - DisplayHeaderType::Initial - } else { - DisplayHeaderType::Continuation - }; - - if let Some(main_range) = main_range { - let mut col = 1; - - for item in body { - if let DisplayLine::Source { - line: DisplaySourceLine::Content { range, .. }, - .. - } = item - { - if main_range >= range.0 && main_range <= range.1 { - col = main_range - range.0 + 1; - break; - } - row += 1; - } - } - if let Some(path) = origin { - return Some(DisplayLine::Raw(DisplayRawLine::Origin { - path, - pos: Some((row, col)), - header_type: display_header, - })); - } - } - if let Some(path) = origin { - return Some(DisplayLine::Raw(DisplayRawLine::Origin { - path, - pos: None, - header_type: display_header, - })); - } - None -} - -fn fold_body(mut body: Vec>) -> Vec> { - enum Line { - Fold(usize), - Source(usize), - }; - - let mut lines = vec![]; - let mut no_annotation_lines_counter = 0; - - for (idx, line) in body.iter().enumerate() { - match line { - DisplayLine::Source { - line: DisplaySourceLine::Annotation { .. }, - .. - } => { - if no_annotation_lines_counter > 2 { - let fold_start = idx - no_annotation_lines_counter; - let fold_end = idx; - let pre_len = if no_annotation_lines_counter > 8 { - 4 - } else { - 0 - }; - let post_len = if no_annotation_lines_counter > 8 { - 2 - } else { - 1 - }; - for (i, _) in body - .iter() - .enumerate() - .take(fold_start + pre_len) - .skip(fold_start) - { - lines.push(Line::Source(i)); - } - lines.push(Line::Fold(idx)); - for (i, _) in body - .iter() - .enumerate() - .take(fold_end) - .skip(fold_end - post_len) - { - lines.push(Line::Source(i)); - } - } else { - let start = idx - no_annotation_lines_counter; - for (i, _) in body.iter().enumerate().take(idx).skip(start) { - lines.push(Line::Source(i)); - } - } - no_annotation_lines_counter = 0; - } - DisplayLine::Source { .. } => { - no_annotation_lines_counter += 1; - continue; - } - _ => { - no_annotation_lines_counter += 1; - } - } - lines.push(Line::Source(idx)); - } - - let mut new_body = vec![]; - let mut removed = 0; - for line in lines { - match line { - Line::Source(i) => { - new_body.push(body.remove(i - removed)); - removed += 1; - } - Line::Fold(i) => { - if let DisplayLine::Source { - line: DisplaySourceLine::Annotation { .. }, - ref inline_marks, - .. - } = body.get(i - removed).unwrap() - { - new_body.push(DisplayLine::Fold { - inline_marks: inline_marks.clone(), - }) - } else { - unreachable!() - } - } - } - } - - new_body -} - -fn format_body(slice: snippet::Slice<'_>, has_footer: bool) -> Vec> { - let source_len = slice.source.chars().count(); - if let Some(bigger) = slice.annotations.iter().find_map(|x| { - if source_len < x.range.1 { - Some(x.range) - } else { - None - } - }) { - panic!( - "SourceAnnotation range `{:?}` is bigger than source length `{}`", - bigger, source_len - ) - } - - let mut body = vec![]; - let mut current_line = slice.line_start; - let mut current_index = 0; - let mut line_index_ranges = vec![]; - - for (line, end_line) in CursorLines::new(slice.source) { - let line_length = line.chars().count(); - let line_range = (current_index, current_index + line_length); - body.push(DisplayLine::Source { - lineno: Some(current_line), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: line, - range: line_range, - }, - }); - line_index_ranges.push(line_range); - current_line += 1; - current_index += line_length + end_line as usize; - } - - let mut annotation_line_count = 0; - let mut annotations = slice.annotations; - for (idx, (line_start, line_end)) in line_index_ranges.into_iter().enumerate() { - // It would be nice to use filter_drain here once it's stable. - annotations = annotations - .into_iter() - .filter(|annotation| { - let body_idx = idx + annotation_line_count; - let annotation_type = match annotation.annotation_type { - snippet::AnnotationType::Error => DisplayAnnotationType::None, - snippet::AnnotationType::Warning => DisplayAnnotationType::None, - _ => DisplayAnnotationType::from(annotation.annotation_type), - }; - match annotation.range { - (start, _) if start > line_end => true, - (start, end) - if start >= line_start && end <= line_end - || start == line_end && end - start <= 1 => - { - let range = (start - line_start, end - line_start); - body.insert( - body_idx + 1, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - annotation: Annotation { - annotation_type, - id: None, - label: format_label(Some(&annotation.label), None), - }, - range, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - ); - annotation_line_count += 1; - false - } - (start, end) if start >= line_start && start <= line_end && end > line_end => { - if start - line_start == 0 { - if let DisplayLine::Source { - ref mut inline_marks, - .. - } = body[body_idx] - { - inline_marks.push(DisplayMark { - mark_type: DisplayMarkType::AnnotationStart, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - }); - } - } else { - let range = (start - line_start, start - line_start + 1); - body.insert( - body_idx + 1, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![], - }, - range, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - annotation_part: DisplayAnnotationPart::MultilineStart, - }, - }, - ); - annotation_line_count += 1; - } - true - } - (start, end) if start < line_start && end > line_end => { - if let DisplayLine::Source { - ref mut inline_marks, - .. - } = body[body_idx] - { - inline_marks.push(DisplayMark { - mark_type: DisplayMarkType::AnnotationThrough, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - }); - } - true - } - (start, end) if start < line_start && end >= line_start && end <= line_end => { - if let DisplayLine::Source { - ref mut inline_marks, - .. - } = body[body_idx] - { - inline_marks.push(DisplayMark { - mark_type: DisplayMarkType::AnnotationThrough, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - }); - } - - let range = (end - line_start, end - line_start + 1); - body.insert( - body_idx + 1, - DisplayLine::Source { - lineno: None, - inline_marks: vec![DisplayMark { - mark_type: DisplayMarkType::AnnotationThrough, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - }], - line: DisplaySourceLine::Annotation { - annotation: Annotation { - annotation_type, - id: None, - label: format_label(Some(&annotation.label), None), - }, - range, - annotation_type: DisplayAnnotationType::from( - annotation.annotation_type, - ), - annotation_part: DisplayAnnotationPart::MultilineEnd, - }, - }, - ); - annotation_line_count += 1; - false - } - _ => true, - } - }) - .collect(); - } - - if slice.fold { - body = fold_body(body); - } - - body.insert( - 0, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - ); - if has_footer { - body.push(DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }); - } else if let Some(DisplayLine::Source { .. }) = body.last() { - body.push(DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }); - } - body -} - -impl<'a> From> for DisplayList<'a> { - fn from( - snippet::Snippet { - title, - footer, - slices, - opt, - }: snippet::Snippet<'a>, - ) -> DisplayList<'a> { - let mut body = vec![]; - if let Some(annotation) = title { - body.push(format_title(annotation)); - } - - for (idx, slice) in slices.into_iter().enumerate() { - body.append(&mut format_slice(slice, idx == 0, !footer.is_empty())); - } - - for annotation in footer { - body.append(&mut format_annotation(annotation)); - } - - let FormatOptions { - color, - anonymized_line_numbers, - } = opt; - - Self { - body, - stylesheet: get_term_style(color), - anonymized_line_numbers, - } - } -} - -impl From for DisplayAnnotationType { - fn from(at: snippet::AnnotationType) -> Self { - match at { - snippet::AnnotationType::Error => DisplayAnnotationType::Error, - snippet::AnnotationType::Warning => DisplayAnnotationType::Warning, - snippet::AnnotationType::Info => DisplayAnnotationType::Info, - snippet::AnnotationType::Note => DisplayAnnotationType::Note, - snippet::AnnotationType::Help => DisplayAnnotationType::Help, - } - } -} diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs b/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs deleted file mode 100644 index 224a9f580..000000000 --- a/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! display_list module stores the output model for the snippet. -//! -//! `DisplayList` is a central structure in the crate, which contains -//! the structured list of lines to be displayed. -//! -//! It is made of two types of lines: `Source` and `Raw`. All `Source` lines -//! are structured using four columns: -//! -//! ```text -//! /------------ (1) Line number column. -//! | /--------- (2) Line number column delimiter. -//! | | /------- (3) Inline marks column. -//! | | | /--- (4) Content column with the source and annotations for slices. -//! | | | | -//! ============================================================================= -//! error[E0308]: mismatched types -//! --> src/format.rs:51:5 -//! | -//! 151 | / fn test() -> String { -//! 152 | | return "test"; -//! 153 | | } -//! | |___^ error: expected `String`, for `&str`. -//! | -//! ``` -//! -//! The first two lines of the example above are `Raw` lines, while the rest -//! are `Source` lines. -//! -//! `DisplayList` does not store column alignment information, and those are -//! only calculated by the implementation of `std::fmt::Display` using information such as -//! styling. -//! -//! The above snippet has been built out of the following structure: -mod from_snippet; -mod structs; - -pub use self::structs::*; diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs b/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs deleted file mode 100644 index 8f6d8fcf1..000000000 --- a/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::fmt; - -use crate::formatter::{get_term_style, style::Stylesheet}; - -/// List of lines to be displayed. -pub struct DisplayList<'a> { - pub body: Vec>, - pub stylesheet: Box, - pub anonymized_line_numbers: bool, -} - -impl<'a> From>> for DisplayList<'a> { - fn from(body: Vec>) -> DisplayList<'a> { - Self { - body, - anonymized_line_numbers: false, - stylesheet: get_term_style(false), - } - } -} - -impl<'a> PartialEq for DisplayList<'a> { - fn eq(&self, other: &Self) -> bool { - self.body == other.body && self.anonymized_line_numbers == other.anonymized_line_numbers - } -} - -impl<'a> fmt::Debug for DisplayList<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DisplayList") - .field("body", &self.body) - .field("anonymized_line_numbers", &self.anonymized_line_numbers) - .finish() - } -} - -#[derive(Debug, Default, Copy, Clone)] -pub struct FormatOptions { - pub color: bool, - pub anonymized_line_numbers: bool, -} - -/// Inline annotation which can be used in either Raw or Source line. -#[derive(Debug, PartialEq)] -pub struct Annotation<'a> { - pub annotation_type: DisplayAnnotationType, - pub id: Option<&'a str>, - pub label: Vec>, -} - -/// A single line used in `DisplayList`. -#[derive(Debug, PartialEq)] -pub enum DisplayLine<'a> { - /// A line with `lineno` portion of the slice. - Source { - lineno: Option, - inline_marks: Vec, - line: DisplaySourceLine<'a>, - }, - - /// A line indicating a folded part of the slice. - Fold { inline_marks: Vec }, - - /// A line which is displayed outside of slices. - Raw(DisplayRawLine<'a>), -} - -/// A source line. -#[derive(Debug, PartialEq)] -pub enum DisplaySourceLine<'a> { - /// A line with the content of the Slice. - Content { - text: &'a str, - range: (usize, usize), // meta information for annotation placement. - }, - - /// An annotation line which is displayed in context of the slice. - Annotation { - annotation: Annotation<'a>, - range: (usize, usize), - annotation_type: DisplayAnnotationType, - annotation_part: DisplayAnnotationPart, - }, - - /// An empty source line. - Empty, -} - -/// Raw line - a line which does not have the `lineno` part and is not considered -/// a part of the snippet. -#[derive(Debug, PartialEq)] -pub enum DisplayRawLine<'a> { - /// A line which provides information about the location of the given - /// slice in the project structure. - Origin { - path: &'a str, - pos: Option<(usize, usize)>, - header_type: DisplayHeaderType, - }, - - /// An annotation line which is not part of any snippet. - Annotation { - annotation: Annotation<'a>, - - /// If set to `true`, the annotation will be aligned to the - /// lineno delimiter of the snippet. - source_aligned: bool, - /// If set to `true`, only the label of the `Annotation` will be - /// displayed. It allows for a multiline annotation to be aligned - /// without displaing the meta information (`type` and `id`) to be - /// displayed on each line. - continuation: bool, - }, -} - -/// An inline text fragment which any label is composed of. -#[derive(Debug, PartialEq)] -pub struct DisplayTextFragment<'a> { - pub content: &'a str, - pub style: DisplayTextStyle, -} - -/// A style for the `DisplayTextFragment` which can be visually formatted. -/// -/// This information may be used to emphasis parts of the label. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum DisplayTextStyle { - Regular, - Emphasis, -} - -/// An indicator of what part of the annotation a given `Annotation` is. -#[derive(Debug, Clone, PartialEq)] -pub enum DisplayAnnotationPart { - /// A standalone, single-line annotation. - Standalone, - /// A continuation of a multi-line label of an annotation. - LabelContinuation, - /// A consequitive annotation in case multiple annotations annotate a single line. - Consequitive, - /// A line starting a multiline annotation. - MultilineStart, - /// A line ending a multiline annotation. - MultilineEnd, -} - -/// A visual mark used in `inline_marks` field of the `DisplaySourceLine`. -#[derive(Debug, Clone, PartialEq)] -pub struct DisplayMark { - pub mark_type: DisplayMarkType, - pub annotation_type: DisplayAnnotationType, -} - -/// A type of the `DisplayMark`. -#[derive(Debug, Clone, PartialEq)] -pub enum DisplayMarkType { - /// A mark indicating a multiline annotation going through the current line. - AnnotationThrough, - /// A mark indicating a multiline annotation starting on the given line. - AnnotationStart, -} - -/// A type of the `Annotation` which may impact the sigils, style or text displayed. -/// -/// There are several ways in which the `DisplayListFormatter` uses this information -/// when formatting the `DisplayList`: -/// -/// * An annotation may display the name of the type like `error` or `info`. -/// * An underline for `Error` may be `^^^` while for `Warning` it coule be `---`. -/// * `ColorStylesheet` may use different colors for different annotations. -#[derive(Debug, Clone, PartialEq)] -pub enum DisplayAnnotationType { - None, - Error, - Warning, - Info, - Note, - Help, -} - -/// Information whether the header is the initial one or a consequitive one -/// for multi-slice cases. -// TODO: private -#[derive(Debug, Clone, PartialEq)] -pub enum DisplayHeaderType { - /// Initial header is the first header in the snippet. - Initial, - - /// Continuation marks all headers of following slices in the snippet. - Continuation, -} diff --git a/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs b/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs deleted file mode 100644 index e93aeb329..000000000 --- a/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs +++ /dev/null @@ -1,397 +0,0 @@ -use std::{ - cmp, - fmt::{self, Display, Write}, -}; - -pub mod style; - -use self::style::{Style, StyleClass, Stylesheet}; - -#[cfg(feature = "color")] -use crate::stylesheets::color::AnsiTermStylesheet; -use crate::{display_list::*, stylesheets::no_color::NoColorStylesheet}; - -fn format_repeat_char(c: char, n: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for _ in 0..n { - f.write_char(c)?; - } - Ok(()) -} - -#[inline] -fn is_annotation_empty(annotation: &Annotation<'_>) -> bool { - annotation - .label - .iter() - .all(|fragment| fragment.content.is_empty()) -} - -#[cfg(feature = "color")] -#[inline] -pub fn get_term_style(color: bool) -> Box { - if color { - Box::new(AnsiTermStylesheet) - } else { - Box::new(NoColorStylesheet) - } -} - -#[cfg(not(feature = "color"))] -#[inline] -pub fn get_term_style(_color: bool) -> Box { - Box::new(NoColorStylesheet) -} - -impl<'a> fmt::Display for DisplayList<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let lineno_width = self.body.iter().fold(0, |max, line| match line { - DisplayLine::Source { - lineno: Some(lineno), - .. - } => { - // The largest line is the largest width. - cmp::max(*lineno, max) - } - _ => max, - }); - let lineno_width = if lineno_width == 0 { - lineno_width - } else if self.anonymized_line_numbers { - Self::ANONYMIZED_LINE_NUM.len() - } else { - ((lineno_width as f64).log10().floor() as usize) + 1 - }; - let inline_marks_width = self.body.iter().fold(0, |max, line| match line { - DisplayLine::Source { inline_marks, .. } => cmp::max(inline_marks.len(), max), - _ => max, - }); - - for (i, line) in self.body.iter().enumerate() { - self.format_line(line, lineno_width, inline_marks_width, f)?; - if i + 1 < self.body.len() { - f.write_char('\n')?; - } - } - Ok(()) - } -} - -impl<'a> DisplayList<'a> { - const ANONYMIZED_LINE_NUM: &'static str = "LL"; - const ERROR_TXT: &'static str = "error"; - const HELP_TXT: &'static str = "help"; - const INFO_TXT: &'static str = "info"; - const NOTE_TXT: &'static str = "note"; - const WARNING_TXT: &'static str = "warning"; - - #[inline] - fn format_annotation_type( - annotation_type: &DisplayAnnotationType, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match annotation_type { - DisplayAnnotationType::Error => f.write_str(Self::ERROR_TXT), - DisplayAnnotationType::Help => f.write_str(Self::HELP_TXT), - DisplayAnnotationType::Info => f.write_str(Self::INFO_TXT), - DisplayAnnotationType::Note => f.write_str(Self::NOTE_TXT), - DisplayAnnotationType::Warning => f.write_str(Self::WARNING_TXT), - DisplayAnnotationType::None => Ok(()), - } - } - - fn annotation_type_len(annotation_type: &DisplayAnnotationType) -> usize { - match annotation_type { - DisplayAnnotationType::Error => Self::ERROR_TXT.len(), - DisplayAnnotationType::Help => Self::HELP_TXT.len(), - DisplayAnnotationType::Info => Self::INFO_TXT.len(), - DisplayAnnotationType::Note => Self::NOTE_TXT.len(), - DisplayAnnotationType::Warning => Self::WARNING_TXT.len(), - DisplayAnnotationType::None => 0, - } - } - - fn get_annotation_style(&self, annotation_type: &DisplayAnnotationType) -> Box { - self.stylesheet.get_style(match annotation_type { - DisplayAnnotationType::Error => StyleClass::Error, - DisplayAnnotationType::Warning => StyleClass::Warning, - DisplayAnnotationType::Info => StyleClass::Info, - DisplayAnnotationType::Note => StyleClass::Note, - DisplayAnnotationType::Help => StyleClass::Help, - DisplayAnnotationType::None => StyleClass::None, - }) - } - - fn format_label( - &self, - label: &[DisplayTextFragment<'_>], - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - let emphasis_style = self.stylesheet.get_style(StyleClass::Emphasis); - - for fragment in label { - match fragment.style { - DisplayTextStyle::Regular => fragment.content.fmt(f)?, - DisplayTextStyle::Emphasis => emphasis_style.paint(&fragment.content, f)?, - } - } - Ok(()) - } - - fn format_annotation( - &self, - annotation: &Annotation<'_>, - continuation: bool, - in_source: bool, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - let color = self.get_annotation_style(&annotation.annotation_type); - let formatted_len = if let Some(id) = &annotation.id { - 2 + id.len() + Self::annotation_type_len(&annotation.annotation_type) - } else { - Self::annotation_type_len(&annotation.annotation_type) - }; - - if continuation { - format_repeat_char(' ', formatted_len + 2, f)?; - return self.format_label(&annotation.label, f); - } - if formatted_len == 0 { - self.format_label(&annotation.label, f) - } else { - color.paint_fn( - Box::new(|f| { - Self::format_annotation_type(&annotation.annotation_type, f)?; - if let Some(id) = &annotation.id { - f.write_char('[')?; - f.write_str(id)?; - f.write_char(']')?; - } - Ok(()) - }), - f, - )?; - if !is_annotation_empty(annotation) { - if in_source { - color.paint_fn( - Box::new(|f| { - f.write_str(": ")?; - self.format_label(&annotation.label, f) - }), - f, - )?; - } else { - f.write_str(": ")?; - self.format_label(&annotation.label, f)?; - } - } - Ok(()) - } - } - - #[inline] - fn format_source_line( - &self, - line: &DisplaySourceLine<'_>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match line { - DisplaySourceLine::Empty => Ok(()), - DisplaySourceLine::Content { text, .. } => { - f.write_char(' ')?; - text.fmt(f) - } - DisplaySourceLine::Annotation { - range, - annotation, - annotation_type, - annotation_part, - } => { - let indent_char = match annotation_part { - DisplayAnnotationPart::Standalone => ' ', - DisplayAnnotationPart::LabelContinuation => ' ', - DisplayAnnotationPart::Consequitive => ' ', - DisplayAnnotationPart::MultilineStart => '_', - DisplayAnnotationPart::MultilineEnd => '_', - }; - let mark = match annotation_type { - DisplayAnnotationType::Error => '^', - DisplayAnnotationType::Warning => '-', - DisplayAnnotationType::Info => '-', - DisplayAnnotationType::Note => '-', - DisplayAnnotationType::Help => '-', - DisplayAnnotationType::None => ' ', - }; - let color = self.get_annotation_style(annotation_type); - let indent_length = match annotation_part { - DisplayAnnotationPart::LabelContinuation => range.1, - DisplayAnnotationPart::Consequitive => range.1, - _ => range.0, - }; - - color.paint_fn( - Box::new(|f| { - format_repeat_char(indent_char, indent_length + 1, f)?; - format_repeat_char(mark, range.1 - indent_length, f) - }), - f, - )?; - - if !is_annotation_empty(&annotation) { - f.write_char(' ')?; - color.paint_fn( - Box::new(|f| { - self.format_annotation( - annotation, - annotation_part == &DisplayAnnotationPart::LabelContinuation, - true, - f, - ) - }), - f, - )?; - } - - Ok(()) - } - } - } - - #[inline] - fn format_raw_line( - &self, - line: &DisplayRawLine<'_>, - lineno_width: usize, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match line { - DisplayRawLine::Origin { - path, - pos, - header_type, - } => { - let header_sigil = match header_type { - DisplayHeaderType::Initial => "-->", - DisplayHeaderType::Continuation => ":::", - }; - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); - - if let Some((col, row)) = pos { - format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil, f)?; - f.write_char(' ')?; - path.fmt(f)?; - f.write_char(':')?; - col.fmt(f)?; - f.write_char(':')?; - row.fmt(f) - } else { - format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil, f)?; - f.write_char(' ')?; - path.fmt(f) - } - } - DisplayRawLine::Annotation { - annotation, - source_aligned, - continuation, - } => { - if *source_aligned { - if *continuation { - format_repeat_char(' ', lineno_width + 3, f)?; - self.format_annotation(annotation, *continuation, false, f) - } else { - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); - format_repeat_char(' ', lineno_width, f)?; - f.write_char(' ')?; - lineno_color.paint("=", f)?; - f.write_char(' ')?; - self.format_annotation(annotation, *continuation, false, f) - } - } else { - self.format_annotation(annotation, *continuation, false, f) - } - } - } - } - - #[inline] - fn format_line( - &self, - dl: &DisplayLine<'_>, - lineno_width: usize, - inline_marks_width: usize, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match dl { - DisplayLine::Source { - lineno, - inline_marks, - line, - } => { - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); - if self.anonymized_line_numbers && lineno.is_some() { - lineno_color.paint_fn( - Box::new(|f| { - f.write_str(Self::ANONYMIZED_LINE_NUM)?; - f.write_str(" |") - }), - f, - )?; - } else { - lineno_color.paint_fn( - Box::new(|f| { - match lineno { - Some(n) => write!(f, "{:>width$}", n, width = lineno_width), - None => format_repeat_char(' ', lineno_width, f), - }?; - f.write_str(" |") - }), - f, - )?; - } - if *line != DisplaySourceLine::Empty { - if !inline_marks.is_empty() || 0 < inline_marks_width { - f.write_char(' ')?; - self.format_inline_marks(inline_marks, inline_marks_width, f)?; - } - self.format_source_line(line, f)?; - } else if !inline_marks.is_empty() { - f.write_char(' ')?; - self.format_inline_marks(inline_marks, inline_marks_width, f)?; - } - Ok(()) - } - DisplayLine::Fold { inline_marks } => { - f.write_str("...")?; - if !inline_marks.is_empty() || 0 < inline_marks_width { - format_repeat_char(' ', lineno_width, f)?; - self.format_inline_marks(inline_marks, inline_marks_width, f)?; - } - Ok(()) - } - DisplayLine::Raw(line) => self.format_raw_line(line, lineno_width, f), - } - } - - fn format_inline_marks( - &self, - inline_marks: &[DisplayMark], - inline_marks_width: usize, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - format_repeat_char(' ', inline_marks_width - inline_marks.len(), f)?; - for mark in inline_marks { - self.get_annotation_style(&mark.annotation_type).paint_fn( - Box::new(|f| { - f.write_char(match mark.mark_type { - DisplayMarkType::AnnotationThrough => '|', - DisplayMarkType::AnnotationStart => '/', - }) - }), - f, - )?; - } - Ok(()) - } -} diff --git a/vendor/annotate-snippets-0.8.0/src/formatter/style.rs b/vendor/annotate-snippets-0.8.0/src/formatter/style.rs deleted file mode 100644 index f76e6b0ab..000000000 --- a/vendor/annotate-snippets-0.8.0/src/formatter/style.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Set of structures required to implement a stylesheet -//! -//! In order to provide additional styling information for the -//! formatter, a structs can implement `Stylesheet` and `Style` -//! traits. -//! -use std::fmt; - -/// StyleClass is a collection of named variants of style classes -pub enum StyleClass { - /// Message indicating an error. - Error, - /// Message indicating a warning. - Warning, - /// Message indicating an information. - Info, - /// Message indicating a note. - Note, - /// Message indicating a help. - Help, - - /// Style for line numbers. - LineNo, - - /// Parts of the text that are to be emphasised. - Emphasis, - - /// Parts of the text that are regular. Usually a no-op. - None, -} - -/// This trait implements a return value for the `Stylesheet::get_style`. -pub trait Style { - /// The method used to write text with formatter - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result; - /// The method used to write display function with formatter - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result; - /// The method used by the DisplayListFormatter to display the message - /// in bold font. - fn bold(&self) -> Box; -} - -/// Trait to annotate structs that can provide `Style` implementations for -/// every `StyleClass` variant. -pub trait Stylesheet { - /// Returns a `Style` implementer based on the requested `StyleClass` variant. - fn get_style(&self, class: StyleClass) -> Box; -} diff --git a/vendor/annotate-snippets-0.8.0/src/lib.rs b/vendor/annotate-snippets-0.8.0/src/lib.rs deleted file mode 100644 index 46b25e156..000000000 --- a/vendor/annotate-snippets-0.8.0/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![deny(rust_2018_idioms)] - -//! A library for formatting of text or programming code snippets. -//! -//! It's primary purpose is to build an ASCII-graphical representation of the snippet -//! with annotations. -//! -//! # Example -//! -//! ```text -//! error[E0308]: mismatched types -//! --> src/format.rs:52:1 -//! | -//! 51 | ) -> Option { -//! | -------------- expected `Option` because of return type -//! 52 | / for ann in annotations { -//! 53 | | match (ann.range.0, ann.range.1) { -//! 54 | | (None, None) => continue, -//! 55 | | (Some(start), Some(end)) if start > end_index => continue, -//! ... | -//! 71 | | } -//! 72 | | } -//! | |_____^ expected enum `std::option::Option`, found () -//! ``` -//! -//! The crate uses a three stage process with two conversions between states: -//! -//! ```text -//! Snippet --> DisplayList --> String -//! ``` -//! -//! The input type - [Snippet](self::snippet) is a structure designed -//! to align with likely output from any parser whose code snippet is to be -//! annotated. -//! -//! The middle structure - [DisplayList](self::display_list) is a -//! structure designed to store the snippet data converted into a vector -//! of lines containing semantic information about each line. -//! This structure is the easiest to manipulate and organize. -//! -//! Finally, [DisplayListFormatter](self::formatter::DisplayListFormatter) is -//! used to format the `DisplayList` using a `Stylesheet` into a final `String` output. -//! -//! A user of the crate may choose to provide their own equivalent of the input -//! structure with an `Into` trait. -//! -//! A user of the crate may also choose to provide their own formatter logic, -//! to convert a `DisplayList` into a `String`, or just a `Stylesheet` to -//! use the crate's formatting logic, but with a custom stylesheet. - -pub mod display_list; -pub mod formatter; -pub mod snippet; -pub mod stylesheets; diff --git a/vendor/annotate-snippets-0.8.0/src/snippet.rs b/vendor/annotate-snippets-0.8.0/src/snippet.rs deleted file mode 100644 index bc7ba0099..000000000 --- a/vendor/annotate-snippets-0.8.0/src/snippet.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Structures used as an input for the library. -//! -//! Example: -//! -//! ``` -//! use annotate_snippets::snippet::*; -//! -//! Snippet { -//! title: Some(Annotation { -//! label: Some("mismatched types"), -//! id: None, -//! annotation_type: AnnotationType::Error, -//! }), -//! footer: vec![], -//! slices: vec![ -//! Slice { -//! source: "Foo", -//! line_start: 51, -//! origin: Some("src/format.rs"), -//! fold: false, -//! annotations: vec![], -//! }, -//! Slice { -//! source: "Faa", -//! line_start: 129, -//! origin: Some("src/display.rs"), -//! fold: false, -//! annotations: vec![], -//! }, -//! ], -//! opt: Default::default(), -//! }; -//! ``` -use crate::display_list::FormatOptions; - -/// Primary structure provided for formatting -#[derive(Debug, Default)] -pub struct Snippet<'a> { - pub title: Option>, - pub footer: Vec>, - pub slices: Vec>, - pub opt: FormatOptions, -} - -/// Structure containing the slice of text to be annotated and -/// basic information about the location of the slice. -/// -/// One `Slice` is meant to represent a single, continuous, -/// slice of source code that you want to annotate. -#[derive(Debug)] -pub struct Slice<'a> { - pub source: &'a str, - pub line_start: usize, - pub origin: Option<&'a str>, - pub annotations: Vec>, - /// If set explicitly to `true`, the snippet will fold - /// parts of the slice that don't contain any annotations. - pub fold: bool, -} - -/// Types of annotations. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum AnnotationType { - /// Error annotations are displayed using red color and "^" character. - Error, - /// Warning annotations are displayed using blue color and "-" character. - Warning, - Info, - Note, - Help, -} - -/// An annotation for a `Slice`. -#[derive(Debug)] -pub struct SourceAnnotation<'a> { - pub range: (usize, usize), - pub label: &'a str, - pub annotation_type: AnnotationType, -} - -/// An annotation for a `Snippet`. -#[derive(Debug)] -pub struct Annotation<'a> { - /// Identifier of the annotation. Usually error code like "E0308". - pub id: Option<&'a str>, - pub label: Option<&'a str>, - pub annotation_type: AnnotationType, -} diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs deleted file mode 100644 index 024dd06f6..000000000 --- a/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::fmt::{self, Display}; - -use yansi_term::{Color::Fixed, Style as AnsiTermStyle}; - -use crate::formatter::style::{Style, StyleClass, Stylesheet}; - -struct AnsiTermStyleWrapper { - style: AnsiTermStyle, -} - -impl Style for AnsiTermStyleWrapper { - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.style.paint(text).fmt(f) - } - - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - self.style.paint_fn(c).fmt(f) - } - - fn bold(&self) -> Box { - Box::new(AnsiTermStyleWrapper { style: self.style }) - } -} - -pub struct AnsiTermStylesheet; - -impl Stylesheet for AnsiTermStylesheet { - fn get_style(&self, class: StyleClass) -> Box { - let ansi_term_style = match class { - StyleClass::Error => Fixed(9).bold(), - StyleClass::Warning => Fixed(11).bold(), - StyleClass::Info => Fixed(12).bold(), - StyleClass::Note => AnsiTermStyle::new().bold(), - StyleClass::Help => Fixed(14).bold(), - - StyleClass::LineNo => Fixed(12).bold(), - - StyleClass::Emphasis => AnsiTermStyle::new().bold(), - - StyleClass::None => AnsiTermStyle::new(), - }; - Box::new(AnsiTermStyleWrapper { - style: ansi_term_style, - }) - } -} diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs deleted file mode 100644 index 49f6ea04b..000000000 --- a/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! List of stylesheets that can be used by the `DisplayListFormatter`. -//! -//! The list depends on what optional dependencies the crate has been -//! compiled with. -//! -//! By default the `no_color` is available. If the crate gets compiled -//! with `ansi_term`, the `color` stylesheet is added. - -#[cfg(feature = "color")] -pub mod color; -pub mod no_color; diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs deleted file mode 100644 index 21cb26955..000000000 --- a/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::fmt; - -use crate::formatter::style::{Style, StyleClass, Stylesheet}; - -pub struct NoOpStyle {} - -impl Style for NoOpStyle { - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(text) - } - - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - c(f) - } - - fn bold(&self) -> Box { - Box::new(NoOpStyle {}) - } -} - -pub struct NoColorStylesheet; - -impl Stylesheet for NoColorStylesheet { - fn get_style(&self, _class: StyleClass) -> Box { - Box::new(NoOpStyle {}) - } -} diff --git a/vendor/annotate-snippets-0.8.0/tests/diff/mod.rs b/vendor/annotate-snippets-0.8.0/tests/diff/mod.rs deleted file mode 100644 index 576c6c4d6..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/diff/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -use difference::{Changeset, Difference}; -use yansi_term::Color::{Black, Green, Red}; - -pub fn get_diff(left: &str, right: &str) -> String { - let mut output = String::new(); - - let Changeset { diffs, .. } = Changeset::new(left, right, "\n"); - - for i in 0..diffs.len() { - match diffs[i] { - Difference::Same(ref x) => { - output += &format!(" {}\n", x); - } - Difference::Add(ref x) => { - match diffs[i - 1] { - Difference::Rem(ref y) => { - output += &format!("{}", Green.paint("+")); - let Changeset { diffs, .. } = Changeset::new(y, x, " "); - for c in diffs { - match c { - Difference::Same(ref z) => { - output += &format!("{} ", Green.paint(z.as_str())); - } - Difference::Add(ref z) => { - output += &format!("{} ", Black.on(Green).paint(z.as_str())); - } - _ => (), - } - } - output += "\n"; - } - _ => { - output += &format!("+{}\n", Green.paint(x.as_str())); - } - }; - } - Difference::Rem(ref x) => { - output += &format!("-{}\n", Red.paint(x.as_str())); - } - } - } - output -} diff --git a/vendor/annotate-snippets-0.8.0/tests/dl_from_snippet.rs b/vendor/annotate-snippets-0.8.0/tests/dl_from_snippet.rs deleted file mode 100644 index 2ed990261..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/dl_from_snippet.rs +++ /dev/null @@ -1,401 +0,0 @@ -use annotate_snippets::display_list::DisplayList; -use annotate_snippets::{display_list as dl, formatter::get_term_style, snippet}; - -#[test] -fn test_format_title() { - let input = snippet::Snippet { - title: Some(snippet::Annotation { - id: Some("E0001"), - label: Some("This is a title"), - annotation_type: snippet::AnnotationType::Error, - }), - footer: vec![], - slices: vec![], - opt: Default::default(), - }; - let output = dl::DisplayList { - body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![dl::DisplayTextFragment { - content: "This is a title", - style: dl::DisplayTextStyle::Emphasis, - }], - }, - source_aligned: false, - continuation: false, - })], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slice() { - let line_1 = "This is line 1"; - let line_2 = "This is line 2"; - let source = vec![line_1, line_2].join("\n"); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - source: &source, - line_start: 5402, - origin: None, - annotations: vec![], - fold: false, - }], - opt: Default::default(), - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: line_1, - range: (0, line_1.len()), - }, - }, - dl::DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slices_continuation() { - let src_0 = "This is slice 1"; - let src_0_len = src_0.len(); - let src_1 = "This is slice 2"; - let src_1_len = src_1.len(); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![ - snippet::Slice { - source: src_0, - line_start: 5402, - origin: Some("file1.rs"), - annotations: vec![], - fold: false, - }, - snippet::Slice { - source: src_1, - line_start: 2, - origin: Some("file2.rs"), - annotations: vec![], - fold: false, - }, - ], - opt: Default::default(), - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "file1.rs", - pos: None, - header_type: dl::DisplayHeaderType::Initial, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: src_0, - range: (0, src_0_len), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "file2.rs", - pos: None, - header_type: dl::DisplayHeaderType::Continuation, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: src_1, - range: (0, src_1_len), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slice_annotation_standalone() { - let line_1 = "This is line 1"; - let line_2 = "This is line 2"; - let source = vec![line_1, line_2].join("\n"); - // In line 2 - let range = (22, 24); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - source: &source, - line_start: 5402, - origin: None, - annotations: vec![snippet::SourceAnnotation { - range, - label: "Test annotation", - annotation_type: snippet::AnnotationType::Info, - }], - fold: false, - }], - opt: Default::default(), - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (0, line_1.len()), - text: line_1, - }, - }, - dl::DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Info, - id: None, - label: vec![dl::DisplayTextFragment { - content: "Test annotation", - style: dl::DisplayTextStyle::Regular, - }], - }, - range: (range.0 - (line_1.len() + 1), range.1 - (line_1.len() + 1)), - annotation_type: dl::DisplayAnnotationType::Info, - annotation_part: dl::DisplayAnnotationPart::Standalone, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_label() { - let input = snippet::Snippet { - title: None, - footer: vec![snippet::Annotation { - id: None, - label: Some("This __is__ a title"), - annotation_type: snippet::AnnotationType::Error, - }], - slices: vec![], - opt: Default::default(), - }; - let output = dl::DisplayList { - body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: None, - label: vec![ - dl::DisplayTextFragment { - content: "This ", - style: dl::DisplayTextStyle::Regular, - }, - dl::DisplayTextFragment { - content: "is", - style: dl::DisplayTextStyle::Emphasis, - }, - dl::DisplayTextFragment { - content: " a title", - style: dl::DisplayTextStyle::Regular, - }, - ], - }, - source_aligned: true, - continuation: false, - })], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -#[should_panic] -fn test_i26() { - let source = "short"; - let label = "label"; - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - annotations: vec![snippet::SourceAnnotation { - range: (0, source.len() + 1), - label, - annotation_type: snippet::AnnotationType::Error, - }], - source, - line_start: 0, - origin: None, - fold: false, - }], - opt: Default::default(), - }; - - let _ = dl::DisplayList::from(input); -} - -#[test] -fn test_i_29() { - let snippets = snippet::Snippet { - title: Some(snippet::Annotation { - id: None, - label: Some("oops"), - annotation_type: snippet::AnnotationType::Error, - }), - footer: vec![], - slices: vec![snippet::Slice { - source: "First line\r\nSecond oops line", - line_start: 1, - origin: Some(""), - annotations: vec![snippet::SourceAnnotation { - range: (19, 23), - label: "oops", - annotation_type: snippet::AnnotationType::Error, - }], - fold: true, - }], - opt: Default::default(), - }; - - let expected = DisplayList { - body: vec![ - dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: None, - label: vec![dl::DisplayTextFragment { - content: "oops", - style: dl::DisplayTextStyle::Emphasis, - }], - }, - source_aligned: false, - continuation: false, - }), - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "", - pos: Some((2, 8)), - header_type: dl::DisplayHeaderType::Initial, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(1), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: "First line", - range: (0, 10), - }, - }, - dl::DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: "Second oops line", - range: (12, 28), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::None, - id: None, - label: vec![dl::DisplayTextFragment { - content: "oops", - style: dl::DisplayTextStyle::Regular, - }], - }, - range: (7, 11), - annotation_type: dl::DisplayAnnotationType::Error, - annotation_part: dl::DisplayAnnotationPart::Standalone, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: get_term_style(false), - anonymized_line_numbers: false, - }; - - assert_eq!(DisplayList::from(snippets), expected); -} diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.toml b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.toml deleted file mode 100644 index bdb577f46..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.toml +++ /dev/null @@ -1,40 +0,0 @@ -[[slices]] -source = """ -) -> Option { - for ann in annotations { - match (ann.range.0, ann.range.1) { - (None, None) => continue, - (Some(start), Some(end)) if start > end_index || end < start_index => continue, - (Some(start), Some(end)) if start >= start_index && end <= end_index => { - let label = if let Some(ref label) = ann.label { - format!(" {}", label) - } else { - String::from("") - }; - - return Some(format!( - "{}{}{}", - " ".repeat(start - start_index), - "^".repeat(end - start), - label - )); - } - _ => continue, - } - } -""" -line_start = 51 -origin = "src/format.rs" -fold = true -[[slices.annotations]] -label = "expected `std::option::Option` because of return type" -annotation_type = "Warning" -range = [5, 19] -[[slices.annotations]] -label = "expected enum `std::option::Option`, found ()" -annotation_type = "Error" -range = [22, 765] -[title] -label = "mismatched types" -id = "E0308" -annotation_type = "Error" diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.txt b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.txt deleted file mode 100644 index bacdec10d..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation.txt +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> src/format.rs:51:6 - | -51 | ) -> Option { - | -------------- expected `std::option::Option` because of return type -52 | / for ann in annotations { -53 | | match (ann.range.0, ann.range.1) { -54 | | (None, None) => continue, -55 | | (Some(start), Some(end)) if start > end_index || end < start_index => continue, -... | -71 | | } -72 | | } - | |_____^ expected enum `std::option::Option`, found () - | diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.toml b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.toml deleted file mode 100644 index 6ec0b1fe8..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.toml +++ /dev/null @@ -1,18 +0,0 @@ -[[slices]] -source = """ - if let DisplayLine::Source { - ref mut inline_marks, - } = body[body_idx] -""" -line_start = 139 -origin = "src/display_list.rs" -fold = false -[[slices.annotations]] -label = "missing fields `lineno`, `content`" -annotation_type = "Error" -range = [31, 127] - -[title] -label = "pattern does not mention fields `lineno`, `content`" -id = "E0027" -annotation_type = "Error" diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.txt b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.txt deleted file mode 100644 index 8a00bfa20..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation2.txt +++ /dev/null @@ -1,9 +0,0 @@ -error[E0027]: pattern does not mention fields `lineno`, `content` - --> src/display_list.rs:139:32 - | -139 | if let DisplayLine::Source { - | ________________________________^ -140 | | ref mut inline_marks, -141 | | } = body[body_idx] - | |_________________________^ missing fields `lineno`, `content` - | diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.toml b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.toml deleted file mode 100644 index 21bbcd857..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.toml +++ /dev/null @@ -1,18 +0,0 @@ -[[slices]] -source = """ -This is an exampl -e of an edge case of an annotation overflowing -to exactly one character on next line. -""" -line_start = 26 -origin = "foo.txt" -fold = false -[[slices.annotations]] -label = "this should not be on separate lines" -annotation_type = "Error" -range = [11, 18] - -[title] -label = "spacing error found" -id = "E####" -annotation_type = "Error" diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.txt b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.txt deleted file mode 100644 index 12e174c56..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiline_annotation3.txt +++ /dev/null @@ -1,9 +0,0 @@ -error[E####]: spacing error found - --> foo.txt:26:12 - | -26 | This is an exampl - | ____________^ -27 | | e of an edge case of an annotation overflowing - | |_^ this should not be on separate lines -28 | to exactly one character on next line. - | \ No newline at end of file diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.toml b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.toml deleted file mode 100644 index 84efc5f17..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.toml +++ /dev/null @@ -1,25 +0,0 @@ -[[slices]] -source = """ -fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation>) { - if let Some(annotation) = main_annotation { - result.push(format_title_line( - &annotation.annotation_type, - None, - &annotation.label, - )); - } -} -""" -line_start = 96 -[[slices.annotations]] -label = "Variable defined here" -annotation_type = "Error" -range = [100, 110] -[[slices.annotations]] -label = "Referenced here" -annotation_type = "Error" -range = [184, 194] -[[slices.annotations]] -label = "Referenced again here" -annotation_type = "Error" -range = [243, 253] diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.txt b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.txt deleted file mode 100644 index 26c677f7e..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/multiple_annotations.txt +++ /dev/null @@ -1,14 +0,0 @@ - | - 96 | fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation>) { - 97 | if let Some(annotation) = main_annotation { - | ^^^^^^^^^^ Variable defined here - 98 | result.push(format_title_line( - 99 | &annotation.annotation_type, - | ^^^^^^^^^^ Referenced here -100 | None, -101 | &annotation.label, - | ^^^^^^^^^^ Referenced again here -102 | )); -103 | } -104 | } - | diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.toml b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.toml deleted file mode 100644 index 6c38674ac..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.toml +++ /dev/null @@ -1,18 +0,0 @@ -[[slices]] -source = """ - }) - - for line in &self.body {""" -line_start = 169 -origin = "src/format_color.rs" -[[slices.annotations]] -label = "unexpected token" -annotation_type = "Error" -range = [20, 23] -[[slices.annotations]] -label = "expected one of `.`, `;`, `?`, or an operator here" -annotation_type = "Warning" -range = [10, 11] -[title] -label = "expected one of `.`, `;`, `?`, or an operator, found `for`" -annotation_type = "Error" diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.txt b/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.txt deleted file mode 100644 index 752cc890f..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures/no-color/simple.txt +++ /dev/null @@ -1,9 +0,0 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `for` - --> src/format_color.rs:171:9 - | -169 | }) - | - expected one of `.`, `;`, `?`, or an operator here -170 | -171 | for line in &self.body { - | ^^^ unexpected token - | diff --git a/vendor/annotate-snippets-0.8.0/tests/fixtures_test.rs b/vendor/annotate-snippets-0.8.0/tests/fixtures_test.rs deleted file mode 100644 index e471521f2..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/fixtures_test.rs +++ /dev/null @@ -1,45 +0,0 @@ -mod diff; -mod snippet; - -use crate::snippet::SnippetDef; -use annotate_snippets::{display_list::DisplayList, snippet::Snippet}; -use glob::glob; -use std::{error::Error, fs::File, io, io::prelude::*}; - -fn read_file(path: &str) -> Result { - let mut f = File::open(path)?; - let mut s = String::new(); - (f.read_to_string(&mut s))?; - Ok(s.trim_end().to_string()) -} - -fn read_fixture<'de>(src: &'de str) -> Result, Box> { - Ok(toml::from_str(src).map(|a: SnippetDef| a.into())?) -} - -#[test] -fn test_fixtures() { - for entry in glob("./tests/fixtures/no-color/**/*.toml").expect("Failed to read glob pattern") { - let p = entry.expect("Error while getting an entry"); - - let path_in = p.to_str().expect("Can't print path"); - let path_out = path_in.replace(".toml", ".txt"); - - let src = read_file(&path_in).expect("Failed to read file"); - let snippet = read_fixture(&src).expect("Failed to read file"); - let expected_out = read_file(&path_out).expect("Failed to read file"); - - let dl = DisplayList::from(snippet); - let actual_out = dl.to_string(); - println!("{}", expected_out); - println!("{}", actual_out.trim_end()); - - assert_eq!( - expected_out, - actual_out.trim_end(), - "\n\n\nWhile parsing: {}\nThe diff is:\n\n\n{}\n\n\n", - path_in, - diff::get_diff(expected_out.as_str(), actual_out.as_str()) - ); - } -} diff --git a/vendor/annotate-snippets-0.8.0/tests/formatter.rs b/vendor/annotate-snippets-0.8.0/tests/formatter.rs deleted file mode 100644 index 5c7211d1e..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/formatter.rs +++ /dev/null @@ -1,552 +0,0 @@ -use annotate_snippets::display_list::*; -use annotate_snippets::snippet::{self, Snippet}; - -#[test] -fn test_source_empty() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }]); - - assert_eq!(dl.to_string(), " |"); -} - -#[test] -fn test_source_content() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(56), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is an example", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: Some(57), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "of content lines", - range: (0, 19), - }, - }, - ]); - - assert_eq!( - dl.to_string(), - "56 | This is an example\n57 | of content lines" - ); -} - -#[test] -fn test_source_annotation_standalone_singleline() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Error, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }]); - - assert_eq!(dl.to_string(), " | ^^^^^ Example string"); -} - -#[test] -fn test_source_annotation_standalone_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Warning, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "Second line", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Warning, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - ]); - - assert_eq!( - dl.to_string(), - " | ----- help: Example string\n | Second line" - ); -} - -#[test] -fn test_source_annotation_standalone_multi_annotation() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "Second line", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: None, - label: vec![DisplayTextFragment { - content: "This is a note", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::Consequitive, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: None, - label: vec![DisplayTextFragment { - content: "Second line of the warning", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "This is an info", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Info, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "This is help", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Help, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 0), - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "This is an annotation of type none", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::None, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - ]); - - assert_eq!(dl.to_string(), " | ----- info: Example string\n | Second line\n | warning: This is a note\n | Second line of the warning\n | ----- info: This is an info\n | ----- help: This is help\n | This is an annotation of type none"); -} - -#[test] -fn test_fold_line() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(5), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is line 5", - range: (0, 19), - }, - }, - DisplayLine::Fold { - inline_marks: vec![], - }, - DisplayLine::Source { - lineno: Some(10021), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "... and now we're at line 10021", - range: (0, 19), - }, - }, - ]); - - assert_eq!( - dl.to_string(), - " 5 | This is line 5\n...\n10021 | ... and now we're at line 10021" - ); -} - -#[test] -fn test_raw_origin_initial_nopos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: None, - header_type: DisplayHeaderType::Initial, - })]); - - assert_eq!(dl.to_string(), "--> src/test.rs"); -} - -#[test] -fn test_raw_origin_initial_pos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Initial, - })]); - - assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); -} - -#[test] -fn test_raw_origin_continuation() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Continuation, - })]); - - assert_eq!(dl.to_string(), "::: src/test.rs:23:15"); -} - -#[test] -fn test_raw_annotation_unaligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - })]); - - assert_eq!(dl.to_string(), "error[E0001]: This is an error"); -} - -#[test] -fn test_raw_annotation_unaligned_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "Second line of the error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - "warning[E0001]: This is an error\n Second line of the error" - ); -} - -#[test] -fn test_raw_annotation_aligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - })]); - - assert_eq!(dl.to_string(), " = error[E0001]: This is an error"); -} - -#[test] -fn test_raw_annotation_aligned_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "Second line of the error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - " = warning[E0001]: This is an error\n Second line of the error" - ); -} - -#[test] -fn test_different_annotation_types() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Note, - id: None, - label: vec![DisplayTextFragment { - content: "This is a note", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "This is just a string", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "Second line of none type annotation", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - "note: This is a note\nThis is just a string\n Second line of none type annotation", - ); -} - -#[test] -fn test_inline_marks_empty_line() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![DisplayMark { - mark_type: DisplayMarkType::AnnotationThrough, - annotation_type: DisplayAnnotationType::Error, - }], - line: DisplaySourceLine::Empty, - }]); - - assert_eq!(dl.to_string(), " | |",); -} - -#[test] -fn test_anon_lines() { - let mut dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(56), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is an example", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: Some(57), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "of content lines", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "abc", - range: (0, 19), - }, - }, - ]); - - dl.anonymized_line_numbers = true; - assert_eq!( - dl.to_string(), - "LL | This is an example\nLL | of content lines\n |\n | abc" - ); -} - -#[test] -fn test_raw_origin_initial_pos_anon_lines() { - let mut dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Initial, - })]); - - // Using anonymized_line_numbers should not affect the inital position - dl.anonymized_line_numbers = true; - assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); -} - -#[test] -fn test_i_29() { - let snippets = Snippet { - title: Some(snippet::Annotation { - id: None, - label: Some("oops"), - annotation_type: snippet::AnnotationType::Error, - }), - footer: vec![], - slices: vec![snippet::Slice { - source: "First line\r\nSecond oops line", - line_start: 1, - origin: Some(""), - annotations: vec![snippet::SourceAnnotation { - range: (19, 23), - label: "oops", - annotation_type: snippet::AnnotationType::Error, - }], - fold: true, - }], - opt: Default::default(), - }; - let expected = r#"error: oops - --> :2:8 - | -1 | First line -2 | Second oops line - | ^^^^ oops - |"#; - - assert_eq!(DisplayList::from(snippets).to_string(), expected); -} diff --git a/vendor/annotate-snippets-0.8.0/tests/snippet/mod.rs b/vendor/annotate-snippets-0.8.0/tests/snippet/mod.rs deleted file mode 100644 index c3348741a..000000000 --- a/vendor/annotate-snippets-0.8.0/tests/snippet/mod.rs +++ /dev/null @@ -1,167 +0,0 @@ -use serde::{Deserialize, Deserializer, Serialize}; - -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; - -#[derive(Deserialize)] -pub struct SnippetDef<'a> { - #[serde(deserialize_with = "deserialize_annotation")] - #[serde(default)] - #[serde(borrow)] - pub title: Option>, - #[serde(deserialize_with = "deserialize_annotations")] - #[serde(default)] - #[serde(borrow)] - pub footer: Vec>, - #[serde(deserialize_with = "deserialize_opt")] - #[serde(default)] - pub opt: FormatOptions, - #[serde(deserialize_with = "deserialize_slices")] - #[serde(borrow)] - pub slices: Vec>, -} - -impl<'a> Into> for SnippetDef<'a> { - fn into(self) -> Snippet<'a> { - let SnippetDef { - title, - footer, - opt, - slices, - } = self; - Snippet { - title, - footer, - slices, - opt, - } - } -} - -fn deserialize_opt<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper(#[serde(with = "FormatOptionsDef")] FormatOptions); - - Wrapper::deserialize(deserializer).map(|w| w.0) -} - -#[derive(Deserialize)] -#[serde(remote = "FormatOptions")] -pub struct FormatOptionsDef { - pub color: bool, - pub anonymized_line_numbers: bool, -} - -fn deserialize_slices<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper<'a>( - #[serde(with = "SliceDef")] - #[serde(borrow)] - Slice<'a>, - ); - - let v = Vec::deserialize(deserializer)?; - Ok(v.into_iter().map(|Wrapper(a)| a).collect()) -} - -fn deserialize_annotation<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper<'a>( - #[serde(with = "AnnotationDef")] - #[serde(borrow)] - Annotation<'a>, - ); - - Option::::deserialize(deserializer) - .map(|opt_wrapped: Option| opt_wrapped.map(|wrapped: Wrapper| wrapped.0)) -} - -fn deserialize_annotations<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper<'a>( - #[serde(with = "AnnotationDef")] - #[serde(borrow)] - Annotation<'a>, - ); - - let v = Vec::deserialize(deserializer)?; - Ok(v.into_iter().map(|Wrapper(a)| a).collect()) -} - -#[derive(Deserialize)] -#[serde(remote = "Slice")] -pub struct SliceDef<'a> { - #[serde(borrow)] - pub source: &'a str, - pub line_start: usize, - #[serde(borrow)] - pub origin: Option<&'a str>, - #[serde(deserialize_with = "deserialize_source_annotations")] - #[serde(borrow)] - pub annotations: Vec>, - #[serde(default)] - pub fold: bool, -} - -fn deserialize_source_annotations<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper<'a>( - #[serde(with = "SourceAnnotationDef")] - #[serde(borrow)] - SourceAnnotation<'a>, - ); - - let v = Vec::deserialize(deserializer)?; - Ok(v.into_iter().map(|Wrapper(a)| a).collect()) -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "SourceAnnotation")] -pub struct SourceAnnotationDef<'a> { - pub range: (usize, usize), - #[serde(borrow)] - pub label: &'a str, - #[serde(with = "AnnotationTypeDef")] - pub annotation_type: AnnotationType, -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "Annotation")] -pub struct AnnotationDef<'a> { - #[serde(borrow)] - pub id: Option<&'a str>, - #[serde(borrow)] - pub label: Option<&'a str>, - #[serde(with = "AnnotationTypeDef")] - pub annotation_type: AnnotationType, -} - -#[allow(dead_code)] -#[derive(Serialize, Deserialize)] -#[serde(remote = "AnnotationType")] -enum AnnotationTypeDef { - Error, - Warning, - Info, - Note, - Help, -} diff --git a/vendor/anyhow/.cargo-checksum.json b/vendor/anyhow/.cargo-checksum.json index 7b37c5570..5bbee7b7b 100644 --- a/vendor/anyhow/.cargo-checksum.json +++ b/vendor/anyhow/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b83515ea98aa6ba603307c3629b86b0ad85e3017df8fe9f444c4bc8e0fc18c03","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4bd4d352368ac0f5447031d82454490f6ac0c80d2fa4cb64ba0c23c614670d49","build.rs":"f82a81a4c16e3b68140e10c3d3a9ee54af48c53133a1d894fbb92190f09f0550","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"5a60bd1fe1717c044c7ab34c062ce6651c0cb08596a5878e391c2755ecac07f9","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"559478ae785ce913523aa21358cc1561ef4b0b95c5c87675a77890364c0162fe","src/ensure.rs":"ba404f1708d41a267f8678858aebefadc8fae717bd5533e5ebb47e219aa44f7e","src/error.rs":"6c5b1357eedd6f2be1fdaee1be645a33e68c945c481d6ff20b98c8fdedea687a","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"b21b15dbee77d50abe88684a9571b39659076465dd4b1956f366af8fdd26e95a","src/lib.rs":"b340e18f5666d53289ce3428054e9789009cf60ea3e9ff717b3a4028fbaba6c2","src/macros.rs":"4ff9a40d7ff06cc02b387f40d6ae296990493cd7f9755880c621c47e7e845f07","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"d5e90e3eba58abc60d241d3aade39e0b8d4006d9a14f3cf015d3d925160b5812","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"bd793da08a4d01b8211646d82bec73468e54f6caf5f520617519a12cbb6659b9","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"11f05010bc9b16319884c1286444100e30cddc2ecd1ffe5e0fd3fee5ffb32683","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"345102cbef47310f2f4066a669199873a627ca4f1fcb885505c6e17d1fc95e88","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"4dc15f52c3a186251c948b6a2955b777ed3c88e5da94b887f8ff945b3ecd8cee","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"39d3234c0cbb6213a422485cd1bf64b0877d2b2ea3e168b099bc8a6c1e0d33df","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"64e448b6759cf51d41b1360307a638452bbe53ffa706f93e4a503b712d7b89a8","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"} \ No newline at end of file +{"files":{"Cargo.toml":"5779c6bea2555cdabd4560de187ac5e3c88ff2df8172077397643edc51c6fcc3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4bd4d352368ac0f5447031d82454490f6ac0c80d2fa4cb64ba0c23c614670d49","build.rs":"88bf7100143c79c0af683da7f28deaac031c9b9b213a6426560dc089b0ba45aa","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"5b4103a7d24d6f438a64b8cc0fafe28d55fc0ca090368174ce44d64e3940badd","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"0bb1566aae147d393796dd6ede6ba329916e0a373b7cbc38335c3eeeb3d48b57","src/ensure.rs":"498bc9c7fb8b93168ed12f532cb97df6ccdda9ce25371586d7f5b1b1c98a14bf","src/error.rs":"e45d4dcfe64b1823b42fbf9bb260e6437987e8c2d51f92434db9d808b36e700a","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"332854c5eb07d44447c356a2e7dc585634b0da1ffbbfa81269c369deaefbc247","src/lib.rs":"82011e86fb9b41fe10ab2fde2b797b4858e697e7ead3a5f0d30b018357f1721d","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"ff3ad72065a30cc32e9acb0614a30703c49c57b941a335c348b6439af684316b","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"d5e90e3eba58abc60d241d3aade39e0b8d4006d9a14f3cf015d3d925160b5812","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"c8137a9565685aedf02b365008b27c707f4c3d81cd2b986b3b7105b426c723b1","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"11f05010bc9b16319884c1286444100e30cddc2ecd1ffe5e0fd3fee5ffb32683","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"345102cbef47310f2f4066a669199873a627ca4f1fcb885505c6e17d1fc95e88","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"9d36a96220f0b5a81db027bcba411a61a72cc2e370c38058ab556442e8bb8a8b","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"64e448b6759cf51d41b1360307a638452bbe53ffa706f93e4a503b712d7b89a8","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"} \ No newline at end of file diff --git a/vendor/anyhow/Cargo.toml b/vendor/anyhow/Cargo.toml index 6537f7b5f..844c2bd3a 100644 --- a/vendor/anyhow/Cargo.toml +++ b/vendor/anyhow/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.38" name = "anyhow" -version = "1.0.60" +version = "1.0.65" authors = ["David Tolnay "] description = "Flexible concrete Error type built on std::error::Error" documentation = "https://docs.rs/anyhow" diff --git a/vendor/anyhow/build.rs b/vendor/anyhow/build.rs index c470ba11b..38006832e 100644 --- a/vendor/anyhow/build.rs +++ b/vendor/anyhow/build.rs @@ -15,15 +15,17 @@ compile_error! { // type. If the current toolchain is able to compile it, we go ahead and use // backtrace in anyhow. const PROBE: &str = r#" - #![feature(backtrace)] - #![allow(dead_code)] + #![feature(error_generic_member_access, provide_any)] + use std::any::{Demand, Provider}; use std::backtrace::{Backtrace, BacktraceStatus}; use std::error::Error; use std::fmt::{self, Display}; #[derive(Debug)] - struct E; + struct E { + backtrace: Backtrace, + } impl Display for E { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { @@ -32,14 +34,26 @@ const PROBE: &str = r#" } impl Error for E { - fn backtrace(&self) -> Option<&Backtrace> { - let backtrace = Backtrace::capture(); - match backtrace.status() { - BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} - } - unimplemented!() + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + demand.provide_ref(&self.backtrace); } } + + struct P; + + impl Provider for P { + fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {} + } + + const _: fn() = || { + let backtrace: Backtrace = Backtrace::capture(); + let status: BacktraceStatus = backtrace.status(); + match status { + BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} + } + }; + + const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::(); "#; fn main() { diff --git a/vendor/anyhow/src/backtrace.rs b/vendor/anyhow/src/backtrace.rs index e4c907641..23c0c85ce 100644 --- a/vendor/anyhow/src/backtrace.rs +++ b/vendor/anyhow/src/backtrace.rs @@ -38,7 +38,7 @@ macro_rules! backtrace { #[cfg(backtrace)] macro_rules! backtrace_if_absent { ($err:expr) => { - match $err.backtrace() { + match ($err as &dyn std::error::Error).request_ref::() { Some(_) => None, None => backtrace!(), } diff --git a/vendor/anyhow/src/context.rs b/vendor/anyhow/src/context.rs index c2284130f..1b7dd31ac 100644 --- a/vendor/anyhow/src/context.rs +++ b/vendor/anyhow/src/context.rs @@ -4,7 +4,7 @@ use core::convert::Infallible; use core::fmt::{self, Debug, Display, Write}; #[cfg(backtrace)] -use std::backtrace::Backtrace; +use std::any::Demand; mod ext { use super::*; @@ -24,7 +24,7 @@ mod ext { where C: Display + Send + Sync + 'static, { - let backtrace = backtrace_if_absent!(self); + let backtrace = backtrace_if_absent!(&self); Error::from_context(context, self, backtrace) } } @@ -123,28 +123,29 @@ where C: Display, E: StdError + 'static, { - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&Backtrace> { - self.error.backtrace() - } - fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.error) } + + #[cfg(backtrace)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.error.provide(demand); + } } impl StdError for ContextError where C: Display, { - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&Backtrace> { - Some(self.error.backtrace()) - } - fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) }) } + + #[cfg(backtrace)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + demand.provide_ref(self.error.backtrace()); + self.error.provide(demand); + } } struct Quoted(C); diff --git a/vendor/anyhow/src/ensure.rs b/vendor/anyhow/src/ensure.rs index 80bdab704..0ab447123 100644 --- a/vendor/anyhow/src/ensure.rs +++ b/vendor/anyhow/src/ensure.rs @@ -788,15 +788,15 @@ macro_rules! __fancy_ensure { (lhs, rhs) => { if !(lhs $op rhs) { #[allow(unused_imports)] - use $crate::private::{BothDebug, NotBothDebug}; + use $crate::__private::{BothDebug, NotBothDebug}; return Err((lhs, rhs).__dispatch_ensure( - $crate::private::concat!( + $crate::__private::concat!( "Condition failed: `", - $crate::private::stringify!($lhs), + $crate::__private::stringify!($lhs), " ", - $crate::private::stringify!($op), + $crate::__private::stringify!($op), " ", - $crate::private::stringify!($rhs), + $crate::__private::stringify!($rhs), "`", ), )); @@ -811,24 +811,24 @@ macro_rules! __fancy_ensure { macro_rules! __fallback_ensure { ($cond:expr $(,)?) => { if !$cond { - return $crate::private::Err($crate::Error::msg( - $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`") + return $crate::__private::Err($crate::Error::msg( + $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") )); } }; ($cond:expr, $msg:literal $(,)?) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($msg)); + return $crate::__private::Err($crate::__anyhow!($msg)); } }; ($cond:expr, $err:expr $(,)?) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($err)); + return $crate::__private::Err($crate::__anyhow!($err)); } }; ($cond:expr, $fmt:expr, $($arg:tt)*) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*)); + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); } }; } diff --git a/vendor/anyhow/src/error.rs b/vendor/anyhow/src/error.rs index 0971146c9..9f6ce8c10 100644 --- a/vendor/anyhow/src/error.rs +++ b/vendor/anyhow/src/error.rs @@ -5,6 +5,8 @@ use crate::ptr::Mut; use crate::ptr::{Own, Ref}; use crate::{Error, StdError}; use alloc::boxed::Box; +#[cfg(backtrace)] +use core::any::Demand; use core::any::TypeId; use core::fmt::{self, Debug, Display}; use core::mem::ManuallyDrop; @@ -31,7 +33,7 @@ impl Error { where E: StdError + Send + Sync + 'static, { - let backtrace = backtrace_if_absent!(error); + let backtrace = backtrace_if_absent!(&error); Error::from_std(error, backtrace) } @@ -522,6 +524,18 @@ impl Error { } } +#[cfg(backtrace)] +impl std::any::Provider for Error { + // Called by thiserror when you have `#[source] anyhow::Error`. This provide + // implementation includes the anyhow::Error's Backtrace if any, unlike + // deref'ing to dyn Error where the provide implementation would include + // only the original error's Backtrace from before it got wrapped into an + // anyhow::Error. + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + unsafe { ErrorImpl::provide(self.inner.by_ref(), demand) } + } +} + #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] impl From for Error @@ -530,7 +544,7 @@ where { #[cold] fn from(error: E) -> Self { - let backtrace = backtrace_if_absent!(error); + let backtrace = backtrace_if_absent!(&error); Error::from_std(error, backtrace) } } @@ -886,13 +900,21 @@ impl ErrorImpl { .as_ref() .or_else(|| { #[cfg(backtrace)] - return Self::error(this).backtrace(); - #[cfg(all(not(backtrace), feature = "backtrace"))] + return Self::error(this).request_ref::(); + #[cfg(not(backtrace))] return (vtable(this.ptr).object_backtrace)(this); }) .expect("backtrace capture failed") } + #[cfg(backtrace)] + unsafe fn provide<'a>(this: Ref<'a, Self>, demand: &mut Demand<'a>) { + if let Some(backtrace) = &this.deref().backtrace { + demand.provide_ref(backtrace); + } + Self::error(this).provide(demand); + } + #[cold] pub(crate) unsafe fn chain(this: Ref) -> Chain { Chain::new(Self::error(this)) @@ -903,14 +925,14 @@ impl StdError for ErrorImpl where E: StdError, { - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&Backtrace> { - Some(unsafe { ErrorImpl::backtrace(self.erase()) }) - } - fn source(&self) -> Option<&(dyn StdError + 'static)> { unsafe { ErrorImpl::error(self.erase()).source() } } + + #[cfg(backtrace)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + unsafe { ErrorImpl::provide(self.erase(), demand) } + } } impl Debug for ErrorImpl diff --git a/vendor/anyhow/src/kind.rs b/vendor/anyhow/src/kind.rs index 59857057d..f47fe44ba 100644 --- a/vendor/anyhow/src/kind.rs +++ b/vendor/anyhow/src/kind.rs @@ -40,7 +40,7 @@ // The anyhow! macro will set up the call in this form: // // #[allow(unused_imports)] -// use $crate::private::{AdhocKind, TraitKind}; +// use $crate::__private::{AdhocKind, TraitKind}; // let error = $msg; // (&error).anyhow_kind().new(error) @@ -110,7 +110,7 @@ impl BoxedKind for Box {} impl Boxed { #[cold] pub fn new(self, error: Box) -> Error { - let backtrace = backtrace_if_absent!(error); + let backtrace = backtrace_if_absent!(&*error); Error::from_boxed(error, backtrace) } } diff --git a/vendor/anyhow/src/lib.rs b/vendor/anyhow/src/lib.rs index 976668aab..792a4d007 100644 --- a/vendor/anyhow/src/lib.rs +++ b/vendor/anyhow/src/lib.rs @@ -210,8 +210,8 @@ //! will require an explicit `.map_err(Error::msg)` when working with a //! non-Anyhow error type inside a function that returns Anyhow's error type. -#![doc(html_root_url = "https://docs.rs/anyhow/1.0.60")] -#![cfg_attr(backtrace, feature(backtrace))] +#![doc(html_root_url = "https://docs.rs/anyhow/1.0.65")] +#![cfg_attr(backtrace, feature(error_generic_member_access, provide_any))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr(not(feature = "std"), no_std)] #![deny(dead_code, unused_imports, unused_mut)] @@ -634,7 +634,7 @@ pub fn Ok(t: T) -> Result { // Not public API. Referenced by macro-generated code. #[doc(hidden)] -pub mod private { +pub mod __private { use crate::Error; use alloc::fmt; use core::fmt::Arguments; diff --git a/vendor/anyhow/src/macros.rs b/vendor/anyhow/src/macros.rs index 5dc138386..6dd22743b 100644 --- a/vendor/anyhow/src/macros.rs +++ b/vendor/anyhow/src/macros.rs @@ -55,13 +55,13 @@ #[macro_export] macro_rules! bail { ($msg:literal $(,)?) => { - return $crate::private::Err($crate::__anyhow!($msg)) + return $crate::__private::Err($crate::__anyhow!($msg)) }; ($err:expr $(,)?) => { - return $crate::private::Err($crate::__anyhow!($err)) + return $crate::__private::Err($crate::__anyhow!($err)) }; ($fmt:expr, $($arg:tt)*) => { - return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*)) + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)) }; } @@ -120,24 +120,24 @@ macro_rules! bail { macro_rules! ensure { ($cond:expr $(,)?) => { if !$cond { - return $crate::private::Err($crate::Error::msg( - $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`") + return $crate::__private::Err($crate::Error::msg( + $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") )); } }; ($cond:expr, $msg:literal $(,)?) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($msg)); + return $crate::__private::Err($crate::__anyhow!($msg)); } }; ($cond:expr, $err:expr $(,)?) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($err)); + return $crate::__private::Err($crate::__anyhow!($err)); } }; ($cond:expr, $fmt:expr, $($arg:tt)*) => { if !$cond { - return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*)); + return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); } }; } @@ -189,14 +189,14 @@ macro_rules! ensure { #[macro_export] macro_rules! anyhow { ($msg:literal $(,)?) => { - $crate::private::must_use({ - let error = $crate::private::format_err($crate::private::format_args!($msg)); + $crate::__private::must_use({ + let error = $crate::__private::format_err($crate::__private::format_args!($msg)); error }) }; ($err:expr $(,)?) => { - $crate::private::must_use({ - use $crate::private::kind::*; + $crate::__private::must_use({ + use $crate::__private::kind::*; let error = match $err { error => (&error).anyhow_kind().new(error), }; @@ -204,7 +204,7 @@ macro_rules! anyhow { }) }; ($fmt:expr, $($arg:tt)*) => { - $crate::Error::msg($crate::private::format!($fmt, $($arg)*)) + $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) }; } @@ -215,17 +215,17 @@ macro_rules! anyhow { #[macro_export] macro_rules! __anyhow { ($msg:literal $(,)?) => ({ - let error = $crate::private::format_err($crate::private::format_args!($msg)); + let error = $crate::__private::format_err($crate::__private::format_args!($msg)); error }); ($err:expr $(,)?) => ({ - use $crate::private::kind::*; + use $crate::__private::kind::*; let error = match $err { error => (&error).anyhow_kind().new(error), }; error }); ($fmt:expr, $($arg:tt)*) => { - $crate::Error::msg($crate::private::format!($fmt, $($arg)*)) + $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) }; } diff --git a/vendor/anyhow/src/wrapper.rs b/vendor/anyhow/src/wrapper.rs index 3ebe51a88..5f18a5031 100644 --- a/vendor/anyhow/src/wrapper.rs +++ b/vendor/anyhow/src/wrapper.rs @@ -1,6 +1,9 @@ use crate::StdError; use core::fmt::{self, Debug, Display}; +#[cfg(backtrace)] +use std::any::Demand; + #[repr(transparent)] pub struct MessageError(pub M); @@ -67,12 +70,12 @@ impl Display for BoxedError { #[cfg(feature = "std")] impl StdError for BoxedError { - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> { - self.0.backtrace() - } - fn source(&self) -> Option<&(dyn StdError + 'static)> { self.0.source() } + + #[cfg(backtrace)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.0.provide(demand); + } } diff --git a/vendor/anyhow/tests/test_ensure.rs b/vendor/anyhow/tests/test_ensure.rs index 4bb12f9fa..cbcba5798 100644 --- a/vendor/anyhow/tests/test_ensure.rs +++ b/vendor/anyhow/tests/test_ensure.rs @@ -5,9 +5,9 @@ clippy::items_after_statements, clippy::let_and_return, clippy::let_underscore_drop, - clippy::logic_bug, clippy::match_bool, clippy::never_loop, + clippy::overly_complex_bool_expr, clippy::redundant_closure_call, clippy::redundant_pattern_matching, clippy::too_many_lines, diff --git a/vendor/anyhow/tests/ui/must-use.stderr b/vendor/anyhow/tests/ui/must-use.stderr index e9ee24b09..e10bde40f 100644 --- a/vendor/anyhow/tests/ui/must-use.stderr +++ b/vendor/anyhow/tests/ui/must-use.stderr @@ -1,4 +1,4 @@ -error: unused return value of `anyhow::private::must_use` that must be used +error: unused return value of `anyhow::__private::must_use` that must be used --> tests/ui/must-use.rs:8:9 | 8 | anyhow!("it failed"); diff --git a/vendor/anyhow/tests/ui/no-impl.stderr b/vendor/anyhow/tests/ui/no-impl.stderr index 7c5ec503f..074dafe62 100644 --- a/vendor/anyhow/tests/ui/no-impl.stderr +++ b/vendor/anyhow/tests/ui/no-impl.stderr @@ -19,13 +19,13 @@ error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its tr `&Error: Into` which is required by `&Error: anyhow::kind::TraitKind` note: the following traits must be implemented - --> $RUST/core/src/convert/mod.rs - | - | pub trait Into: Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - ::: $RUST/core/src/fmt/mod.rs + --> $RUST/core/src/fmt/mod.rs | | pub trait Display { | ^^^^^^^^^^^^^^^^^ + | + ::: $RUST/core/src/convert/mod.rs + | + | pub trait Into: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/block-buffer-0.7.3/.cargo-checksum.json b/vendor/block-buffer-0.7.3/.cargo-checksum.json deleted file mode 100644 index 779d602b1..000000000 --- a/vendor/block-buffer-0.7.3/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"e4e9e182794c2185438af0c505714df9e051d1d1b17aec7a42265be672b1d027","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"59dd4084e456153bee968153ee45e34c8e853abfb756a53571c5844ccaf18c23"},"package":"c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"} \ No newline at end of file diff --git a/vendor/block-buffer-0.7.3/Cargo.toml b/vendor/block-buffer-0.7.3/Cargo.toml deleted file mode 100644 index 6b10954cb..000000000 --- a/vendor/block-buffer-0.7.3/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "block-buffer" -version = "0.7.3" -authors = ["RustCrypto Developers"] -description = "Fixed size buffer for block processing of data" -documentation = "https://docs.rs/block-buffer" -keywords = ["block", "buffer"] -categories = ["cryptography", "no-std"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/RustCrypto/utils" -[dependencies.block-padding] -version = "0.1" - -[dependencies.byte-tools] -version = "0.3" - -[dependencies.byteorder] -version = "1.1" -default-features = false - -[dependencies.generic-array] -version = "0.12" -[badges.travis-ci] -repository = "RustCrypto/utils" diff --git a/vendor/block-buffer-0.7.3/LICENSE-APACHE b/vendor/block-buffer-0.7.3/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/vendor/block-buffer-0.7.3/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/block-buffer-0.7.3/LICENSE-MIT b/vendor/block-buffer-0.7.3/LICENSE-MIT deleted file mode 100644 index 502cee6e8..000000000 --- a/vendor/block-buffer-0.7.3/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018-2019 The RustCrypto Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/block-buffer-0.7.3/src/lib.rs b/vendor/block-buffer-0.7.3/src/lib.rs deleted file mode 100644 index d3b691655..000000000 --- a/vendor/block-buffer-0.7.3/src/lib.rs +++ /dev/null @@ -1,210 +0,0 @@ -#![no_std] -pub extern crate byteorder; -pub extern crate block_padding; -pub extern crate generic_array; -extern crate byte_tools; - -use byteorder::{ByteOrder, BE}; -use byte_tools::zero; -use block_padding::{Padding, PadError}; -use generic_array::{GenericArray, ArrayLength}; -use core::slice; - -/// Buffer for block processing of data -#[derive(Clone, Default)] -pub struct BlockBuffer> { - buffer: GenericArray, - pos: usize, -} - -#[inline(always)] -unsafe fn cast>(block: &[u8]) -> &GenericArray { - debug_assert_eq!(block.len(), N::to_usize()); - &*(block.as_ptr() as *const GenericArray) -} - - - -impl> BlockBuffer { - /// Process data in `input` in blocks of size `BlockSize` using function `f`. - #[inline] - pub fn input(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&GenericArray) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); - input = r; - self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; - f(&self.buffer); - } - - // While we have at least a full buffer size chunks's worth of data, - // process that data without copying it into the buffer - while input.len() >= self.size() { - let (block, r) = input.split_at(self.size()); - input = r; - f(unsafe { cast(block) }); - } - - // Copy any remaining data into the buffer. - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); - } - - /* - /// Process data in `input` in blocks of size `BlockSize` using function `f`, which accepts - /// slice of blocks. - #[inline] - pub fn input2(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&[GenericArray]) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); - input = r; - self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; - f(slice::from_ref(&self.buffer)); - } - - // While we have at least a full buffer size chunks's worth of data, - // process it data without copying into the buffer - let n_blocks = input.len()/self.size(); - let (left, right) = input.split_at(n_blocks*self.size()); - // safe because we guarantee that `blocks` does not point outside of `input` - let blocks = unsafe { - slice::from_raw_parts( - left.as_ptr() as *const GenericArray, - n_blocks, - ) - }; - f(blocks); - - // Copy remaining data into the buffer. - self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right); - self.pos += right.len(); - } - */ - - /// Variant that doesn't flush the buffer until there's additional - /// data to be processed. Suitable for tweakable block ciphers - /// like Threefish that need to know whether a block is the *last* - /// data block before processing it. - #[inline] - pub fn input_lazy(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&GenericArray) - { - let rem = self.remaining(); - if self.pos != 0 && input.len() > rem { - let (l, r) = input.split_at(rem); - input = r; - self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; - f(&self.buffer); - } - - while input.len() > self.size() { - let (block, r) = input.split_at(self.size()); - input = r; - f(unsafe { cast(block) }); - } - - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); - } - - /// Pad buffer with `prefix` and make sure that internall buffer - /// has at least `up_to` free bytes. All remaining bytes get - /// zeroed-out. - #[inline] - fn digest_pad(&mut self, up_to: usize, f: &mut F) - where F: FnMut(&GenericArray) - { - if self.pos == self.size() { - f(&self.buffer); - self.pos = 0; - } - self.buffer[self.pos] = 0x80; - self.pos += 1; - - zero(&mut self.buffer[self.pos..]); - - if self.remaining() < up_to { - f(&self.buffer); - zero(&mut self.buffer[..self.pos]); - } - } - - /// Pad message with 0x80, zeros and 64-bit message length - /// in a byte order specified by `B` - #[inline] - pub fn len64_padding(&mut self, data_len: u64, mut f: F) - where B: ByteOrder, F: FnMut(&GenericArray) - { - // TODO: replace `F` with `impl Trait` on MSRV bump - self.digest_pad(8, &mut f); - let s = self.size(); - B::write_u64(&mut self.buffer[s-8..], data_len); - f(&self.buffer); - self.pos = 0; - } - - - /// Pad message with 0x80, zeros and 128-bit message length - /// in the big-endian byte order - #[inline] - pub fn len128_padding_be(&mut self, hi: u64, lo: u64, mut f: F) - where F: FnMut(&GenericArray) - { - // TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B` - self.digest_pad(16, &mut f); - let s = self.size(); - BE::write_u64(&mut self.buffer[s-16..s-8], hi); - BE::write_u64(&mut self.buffer[s-8..], lo); - f(&self.buffer); - self.pos = 0; - } - - /// Pad message with a given padding `P` - /// - /// Returns `PadError` if internall buffer is full, which can only happen if - /// `input_lazy` was used. - #[inline] - pub fn pad_with(&mut self) - -> Result<&mut GenericArray, PadError> - { - P::pad_block(&mut self.buffer[..], self.pos)?; - self.pos = 0; - Ok(&mut self.buffer) - } - - /// Return size of the internall buffer in bytes - #[inline] - pub fn size(&self) -> usize { - BlockSize::to_usize() - } - - /// Return current cursor position - #[inline] - pub fn position(&self) -> usize { - self.pos - } - - /// Return number of remaining bytes in the internall buffer - #[inline] - pub fn remaining(&self) -> usize { - self.size() - self.pos - } - - /// Reset buffer by setting cursor position to zero - #[inline] - pub fn reset(&mut self) { - self.pos = 0 - } -} diff --git a/vendor/block-padding/.cargo-checksum.json b/vendor/block-padding/.cargo-checksum.json deleted file mode 100644 index e80396463..000000000 --- a/vendor/block-padding/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"f895c4794f1c00f5f01376dae2b66870d939a01b9a366ee4d177b6b7ad99bd4a","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"962c90d43c7c2761b3c96fab2713ae357a7a8d2d048e37ce4f3354941ad41b97"},"package":"fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"} \ No newline at end of file diff --git a/vendor/block-padding/Cargo.toml b/vendor/block-padding/Cargo.toml deleted file mode 100644 index 1b1c849a8..000000000 --- a/vendor/block-padding/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "block-padding" -version = "0.1.5" -authors = ["RustCrypto Developers"] -description = "Padding and unpadding of messages divided into blocks." -documentation = "https://docs.rs/block-padding" -keywords = ["padding", "pkcs7", "ansix923", "iso7816"] -categories = ["cryptography", "no-std"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/RustCrypto/utils" -[dependencies.byte-tools] -version = "0.3" -[badges.travis-ci] -repository = "RustCrypto/utils" diff --git a/vendor/block-padding/LICENSE-APACHE b/vendor/block-padding/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/vendor/block-padding/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/block-padding/LICENSE-MIT b/vendor/block-padding/LICENSE-MIT deleted file mode 100644 index 502cee6e8..000000000 --- a/vendor/block-padding/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018-2019 The RustCrypto Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/block-padding/src/lib.rs b/vendor/block-padding/src/lib.rs deleted file mode 100644 index 5c4c8c3b6..000000000 --- a/vendor/block-padding/src/lib.rs +++ /dev/null @@ -1,323 +0,0 @@ -//! Padding and unpadding of messages divided into blocks. -//! -//! This crate provides `Padding` trait which provides padding and unpadding -//! operations. Additionally several common padding schemes are available out -//! of the box. -#![no_std] -#![doc(html_logo_url = - "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] -extern crate byte_tools; - -use byte_tools::{zero, set}; - -/// Error for indicating failed padding operation -#[derive(Clone, Copy, Debug)] -pub struct PadError; - -/// Error for indicating failed unpadding operation -#[derive(Clone, Copy, Debug)] -pub struct UnpadError; - -/// Trait for padding messages divided into blocks -pub trait Padding { - /// Pads `block` filled with data up to `pos`. - /// - /// `pos` should be inside of the block and block must not be full, i.e. - /// `pos < block.len()` must be true. Otherwise method will return - /// `PadError`. Some potentially irreversible padding schemes can allow - /// padding of the full block, in this case aforementioned condition is - /// relaxed to `pos <= block.len()`. - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError>; - - /// Pads message with length `pos` in the provided buffer. - /// - /// `&buf[..pos]` is perceived as the message, the buffer must contain - /// enough leftover space for padding: `block_size - (pos % block_size)` - /// extra bytes must be available. Otherwise method will return - /// `PadError`. - fn pad(buf: &mut [u8], pos: usize, block_size: usize) - -> Result<&mut [u8], PadError> - { - let bs = block_size * (pos / block_size); - if buf.len() < bs || buf.len() - bs < block_size { Err(PadError)? } - Self::pad_block(&mut buf[bs..bs+block_size], pos - bs)?; - Ok(&mut buf[..bs+block_size]) - } - - /// Unpad given `data` by truncating it according to the used padding. - /// In case of the malformed padding will return `UnpadError` - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError>; -} - -/// Pad block with zeros. -/// -/// ``` -/// use block_padding::{ZeroPadding, Padding}; -/// -/// let msg = b"test"; -/// let n = msg.len(); -/// let mut buffer = [0xff; 16]; -/// buffer[..n].copy_from_slice(msg); -/// let padded_msg = ZeroPadding::pad(&mut buffer, n, 8).unwrap(); -/// assert_eq!(padded_msg, b"test\x00\x00\x00\x00"); -/// assert_eq!(ZeroPadding::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{ZeroPadding, Padding}; -/// # let msg = b"test"; -/// # let n = msg.len(); -/// # let mut buffer = [0xff; 16]; -/// # buffer[..n].copy_from_slice(msg); -/// let padded_msg = ZeroPadding::pad(&mut buffer, n, 2).unwrap(); -/// assert_eq!(padded_msg, b"test"); -/// assert_eq!(ZeroPadding::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// -/// Note that zero padding may not be reversible if the original message ends -/// with one or more zero bytes. -pub enum ZeroPadding{} - -impl Padding for ZeroPadding { - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { - if pos > block.len() { Err(PadError)? } - zero(&mut block[pos..]); - Ok(()) - } - - fn pad(buf: &mut [u8], pos: usize, block_size: usize) - -> Result<&mut [u8], PadError> - { - if pos % block_size == 0 { - Ok(&mut buf[..pos]) - } else { - let bs = block_size * (pos / block_size); - let be = bs + block_size; - if buf.len() < be { Err(PadError)? } - Self::pad_block(&mut buf[bs..be], pos - bs)?; - Ok(&mut buf[..be]) - } - } - - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> { - let mut n = data.len() - 1; - while n != 0 { - if data[n] != 0 { - break; - } - n -= 1; - } - Ok(&data[..n+1]) - } -} - -/// Pad block with bytes with value equal to the number of bytes added. -/// -/// PKCS#7 described in the [RFC 5652](https://tools.ietf.org/html/rfc5652#section-6.3). -/// -/// ``` -/// use block_padding::{Pkcs7, Padding}; -/// -/// let msg = b"test"; -/// let n = msg.len(); -/// let mut buffer = [0xff; 8]; -/// buffer[..n].copy_from_slice(msg); -/// let padded_msg = Pkcs7::pad(&mut buffer, n, 8).unwrap(); -/// assert_eq!(padded_msg, b"test\x04\x04\x04\x04"); -/// assert_eq!(Pkcs7::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{Pkcs7, Padding}; -/// # let msg = b"test"; -/// # let n = msg.len(); -/// # let mut buffer = [0xff; 8]; -/// # buffer[..n].copy_from_slice(msg); -/// let padded_msg = Pkcs7::pad(&mut buffer, n, 2).unwrap(); -/// assert_eq!(padded_msg, b"test\x02\x02"); -/// assert_eq!(Pkcs7::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{Pkcs7, Padding}; -/// let mut buffer = [0xff; 5]; -/// assert!(Pkcs7::pad(&mut buffer, 4, 2).is_err()); -/// ``` -/// ``` -/// # use block_padding::{Pkcs7, Padding}; -/// # let buffer = [0xff; 16]; -/// assert!(Pkcs7::unpad(&buffer).is_err()); -/// ``` -/// -/// In addition to conditions stated in the `Padding` trait documentation, -/// `pad_block` will return `PadError` if `block.len() > 255`, and in case of -/// `pad` if `block_size > 255`. -pub enum Pkcs7{} - -impl Padding for Pkcs7 { - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { - if block.len() > 255 { Err(PadError)? } - if pos >= block.len() { Err(PadError)? } - let n = block.len() - pos; - set(&mut block[pos..], n as u8); - Ok(()) - } - - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> { - if data.is_empty() { Err(UnpadError)? } - let l = data.len(); - let n = data[l-1]; - if n == 0 || n as usize > l { Err(UnpadError)? } - for v in &data[l-n as usize..l-1] { - if *v != n { Err(UnpadError)? } - } - Ok(&data[..l - n as usize]) - } -} - -/// Pad block with zeros except the last byte which will be set to the number -/// bytes. -/// -/// ``` -/// use block_padding::{AnsiX923, Padding}; -/// -/// let msg = b"test"; -/// let n = msg.len(); -/// let mut buffer = [0xff; 16]; -/// buffer[..n].copy_from_slice(msg); -/// let padded_msg = AnsiX923::pad(&mut buffer, n, 8).unwrap(); -/// assert_eq!(padded_msg, b"test\x00\x00\x00\x04"); -/// assert_eq!(AnsiX923::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{AnsiX923, Padding}; -/// # let msg = b"test"; -/// # let n = msg.len(); -/// # let mut buffer = [0xff; 16]; -/// # buffer[..n].copy_from_slice(msg); -/// let padded_msg = AnsiX923::pad(&mut buffer, n, 2).unwrap(); -/// assert_eq!(padded_msg, b"test\x00\x02"); -/// assert_eq!(AnsiX923::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{AnsiX923, Padding}; -/// # let buffer = [0xff; 16]; -/// assert!(AnsiX923::unpad(&buffer).is_err()); -/// ``` -/// -/// In addition to conditions stated in the `Padding` trait documentation, -/// `pad_block` will return `PadError` if `block.len() > 255`, and in case of -/// `pad` if `block_size > 255`. -pub enum AnsiX923{} - -impl Padding for AnsiX923 { - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError>{ - if block.len() > 255 { Err(PadError)? } - if pos >= block.len() { Err(PadError)? } - let bs = block.len(); - zero(&mut block[pos..bs-1]); - block[bs-1] = (bs - pos) as u8; - Ok(()) - } - - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> { - if data.is_empty() { Err(UnpadError)? } - let l = data.len(); - let n = data[l-1] as usize; - if n == 0 || n > l { - return Err(UnpadError) - } - for v in &data[l-n..l-1] { - if *v != 0 { Err(UnpadError)? } - } - Ok(&data[..l-n]) - } -} - -/// Pad block with byte sequence `\x80 00...00 00`. -/// -/// ``` -/// use block_padding::{Iso7816, Padding}; -/// -/// let msg = b"test"; -/// let n = msg.len(); -/// let mut buffer = [0xff; 16]; -/// buffer[..n].copy_from_slice(msg); -/// let padded_msg = Iso7816::pad(&mut buffer, n, 8).unwrap(); -/// assert_eq!(padded_msg, b"test\x80\x00\x00\x00"); -/// assert_eq!(Iso7816::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{Iso7816, Padding}; -/// # let msg = b"test"; -/// # let n = msg.len(); -/// # let mut buffer = [0xff; 16]; -/// # buffer[..n].copy_from_slice(msg); -/// let padded_msg = Iso7816::pad(&mut buffer, n, 2).unwrap(); -/// assert_eq!(padded_msg, b"test\x80\x00"); -/// assert_eq!(Iso7816::unpad(&padded_msg).unwrap(), msg); -/// ``` -pub enum Iso7816{} - -impl Padding for Iso7816 { - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { - if pos >= block.len() { Err(PadError)? } - block[pos] = 0x80; - zero(&mut block[pos+1..]); - Ok(()) - } - - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> { - if data.is_empty() { Err(UnpadError)? } - let mut n = data.len() - 1; - while n != 0 { - if data[n] != 0 { break; } - n -= 1; - } - if data[n] != 0x80 { Err(UnpadError)? } - Ok(&data[..n]) - } -} - -/// Don't pad the data. Useful for key wrapping. Padding will fail if the data cannot be -/// fitted into blocks without padding. -/// -/// ``` -/// use block_padding::{NoPadding, Padding}; -/// -/// let msg = b"test"; -/// let n = msg.len(); -/// let mut buffer = [0xff; 16]; -/// buffer[..n].copy_from_slice(msg); -/// let padded_msg = NoPadding::pad(&mut buffer, n, 4).unwrap(); -/// assert_eq!(padded_msg, b"test"); -/// assert_eq!(NoPadding::unpad(&padded_msg).unwrap(), msg); -/// ``` -/// ``` -/// # use block_padding::{NoPadding, Padding}; -/// # let msg = b"test"; -/// # let n = msg.len(); -/// # let mut buffer = [0xff; 16]; -/// # buffer[..n].copy_from_slice(msg); -/// let padded_msg = NoPadding::pad(&mut buffer, n, 2).unwrap(); -/// assert_eq!(padded_msg, b"test"); -/// assert_eq!(NoPadding::unpad(&padded_msg).unwrap(), msg); -/// ``` -pub enum NoPadding {} - -impl Padding for NoPadding { - fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { - if pos % block.len() != 0 { - Err(PadError)? - } - Ok(()) - } - - fn pad(buf: &mut [u8], pos: usize, block_size: usize) -> Result<&mut [u8], PadError> { - if pos % block_size != 0 { - Err(PadError)? - } - Ok(&mut buf[..pos]) - } - - fn unpad(data: &[u8]) -> Result<&[u8], UnpadError> { - Ok(data) - } -} diff --git a/vendor/byte-tools/.cargo-checksum.json b/vendor/byte-tools/.cargo-checksum.json deleted file mode 100644 index 36f28b52e..000000000 --- a/vendor/byte-tools/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"0542f7bd3605206297b6708b28bfff87a2ef7fa65ccab1474ddb53072600d7e1","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"c8fb45d44cae0b1094bf8cef5059827b28b490eb14a3865fa536b61241c2c8c4"},"package":"e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"} \ No newline at end of file diff --git a/vendor/byte-tools/Cargo.toml b/vendor/byte-tools/Cargo.toml deleted file mode 100644 index 74c6b9a0e..000000000 --- a/vendor/byte-tools/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "byte-tools" -version = "0.3.1" -authors = ["RustCrypto Developers"] -description = "Bytes related utility functions" -documentation = "https://docs.rs/byte-tools" -keywords = ["bytes"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/RustCrypto/utils" diff --git a/vendor/byte-tools/LICENSE-APACHE b/vendor/byte-tools/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/vendor/byte-tools/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/byte-tools/LICENSE-MIT b/vendor/byte-tools/LICENSE-MIT deleted file mode 100644 index 502cee6e8..000000000 --- a/vendor/byte-tools/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018-2019 The RustCrypto Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/byte-tools/src/lib.rs b/vendor/byte-tools/src/lib.rs deleted file mode 100644 index b4a450f9f..000000000 --- a/vendor/byte-tools/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -use core::ptr; - -/// Copy bytes from `src` to `dst` -/// -/// Panics if `src.len() < dst.len()` -#[inline(always)] -pub fn copy(src: &[u8], dst: &mut [u8]) { - assert!(dst.len() >= src.len()); - unsafe { - ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len()); - } -} - -/// Zero all bytes in `dst` -#[inline(always)] -pub fn zero(dst: &mut [u8]) { - unsafe { - ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len()); - } -} - -/// Sets all bytes in `dst` equal to `value` -#[inline(always)] -pub fn set(dst: &mut [u8], value: u8) { - unsafe { - ptr::write_bytes(dst.as_mut_ptr(), value, dst.len()); - } -} diff --git a/vendor/byteorder/.cargo-checksum.json b/vendor/byteorder/.cargo-checksum.json deleted file mode 100644 index 434cc1a16..000000000 --- a/vendor/byteorder/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"3a745d94ee9dce0d9dc638c02078cd5001d3d9d12d58b4f220c0101e32cfc16a","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"8585455e5a0e638cf5d489a21e286e93680f835cb8a13595918b5eb7c8c7f212","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"9d57556868344534de2489317e3c6bb611348ecd44438dcb982bd8d2a55a5a1b","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"a80bf3cd446c9b6c0cca3865c4de047bdf4644b74cdf696822f8ff87adfa1fca","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/io.rs":"9612530634d0e7ce9887a23836b58c0d972c1f45b05d9ada8355961567075627","src/lib.rs":"813ce6a8beafee3fd4e63325d783108aa02e8c57e412bc97580191d84082fbc9"},"package":"14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"} \ No newline at end of file diff --git a/vendor/byteorder/CHANGELOG.md b/vendor/byteorder/CHANGELOG.md deleted file mode 100644 index 6b51eb076..000000000 --- a/vendor/byteorder/CHANGELOG.md +++ /dev/null @@ -1,139 +0,0 @@ -1.3.4 -===== -This patch release squashes deprecation warnings for the `try!` macro, in -accordance with byteorder's minimum supported Rust version (currently at Rust -1.12.0). - - -1.3.3 -===== -This patch release adds `ByteOrder::write_i8_into()` as a simple, safe interface -for ordinarily unsafe or tedious code. - - -1.3.2 -===== -This patch release adds `ReadBytesExt::read_i8_into()` as a simple, safe interface -for ordinarily unsafe or tedious code. - - -1.3.1 -===== -This minor release performs mostly small internal changes. Going forward, these -are not going to be incorporated into the changelog. - - -1.3.0 -===== -This new minor release now enables `i128` support automatically on Rust -compilers that support 128-bit integers. The `i128` feature is now a no-op, but -continues to exist for backward compatibility purposes. The crate continues to -maintain compatibility with Rust 1.12.0. - -This release also deprecates the `ByteOrder` trait methods -`read_f32_into_unchecked` and `read_f64_into_unchecked` in favor of -`read_f32_into` and `read_f64_into`. This was an oversight from the 1.2 release -where the corresponding methods on `ReadBytesExt` were deprecated. - -`quickcheck` and `rand` were bumped to `0.8` and `0.6`, respectively. - -A few small documentation related bugs have been fixed. - - -1.2.7 -===== -This patch release excludes some CI files from the crate release and updates -the license field to use `OR` instead of `/`. - - -1.2.6 -===== -This patch release fixes some test compilation errors introduced by an -over-eager release of 1.2.5. - - -1.2.5 -===== -This patch release fixes some typos in the docs, adds doc tests to methods on -`WriteByteExt` and bumps the quickcheck dependency to `0.7`. - - -1.2.4 -===== -This patch release adds support for 48-bit integers by adding the following -methods to the `ByteOrder` trait: `read_u48`, `read_i48`, `write_u48` and -`write_i48`. Corresponding methods have been added to the `ReadBytesExt` and -`WriteBytesExt` traits as well. - - -1.2.3 -===== -This patch release removes the use of `feature(i128_type)` from byteorder, -since it has been stabilized. We leave byteorder's `i128` feature in place -in order to continue supporting compilation on older versions of Rust. - - -1.2.2 -===== -This patch release only consists of internal improvements and refactorings. -Notably, this removes all uses of `transmute` and instead uses pointer casts. - - -1.2.1 -===== -This patch release removes more unnecessary uses of `unsafe` that -were overlooked in the prior `1.2.0` release. In particular, the -`ReadBytesExt::read_{f32,f64}_into_checked` methods have been deprecated and -replaced by more appropriately named `read_{f32,f64}_into` methods. - - -1.2.0 -===== -The most prominent change in this release of `byteorder` is the removal of -unnecessary signaling NaN masking, and in turn, the `unsafe` annotations -associated with methods that didn't do masking. See -[#103](https://github.com/BurntSushi/byteorder/issues/103) -for more details. - -* [BUG #102](https://github.com/BurntSushi/byteorder/issues/102): - Fix big endian tests. -* [BUG #103](https://github.com/BurntSushi/byteorder/issues/103): - Remove sNaN masking. - - -1.1.0 -===== -This release of `byteorder` features a number of fixes and improvements, mostly -as a result of the -[Litz Blitz evaluation](https://public.etherpad-mozilla.org/p/rust-crate-eval-byteorder). - -Feature enhancements: - -* [FEATURE #63](https://github.com/BurntSushi/byteorder/issues/63): - Add methods for reading/writing slices of numbers for a specific - endianness. -* [FEATURE #65](https://github.com/BurntSushi/byteorder/issues/65): - Add support for `u128`/`i128` types. (Behind the nightly only `i128` - feature.) -* [FEATURE #72](https://github.com/BurntSushi/byteorder/issues/72): - Add "panics" and "errors" sections for each relevant public API item. -* [FEATURE #74](https://github.com/BurntSushi/byteorder/issues/74): - Add CI badges to Cargo.toml. -* [FEATURE #75](https://github.com/BurntSushi/byteorder/issues/75): - Add more examples to public API items. -* Add 24-bit read/write methods. -* Add `BE` and `LE` type aliases for `BigEndian` and `LittleEndian`, - respectively. - -Bug fixes: - -* [BUG #68](https://github.com/BurntSushi/byteorder/issues/68): - Panic in {BigEndian,LittleEndian}::default. -* [BUG #69](https://github.com/BurntSushi/byteorder/issues/69): - Seal the `ByteOrder` trait to prevent out-of-crate implementations. -* [BUG #71](https://github.com/BurntSushi/byteorder/issues/71): - Guarantee that the results of `read_f32`/`read_f64` are always defined. -* [BUG #73](https://github.com/BurntSushi/byteorder/issues/73): - Add crates.io categories. -* [BUG #77](https://github.com/BurntSushi/byteorder/issues/77): - Add `html_root` doc attribute. diff --git a/vendor/byteorder/COPYING b/vendor/byteorder/COPYING deleted file mode 100644 index bb9c20a09..000000000 --- a/vendor/byteorder/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -This project is dual-licensed under the Unlicense and MIT licenses. - -You may use this code under the terms of either license. diff --git a/vendor/byteorder/Cargo.toml b/vendor/byteorder/Cargo.toml deleted file mode 100644 index c71f90ba9..000000000 --- a/vendor/byteorder/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "byteorder" -version = "1.4.3" -authors = ["Andrew Gallant "] -exclude = ["/ci/*"] -description = "Library for reading/writing numbers in big-endian and little-endian." -homepage = "https://github.com/BurntSushi/byteorder" -documentation = "https://docs.rs/byteorder" -readme = "README.md" -keywords = ["byte", "endian", "big-endian", "little-endian", "binary"] -categories = ["encoding", "parsing", "no-std"] -license = "Unlicense OR MIT" -repository = "https://github.com/BurntSushi/byteorder" -[profile.bench] -opt-level = 3 - -[lib] -name = "byteorder" -bench = false -[dev-dependencies.quickcheck] -version = "0.9.2" -default-features = false - -[dev-dependencies.rand] -version = "0.7" - -[features] -default = ["std"] -i128 = [] -std = [] diff --git a/vendor/byteorder/LICENSE-MIT b/vendor/byteorder/LICENSE-MIT deleted file mode 100644 index 3b0a5dc09..000000000 --- a/vendor/byteorder/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/byteorder/README.md b/vendor/byteorder/README.md deleted file mode 100644 index d8461c58f..000000000 --- a/vendor/byteorder/README.md +++ /dev/null @@ -1,63 +0,0 @@ -byteorder -========= -This crate provides convenience methods for encoding and decoding -numbers in either big-endian or little-endian order. - -[![Build status](https://github.com/BurntSushi/byteorder/workflows/ci/badge.svg)](https://github.com/BurntSushi/byteorder/actions) -[![](https://meritbadge.herokuapp.com/byteorder)](https://crates.io/crates/byteorder) - -Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/). - - -### Documentation - -https://docs.rs/byteorder - - -### Installation - -This crate works with Cargo and is on -[crates.io](https://crates.io/crates/byteorder). Add it to your `Cargo.toml` -like so: - -```toml -[dependencies] -byteorder = "1" -``` - -If you want to augment existing `Read` and `Write` traits, then import the -extension methods like so: - -```rust -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian}; -``` - -For example: - -```rust -use std::io::Cursor; -use byteorder::{BigEndian, ReadBytesExt}; - -let mut rdr = Cursor::new(vec![2, 5, 3, 0]); -// Note that we use type parameters to indicate which kind of byte order -// we want! -assert_eq!(517, rdr.read_u16::().unwrap()); -assert_eq!(768, rdr.read_u16::().unwrap()); -``` - -### `no_std` crates - -This crate has a feature, `std`, that is enabled by default. To use this crate -in a `no_std` context, add the following to your `Cargo.toml`: - -```toml -[dependencies] -byteorder = { version = "1", default-features = false } -``` - - -### Alternatives - -Note that as of Rust 1.32, the standard numeric types provide built-in methods -like `to_le_bytes` and `from_le_bytes`, which support some of the same use -cases. diff --git a/vendor/byteorder/UNLICENSE b/vendor/byteorder/UNLICENSE deleted file mode 100644 index 68a49daad..000000000 --- a/vendor/byteorder/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/vendor/byteorder/benches/bench.rs b/vendor/byteorder/benches/bench.rs deleted file mode 100644 index bb00422f7..000000000 --- a/vendor/byteorder/benches/bench.rs +++ /dev/null @@ -1,324 +0,0 @@ -#![feature(test)] - -extern crate test; - -macro_rules! bench_num { - ($name:ident, $read:ident, $bytes:expr, $data:expr) => { - mod $name { - use byteorder::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - use test::black_box as bb; - use test::Bencher; - - const NITER: usize = 100_000; - - #[bench] - fn read_big_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(BigEndian::$read(&buf, $bytes)); - } - }); - } - - #[bench] - fn read_little_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(LittleEndian::$read(&buf, $bytes)); - } - }); - } - - #[bench] - fn read_native_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(NativeEndian::$read(&buf, $bytes)); - } - }); - } - } - }; - ($ty:ident, $max:ident, - $read:ident, $write:ident, $size:expr, $data:expr) => { - mod $ty { - use byteorder::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - use std::$ty; - use test::black_box as bb; - use test::Bencher; - - const NITER: usize = 100_000; - - #[bench] - fn read_big_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(BigEndian::$read(&buf)); - } - }); - } - - #[bench] - fn read_little_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(LittleEndian::$read(&buf)); - } - }); - } - - #[bench] - fn read_native_endian(b: &mut Bencher) { - let buf = $data; - b.iter(|| { - for _ in 0..NITER { - bb(NativeEndian::$read(&buf)); - } - }); - } - - #[bench] - fn write_big_endian(b: &mut Bencher) { - let mut buf = $data; - let n = $ty::$max; - b.iter(|| { - for _ in 0..NITER { - bb(BigEndian::$write(&mut buf, n)); - } - }); - } - - #[bench] - fn write_little_endian(b: &mut Bencher) { - let mut buf = $data; - let n = $ty::$max; - b.iter(|| { - for _ in 0..NITER { - bb(LittleEndian::$write(&mut buf, n)); - } - }); - } - - #[bench] - fn write_native_endian(b: &mut Bencher) { - let mut buf = $data; - let n = $ty::$max; - b.iter(|| { - for _ in 0..NITER { - bb(NativeEndian::$write(&mut buf, n)); - } - }); - } - } - }; -} - -bench_num!(u16, MAX, read_u16, write_u16, 2, [1, 2]); -bench_num!(i16, MAX, read_i16, write_i16, 2, [1, 2]); -bench_num!(u32, MAX, read_u32, write_u32, 4, [1, 2, 3, 4]); -bench_num!(i32, MAX, read_i32, write_i32, 4, [1, 2, 3, 4]); -bench_num!(u64, MAX, read_u64, write_u64, 8, [1, 2, 3, 4, 5, 6, 7, 8]); -bench_num!(i64, MAX, read_i64, write_i64, 8, [1, 2, 3, 4, 5, 6, 7, 8]); -bench_num!(f32, MAX, read_f32, write_f32, 4, [1, 2, 3, 4]); -bench_num!(f64, MAX, read_f64, write_f64, 8, [1, 2, 3, 4, 5, 6, 7, 8]); - -bench_num!(uint_1, read_uint, 1, [1]); -bench_num!(uint_2, read_uint, 2, [1, 2]); -bench_num!(uint_3, read_uint, 3, [1, 2, 3]); -bench_num!(uint_4, read_uint, 4, [1, 2, 3, 4]); -bench_num!(uint_5, read_uint, 5, [1, 2, 3, 4, 5]); -bench_num!(uint_6, read_uint, 6, [1, 2, 3, 4, 5, 6]); -bench_num!(uint_7, read_uint, 7, [1, 2, 3, 4, 5, 6, 7]); -bench_num!(uint_8, read_uint, 8, [1, 2, 3, 4, 5, 6, 7, 8]); - -bench_num!(int_1, read_int, 1, [1]); -bench_num!(int_2, read_int, 2, [1, 2]); -bench_num!(int_3, read_int, 3, [1, 2, 3]); -bench_num!(int_4, read_int, 4, [1, 2, 3, 4]); -bench_num!(int_5, read_int, 5, [1, 2, 3, 4, 5]); -bench_num!(int_6, read_int, 6, [1, 2, 3, 4, 5, 6]); -bench_num!(int_7, read_int, 7, [1, 2, 3, 4, 5, 6, 7]); -bench_num!(int_8, read_int, 8, [1, 2, 3, 4, 5, 6, 7, 8]); - -bench_num!( - u128, - MAX, - read_u128, - write_u128, - 16, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -); -bench_num!( - i128, - MAX, - read_i128, - write_i128, - 16, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -); - -bench_num!(uint128_1, read_uint128, 1, [1]); -bench_num!(uint128_2, read_uint128, 2, [1, 2]); -bench_num!(uint128_3, read_uint128, 3, [1, 2, 3]); -bench_num!(uint128_4, read_uint128, 4, [1, 2, 3, 4]); -bench_num!(uint128_5, read_uint128, 5, [1, 2, 3, 4, 5]); -bench_num!(uint128_6, read_uint128, 6, [1, 2, 3, 4, 5, 6]); -bench_num!(uint128_7, read_uint128, 7, [1, 2, 3, 4, 5, 6, 7]); -bench_num!(uint128_8, read_uint128, 8, [1, 2, 3, 4, 5, 6, 7, 8]); -bench_num!(uint128_9, read_uint128, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]); -bench_num!(uint128_10, read_uint128, 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); -bench_num!(uint128_11, read_uint128, 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); -bench_num!( - uint128_12, - read_uint128, - 12, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] -); -bench_num!( - uint128_13, - read_uint128, - 13, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] -); -bench_num!( - uint128_14, - read_uint128, - 14, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] -); -bench_num!( - uint128_15, - read_uint128, - 15, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -); -bench_num!( - uint128_16, - read_uint128, - 16, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -); - -bench_num!(int128_1, read_int128, 1, [1]); -bench_num!(int128_2, read_int128, 2, [1, 2]); -bench_num!(int128_3, read_int128, 3, [1, 2, 3]); -bench_num!(int128_4, read_int128, 4, [1, 2, 3, 4]); -bench_num!(int128_5, read_int128, 5, [1, 2, 3, 4, 5]); -bench_num!(int128_6, read_int128, 6, [1, 2, 3, 4, 5, 6]); -bench_num!(int128_7, read_int128, 7, [1, 2, 3, 4, 5, 6, 7]); -bench_num!(int128_8, read_int128, 8, [1, 2, 3, 4, 5, 6, 7, 8]); -bench_num!(int128_9, read_int128, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]); -bench_num!(int128_10, read_int128, 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); -bench_num!(int128_11, read_int128, 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); -bench_num!( - int128_12, - read_int128, - 12, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] -); -bench_num!( - int128_13, - read_int128, - 13, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] -); -bench_num!( - int128_14, - read_int128, - 14, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] -); -bench_num!( - int128_15, - read_int128, - 15, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -); -bench_num!( - int128_16, - read_int128, - 16, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -); - -macro_rules! bench_slice { - ($name:ident, $numty:ty, $read:ident, $write:ident) => { - mod $name { - use std::mem::size_of; - - use byteorder::{BigEndian, ByteOrder, LittleEndian}; - use rand::distributions; - use rand::{self, Rng}; - use test::Bencher; - - #[bench] - fn read_big_endian(b: &mut Bencher) { - let mut numbers: Vec<$numty> = rand::thread_rng() - .sample_iter(&distributions::Standard) - .take(100000) - .collect(); - let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; - BigEndian::$write(&numbers, &mut bytes); - - b.bytes = bytes.len() as u64; - b.iter(|| { - BigEndian::$read(&bytes, &mut numbers); - }); - } - - #[bench] - fn read_little_endian(b: &mut Bencher) { - let mut numbers: Vec<$numty> = rand::thread_rng() - .sample_iter(&distributions::Standard) - .take(100000) - .collect(); - let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; - LittleEndian::$write(&numbers, &mut bytes); - - b.bytes = bytes.len() as u64; - b.iter(|| { - LittleEndian::$read(&bytes, &mut numbers); - }); - } - - #[bench] - fn write_big_endian(b: &mut Bencher) { - let numbers: Vec<$numty> = rand::thread_rng() - .sample_iter(&distributions::Standard) - .take(100000) - .collect(); - let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; - - b.bytes = bytes.len() as u64; - b.iter(|| { - BigEndian::$write(&numbers, &mut bytes); - }); - } - - #[bench] - fn write_little_endian(b: &mut Bencher) { - let numbers: Vec<$numty> = rand::thread_rng() - .sample_iter(&distributions::Standard) - .take(100000) - .collect(); - let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; - - b.bytes = bytes.len() as u64; - b.iter(|| { - LittleEndian::$write(&numbers, &mut bytes); - }); - } - } - }; -} - -bench_slice!(slice_u64, u64, read_u64_into, write_u64_into); diff --git a/vendor/byteorder/rustfmt.toml b/vendor/byteorder/rustfmt.toml deleted file mode 100644 index aa37a218b..000000000 --- a/vendor/byteorder/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -max_width = 79 -use_small_heuristics = "max" diff --git a/vendor/byteorder/src/io.rs b/vendor/byteorder/src/io.rs deleted file mode 100644 index dfad2ca39..000000000 --- a/vendor/byteorder/src/io.rs +++ /dev/null @@ -1,1592 +0,0 @@ -use std::{ - io::{self, Result}, - slice, -}; - -use crate::ByteOrder; - -/// Extends [`Read`] with methods for reading numbers. (For `std::io`.) -/// -/// Most of the methods defined here have an unconstrained type parameter that -/// must be explicitly instantiated. Typically, it is instantiated with either -/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate. -/// -/// # Examples -/// -/// Read unsigned 16 bit big-endian integers from a [`Read`]: -/// -/// ```rust -/// use std::io::Cursor; -/// use byteorder::{BigEndian, ReadBytesExt}; -/// -/// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); -/// assert_eq!(517, rdr.read_u16::().unwrap()); -/// assert_eq!(768, rdr.read_u16::().unwrap()); -/// ``` -/// -/// [`BigEndian`]: enum.BigEndian.html -/// [`LittleEndian`]: enum.LittleEndian.html -/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html -pub trait ReadBytesExt: io::Read { - /// Reads an unsigned 8 bit integer from the underlying reader. - /// - /// Note that since this reads a single byte, no byte order conversions - /// are used. It is included for completeness. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read unsigned 8 bit integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::ReadBytesExt; - /// - /// let mut rdr = Cursor::new(vec![2, 5]); - /// assert_eq!(2, rdr.read_u8().unwrap()); - /// assert_eq!(5, rdr.read_u8().unwrap()); - /// ``` - #[inline] - fn read_u8(&mut self) -> Result { - let mut buf = [0; 1]; - self.read_exact(&mut buf)?; - Ok(buf[0]) - } - - /// Reads a signed 8 bit integer from the underlying reader. - /// - /// Note that since this reads a single byte, no byte order conversions - /// are used. It is included for completeness. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read signed 8 bit integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::ReadBytesExt; - /// - /// let mut rdr = Cursor::new(vec![0x02, 0xfb]); - /// assert_eq!(2, rdr.read_i8().unwrap()); - /// assert_eq!(-5, rdr.read_i8().unwrap()); - /// ``` - #[inline] - fn read_i8(&mut self) -> Result { - let mut buf = [0; 1]; - self.read_exact(&mut buf)?; - Ok(buf[0] as i8) - } - - /// Reads an unsigned 16 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read unsigned 16 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); - /// assert_eq!(517, rdr.read_u16::().unwrap()); - /// assert_eq!(768, rdr.read_u16::().unwrap()); - /// ``` - #[inline] - fn read_u16(&mut self) -> Result { - let mut buf = [0; 2]; - self.read_exact(&mut buf)?; - Ok(T::read_u16(&buf)) - } - - /// Reads a signed 16 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read signed 16 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x00, 0xc1, 0xff, 0x7c]); - /// assert_eq!(193, rdr.read_i16::().unwrap()); - /// assert_eq!(-132, rdr.read_i16::().unwrap()); - /// ``` - #[inline] - fn read_i16(&mut self) -> Result { - let mut buf = [0; 2]; - self.read_exact(&mut buf)?; - Ok(T::read_i16(&buf)) - } - - /// Reads an unsigned 24 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read unsigned 24 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x00, 0x01, 0x0b]); - /// assert_eq!(267, rdr.read_u24::().unwrap()); - /// ``` - #[inline] - fn read_u24(&mut self) -> Result { - let mut buf = [0; 3]; - self.read_exact(&mut buf)?; - Ok(T::read_u24(&buf)) - } - - /// Reads a signed 24 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read signed 24 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0xff, 0x7a, 0x33]); - /// assert_eq!(-34253, rdr.read_i24::().unwrap()); - /// ``` - #[inline] - fn read_i24(&mut self) -> Result { - let mut buf = [0; 3]; - self.read_exact(&mut buf)?; - Ok(T::read_i24(&buf)) - } - - /// Reads an unsigned 32 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read unsigned 32 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x00, 0x00, 0x01, 0x0b]); - /// assert_eq!(267, rdr.read_u32::().unwrap()); - /// ``` - #[inline] - fn read_u32(&mut self) -> Result { - let mut buf = [0; 4]; - self.read_exact(&mut buf)?; - Ok(T::read_u32(&buf)) - } - - /// Reads a signed 32 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read signed 32 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0xff, 0xff, 0x7a, 0x33]); - /// assert_eq!(-34253, rdr.read_i32::().unwrap()); - /// ``` - #[inline] - fn read_i32(&mut self) -> Result { - let mut buf = [0; 4]; - self.read_exact(&mut buf)?; - Ok(T::read_i32(&buf)) - } - - /// Reads an unsigned 48 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read unsigned 48 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0xb6, 0x71, 0x6b, 0xdc, 0x2b, 0x31]); - /// assert_eq!(200598257150769, rdr.read_u48::().unwrap()); - /// ``` - #[inline] - fn read_u48(&mut self) -> Result { - let mut buf = [0; 6]; - self.read_exact(&mut buf)?; - Ok(T::read_u48(&buf)) - } - - /// Reads a signed 48 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read signed 48 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x9d, 0x71, 0xab, 0xe7, 0x97, 0x8f]); - /// assert_eq!(-108363435763825, rdr.read_i48::().unwrap()); - /// ``` - #[inline] - fn read_i48(&mut self) -> Result { - let mut buf = [0; 6]; - self.read_exact(&mut buf)?; - Ok(T::read_i48(&buf)) - } - - /// Reads an unsigned 64 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read an unsigned 64 bit big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83]); - /// assert_eq!(918733457491587, rdr.read_u64::().unwrap()); - /// ``` - #[inline] - fn read_u64(&mut self) -> Result { - let mut buf = [0; 8]; - self.read_exact(&mut buf)?; - Ok(T::read_u64(&buf)) - } - - /// Reads a signed 64 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a signed 64 bit big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0]); - /// assert_eq!(i64::min_value(), rdr.read_i64::().unwrap()); - /// ``` - #[inline] - fn read_i64(&mut self) -> Result { - let mut buf = [0; 8]; - self.read_exact(&mut buf)?; - Ok(T::read_i64(&buf)) - } - - /// Reads an unsigned 128 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read an unsigned 128 bit big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83, - /// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83 - /// ]); - /// assert_eq!(16947640962301618749969007319746179, rdr.read_u128::().unwrap()); - /// ``` - #[inline] - fn read_u128(&mut self) -> Result { - let mut buf = [0; 16]; - self.read_exact(&mut buf)?; - Ok(T::read_u128(&buf)) - } - - /// Reads a signed 128 bit integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a signed 128 bit big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - /// assert_eq!(i128::min_value(), rdr.read_i128::().unwrap()); - /// ``` - #[inline] - fn read_i128(&mut self) -> Result { - let mut buf = [0; 16]; - self.read_exact(&mut buf)?; - Ok(T::read_i128(&buf)) - } - - /// Reads an unsigned n-bytes integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read an unsigned n-byte big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0x80, 0x74, 0xfa]); - /// assert_eq!(8418554, rdr.read_uint::(3).unwrap()); - #[inline] - fn read_uint(&mut self, nbytes: usize) -> Result { - let mut buf = [0; 8]; - self.read_exact(&mut buf[..nbytes])?; - Ok(T::read_uint(&buf[..nbytes], nbytes)) - } - - /// Reads a signed n-bytes integer from the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read an unsigned n-byte big-endian integer from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0xc1, 0xff, 0x7c]); - /// assert_eq!(-4063364, rdr.read_int::(3).unwrap()); - #[inline] - fn read_int(&mut self, nbytes: usize) -> Result { - let mut buf = [0; 8]; - self.read_exact(&mut buf[..nbytes])?; - Ok(T::read_int(&buf[..nbytes], nbytes)) - } - - /// Reads an unsigned n-bytes integer from the underlying reader. - #[inline] - fn read_uint128(&mut self, nbytes: usize) -> Result { - let mut buf = [0; 16]; - self.read_exact(&mut buf[..nbytes])?; - Ok(T::read_uint128(&buf[..nbytes], nbytes)) - } - - /// Reads a signed n-bytes integer from the underlying reader. - #[inline] - fn read_int128(&mut self, nbytes: usize) -> Result { - let mut buf = [0; 16]; - self.read_exact(&mut buf[..nbytes])?; - Ok(T::read_int128(&buf[..nbytes], nbytes)) - } - - /// Reads a IEEE754 single-precision (4 bytes) floating point number from - /// the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a big-endian single-precision floating point number from a `Read`: - /// - /// ```rust - /// use std::f32; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x49, 0x0f, 0xdb, - /// ]); - /// assert_eq!(f32::consts::PI, rdr.read_f32::().unwrap()); - /// ``` - #[inline] - fn read_f32(&mut self) -> Result { - let mut buf = [0; 4]; - self.read_exact(&mut buf)?; - Ok(T::read_f32(&buf)) - } - - /// Reads a IEEE754 double-precision (8 bytes) floating point number from - /// the underlying reader. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a big-endian double-precision floating point number from a `Read`: - /// - /// ```rust - /// use std::f64; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, - /// ]); - /// assert_eq!(f64::consts::PI, rdr.read_f64::().unwrap()); - /// ``` - #[inline] - fn read_f64(&mut self) -> Result { - let mut buf = [0; 8]; - self.read_exact(&mut buf)?; - Ok(T::read_f64(&buf)) - } - - /// Reads a sequence of unsigned 16 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of unsigned 16 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); - /// let mut dst = [0; 2]; - /// rdr.read_u16_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_u16_into(&mut self, dst: &mut [u16]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_u16(dst); - Ok(()) - } - - /// Reads a sequence of unsigned 32 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of unsigned 32 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]); - /// let mut dst = [0; 2]; - /// rdr.read_u32_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_u32_into(&mut self, dst: &mut [u32]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_u32(dst); - Ok(()) - } - - /// Reads a sequence of unsigned 64 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of unsigned 64 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0, 0, 0, 0, 0, 0, 2, 5, - /// 0, 0, 0, 0, 0, 0, 3, 0, - /// ]); - /// let mut dst = [0; 2]; - /// rdr.read_u64_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_u64_into(&mut self, dst: &mut [u64]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_u64(dst); - Ok(()) - } - - /// Reads a sequence of unsigned 128 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of unsigned 128 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, - /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - /// ]); - /// let mut dst = [0; 2]; - /// rdr.read_u128_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_u128_into( - &mut self, - dst: &mut [u128], - ) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_u128(dst); - Ok(()) - } - - /// Reads a sequence of signed 8 bit integers from the underlying reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// Note that since each `i8` is a single byte, no byte order conversions - /// are used. This method is included because it provides a safe, simple - /// way for the caller to read into a `&mut [i8]` buffer. (Without this - /// method, the caller would have to either use `unsafe` code or convert - /// each byte to `i8` individually.) - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of signed 8 bit integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![2, 251, 3]); - /// let mut dst = [0; 3]; - /// rdr.read_i8_into(&mut dst).unwrap(); - /// assert_eq!([2, -5, 3], dst); - /// ``` - #[inline] - fn read_i8_into(&mut self, dst: &mut [i8]) -> Result<()> { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf) - } - - /// Reads a sequence of signed 16 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of signed 16 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); - /// let mut dst = [0; 2]; - /// rdr.read_i16_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_i16_into(&mut self, dst: &mut [i16]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_i16(dst); - Ok(()) - } - - /// Reads a sequence of signed 32 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of signed 32 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]); - /// let mut dst = [0; 2]; - /// rdr.read_i32_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_i32_into(&mut self, dst: &mut [i32]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_i32(dst); - Ok(()) - } - - /// Reads a sequence of signed 64 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of signed 64 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0, 0, 0, 0, 0, 0, 2, 5, - /// 0, 0, 0, 0, 0, 0, 3, 0, - /// ]); - /// let mut dst = [0; 2]; - /// rdr.read_i64_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_i64_into(&mut self, dst: &mut [i64]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_i64(dst); - Ok(()) - } - - /// Reads a sequence of signed 128 bit integers from the underlying - /// reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of signed 128 bit big-endian integers from a `Read`: - /// - /// ```rust - /// use std::io::Cursor; - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, - /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - /// ]); - /// let mut dst = [0; 2]; - /// rdr.read_i128_into::(&mut dst).unwrap(); - /// assert_eq!([517, 768], dst); - /// ``` - #[inline] - fn read_i128_into( - &mut self, - dst: &mut [i128], - ) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_i128(dst); - Ok(()) - } - - /// Reads a sequence of IEEE754 single-precision (4 bytes) floating - /// point numbers from the underlying reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of big-endian single-precision floating point number - /// from a `Read`: - /// - /// ```rust - /// use std::f32; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x49, 0x0f, 0xdb, - /// 0x3f, 0x80, 0x00, 0x00, - /// ]); - /// let mut dst = [0.0; 2]; - /// rdr.read_f32_into::(&mut dst).unwrap(); - /// assert_eq!([f32::consts::PI, 1.0], dst); - /// ``` - #[inline] - fn read_f32_into(&mut self, dst: &mut [f32]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_f32(dst); - Ok(()) - } - - /// **DEPRECATED**. - /// - /// This method is deprecated. Use `read_f32_into` instead. - /// - /// Reads a sequence of IEEE754 single-precision (4 bytes) floating - /// point numbers from the underlying reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of big-endian single-precision floating point number - /// from a `Read`: - /// - /// ```rust - /// use std::f32; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x49, 0x0f, 0xdb, - /// 0x3f, 0x80, 0x00, 0x00, - /// ]); - /// let mut dst = [0.0; 2]; - /// rdr.read_f32_into_unchecked::(&mut dst).unwrap(); - /// assert_eq!([f32::consts::PI, 1.0], dst); - /// ``` - #[inline] - #[deprecated(since = "1.2.0", note = "please use `read_f32_into` instead")] - fn read_f32_into_unchecked( - &mut self, - dst: &mut [f32], - ) -> Result<()> { - self.read_f32_into::(dst) - } - - /// Reads a sequence of IEEE754 double-precision (8 bytes) floating - /// point numbers from the underlying reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of big-endian single-precision floating point number - /// from a `Read`: - /// - /// ```rust - /// use std::f64; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, - /// 0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /// ]); - /// let mut dst = [0.0; 2]; - /// rdr.read_f64_into::(&mut dst).unwrap(); - /// assert_eq!([f64::consts::PI, 1.0], dst); - /// ``` - #[inline] - fn read_f64_into(&mut self, dst: &mut [f64]) -> Result<()> { - { - let buf = unsafe { slice_to_u8_mut(dst) }; - self.read_exact(buf)?; - } - T::from_slice_f64(dst); - Ok(()) - } - - /// **DEPRECATED**. - /// - /// This method is deprecated. Use `read_f64_into` instead. - /// - /// Reads a sequence of IEEE754 double-precision (8 bytes) floating - /// point numbers from the underlying reader. - /// - /// The given buffer is either filled completely or an error is returned. - /// If an error is returned, the contents of `dst` are unspecified. - /// - /// # Safety - /// - /// This method is unsafe because there are no guarantees made about the - /// floating point values. In particular, this method does not check for - /// signaling NaNs, which may result in undefined behavior. - /// - /// # Errors - /// - /// This method returns the same errors as [`Read::read_exact`]. - /// - /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact - /// - /// # Examples - /// - /// Read a sequence of big-endian single-precision floating point number - /// from a `Read`: - /// - /// ```rust - /// use std::f64; - /// use std::io::Cursor; - /// - /// use byteorder::{BigEndian, ReadBytesExt}; - /// - /// let mut rdr = Cursor::new(vec![ - /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, - /// 0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /// ]); - /// let mut dst = [0.0; 2]; - /// rdr.read_f64_into_unchecked::(&mut dst).unwrap(); - /// assert_eq!([f64::consts::PI, 1.0], dst); - /// ``` - #[inline] - #[deprecated(since = "1.2.0", note = "please use `read_f64_into` instead")] - fn read_f64_into_unchecked( - &mut self, - dst: &mut [f64], - ) -> Result<()> { - self.read_f64_into::(dst) - } -} - -/// All types that implement `Read` get methods defined in `ReadBytesExt` -/// for free. -impl ReadBytesExt for R {} - -/// Extends [`Write`] with methods for writing numbers. (For `std::io`.) -/// -/// Most of the methods defined here have an unconstrained type parameter that -/// must be explicitly instantiated. Typically, it is instantiated with either -/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate. -/// -/// # Examples -/// -/// Write unsigned 16 bit big-endian integers to a [`Write`]: -/// -/// ```rust -/// use byteorder::{BigEndian, WriteBytesExt}; -/// -/// let mut wtr = vec![]; -/// wtr.write_u16::(517).unwrap(); -/// wtr.write_u16::(768).unwrap(); -/// assert_eq!(wtr, vec![2, 5, 3, 0]); -/// ``` -/// -/// [`BigEndian`]: enum.BigEndian.html -/// [`LittleEndian`]: enum.LittleEndian.html -/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -pub trait WriteBytesExt: io::Write { - /// Writes an unsigned 8 bit integer to the underlying writer. - /// - /// Note that since this writes a single byte, no byte order conversions - /// are used. It is included for completeness. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 8 bit integers to a `Write`: - /// - /// ```rust - /// use byteorder::WriteBytesExt; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u8(2).unwrap(); - /// wtr.write_u8(5).unwrap(); - /// assert_eq!(wtr, b"\x02\x05"); - /// ``` - #[inline] - fn write_u8(&mut self, n: u8) -> Result<()> { - self.write_all(&[n]) - } - - /// Writes a signed 8 bit integer to the underlying writer. - /// - /// Note that since this writes a single byte, no byte order conversions - /// are used. It is included for completeness. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 8 bit integers to a `Write`: - /// - /// ```rust - /// use byteorder::WriteBytesExt; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i8(2).unwrap(); - /// wtr.write_i8(-5).unwrap(); - /// assert_eq!(wtr, b"\x02\xfb"); - /// ``` - #[inline] - fn write_i8(&mut self, n: i8) -> Result<()> { - self.write_all(&[n as u8]) - } - - /// Writes an unsigned 16 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 16 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u16::(517).unwrap(); - /// wtr.write_u16::(768).unwrap(); - /// assert_eq!(wtr, b"\x02\x05\x03\x00"); - /// ``` - #[inline] - fn write_u16(&mut self, n: u16) -> Result<()> { - let mut buf = [0; 2]; - T::write_u16(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 16 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 16 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i16::(193).unwrap(); - /// wtr.write_i16::(-132).unwrap(); - /// assert_eq!(wtr, b"\x00\xc1\xff\x7c"); - /// ``` - #[inline] - fn write_i16(&mut self, n: i16) -> Result<()> { - let mut buf = [0; 2]; - T::write_i16(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned 24 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 24 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u24::(267).unwrap(); - /// wtr.write_u24::(120111).unwrap(); - /// assert_eq!(wtr, b"\x00\x01\x0b\x01\xd5\x2f"); - /// ``` - #[inline] - fn write_u24(&mut self, n: u32) -> Result<()> { - let mut buf = [0; 3]; - T::write_u24(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 24 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 24 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i24::(-34253).unwrap(); - /// wtr.write_i24::(120111).unwrap(); - /// assert_eq!(wtr, b"\xff\x7a\x33\x01\xd5\x2f"); - /// ``` - #[inline] - fn write_i24(&mut self, n: i32) -> Result<()> { - let mut buf = [0; 3]; - T::write_i24(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned 32 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 32 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u32::(267).unwrap(); - /// wtr.write_u32::(1205419366).unwrap(); - /// assert_eq!(wtr, b"\x00\x00\x01\x0b\x47\xd9\x3d\x66"); - /// ``` - #[inline] - fn write_u32(&mut self, n: u32) -> Result<()> { - let mut buf = [0; 4]; - T::write_u32(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 32 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 32 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i32::(-34253).unwrap(); - /// wtr.write_i32::(1205419366).unwrap(); - /// assert_eq!(wtr, b"\xff\xff\x7a\x33\x47\xd9\x3d\x66"); - /// ``` - #[inline] - fn write_i32(&mut self, n: i32) -> Result<()> { - let mut buf = [0; 4]; - T::write_i32(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned 48 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 48 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u48::(52360336390828).unwrap(); - /// wtr.write_u48::(541).unwrap(); - /// assert_eq!(wtr, b"\x2f\x9f\x17\x40\x3a\xac\x00\x00\x00\x00\x02\x1d"); - /// ``` - #[inline] - fn write_u48(&mut self, n: u64) -> Result<()> { - let mut buf = [0; 6]; - T::write_u48(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 48 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 48 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i48::(-108363435763825).unwrap(); - /// wtr.write_i48::(77).unwrap(); - /// assert_eq!(wtr, b"\x9d\x71\xab\xe7\x97\x8f\x00\x00\x00\x00\x00\x4d"); - /// ``` - #[inline] - fn write_i48(&mut self, n: i64) -> Result<()> { - let mut buf = [0; 6]; - T::write_i48(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned 64 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write unsigned 64 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_u64::(918733457491587).unwrap(); - /// wtr.write_u64::(143).unwrap(); - /// assert_eq!(wtr, b"\x00\x03\x43\x95\x4d\x60\x86\x83\x00\x00\x00\x00\x00\x00\x00\x8f"); - /// ``` - #[inline] - fn write_u64(&mut self, n: u64) -> Result<()> { - let mut buf = [0; 8]; - T::write_u64(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 64 bit integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write signed 64 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_i64::(i64::min_value()).unwrap(); - /// wtr.write_i64::(i64::max_value()).unwrap(); - /// assert_eq!(wtr, b"\x80\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff"); - /// ``` - #[inline] - fn write_i64(&mut self, n: i64) -> Result<()> { - let mut buf = [0; 8]; - T::write_i64(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned 128 bit integer to the underlying writer. - #[inline] - fn write_u128(&mut self, n: u128) -> Result<()> { - let mut buf = [0; 16]; - T::write_u128(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a signed 128 bit integer to the underlying writer. - #[inline] - fn write_i128(&mut self, n: i128) -> Result<()> { - let mut buf = [0; 16]; - T::write_i128(&mut buf, n); - self.write_all(&buf) - } - - /// Writes an unsigned n-bytes integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Panics - /// - /// If the given integer is not representable in the given number of bytes, - /// this method panics. If `nbytes > 8`, this method panics. - /// - /// # Examples - /// - /// Write unsigned 40 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_uint::(312550384361, 5).unwrap(); - /// wtr.write_uint::(43, 5).unwrap(); - /// assert_eq!(wtr, b"\x48\xc5\x74\x62\xe9\x00\x00\x00\x00\x2b"); - /// ``` - #[inline] - fn write_uint( - &mut self, - n: u64, - nbytes: usize, - ) -> Result<()> { - let mut buf = [0; 8]; - T::write_uint(&mut buf, n, nbytes); - self.write_all(&buf[0..nbytes]) - } - - /// Writes a signed n-bytes integer to the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Panics - /// - /// If the given integer is not representable in the given number of bytes, - /// this method panics. If `nbytes > 8`, this method panics. - /// - /// # Examples - /// - /// Write signed 56 bit big-endian integers to a `Write`: - /// - /// ```rust - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_int::(-3548172039376767, 7).unwrap(); - /// wtr.write_int::(43, 7).unwrap(); - /// assert_eq!(wtr, b"\xf3\x64\xf4\xd1\xfd\xb0\x81\x00\x00\x00\x00\x00\x00\x2b"); - /// ``` - #[inline] - fn write_int( - &mut self, - n: i64, - nbytes: usize, - ) -> Result<()> { - let mut buf = [0; 8]; - T::write_int(&mut buf, n, nbytes); - self.write_all(&buf[0..nbytes]) - } - - /// Writes an unsigned n-bytes integer to the underlying writer. - /// - /// If the given integer is not representable in the given number of bytes, - /// this method panics. If `nbytes > 16`, this method panics. - #[inline] - fn write_uint128( - &mut self, - n: u128, - nbytes: usize, - ) -> Result<()> { - let mut buf = [0; 16]; - T::write_uint128(&mut buf, n, nbytes); - self.write_all(&buf[0..nbytes]) - } - - /// Writes a signed n-bytes integer to the underlying writer. - /// - /// If the given integer is not representable in the given number of bytes, - /// this method panics. If `nbytes > 16`, this method panics. - #[inline] - fn write_int128( - &mut self, - n: i128, - nbytes: usize, - ) -> Result<()> { - let mut buf = [0; 16]; - T::write_int128(&mut buf, n, nbytes); - self.write_all(&buf[0..nbytes]) - } - - /// Writes a IEEE754 single-precision (4 bytes) floating point number to - /// the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write a big-endian single-precision floating point number to a `Write`: - /// - /// ```rust - /// use std::f32; - /// - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_f32::(f32::consts::PI).unwrap(); - /// assert_eq!(wtr, b"\x40\x49\x0f\xdb"); - /// ``` - #[inline] - fn write_f32(&mut self, n: f32) -> Result<()> { - let mut buf = [0; 4]; - T::write_f32(&mut buf, n); - self.write_all(&buf) - } - - /// Writes a IEEE754 double-precision (8 bytes) floating point number to - /// the underlying writer. - /// - /// # Errors - /// - /// This method returns the same errors as [`Write::write_all`]. - /// - /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all - /// - /// # Examples - /// - /// Write a big-endian double-precision floating point number to a `Write`: - /// - /// ```rust - /// use std::f64; - /// - /// use byteorder::{BigEndian, WriteBytesExt}; - /// - /// let mut wtr = Vec::new(); - /// wtr.write_f64::(f64::consts::PI).unwrap(); - /// assert_eq!(wtr, b"\x40\x09\x21\xfb\x54\x44\x2d\x18"); - /// ``` - #[inline] - fn write_f64(&mut self, n: f64) -> Result<()> { - let mut buf = [0; 8]; - T::write_f64(&mut buf, n); - self.write_all(&buf) - } -} - -/// All types that implement `Write` get methods defined in `WriteBytesExt` -/// for free. -impl WriteBytesExt for W {} - -/// Convert a slice of T (where T is plain old data) to its mutable binary -/// representation. -/// -/// This function is wildly unsafe because it permits arbitrary modification of -/// the binary representation of any `Copy` type. Use with care. It's intended -/// to be called only where `T` is a numeric type. -unsafe fn slice_to_u8_mut(slice: &mut [T]) -> &mut [u8] { - use std::mem::size_of; - - let len = size_of::() * slice.len(); - slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len) -} diff --git a/vendor/byteorder/src/lib.rs b/vendor/byteorder/src/lib.rs deleted file mode 100644 index cc37cca6a..000000000 --- a/vendor/byteorder/src/lib.rs +++ /dev/null @@ -1,4052 +0,0 @@ -/*! -This crate provides convenience methods for encoding and decoding numbers in -either [big-endian or little-endian order]. - -The organization of the crate is pretty simple. A trait, [`ByteOrder`], specifies -byte conversion methods for each type of number in Rust (sans numbers that have -a platform dependent size like `usize` and `isize`). Two types, [`BigEndian`] -and [`LittleEndian`] implement these methods. Finally, [`ReadBytesExt`] and -[`WriteBytesExt`] provide convenience methods available to all types that -implement [`Read`] and [`Write`]. - -An alias, [`NetworkEndian`], for [`BigEndian`] is provided to help improve -code clarity. - -An additional alias, [`NativeEndian`], is provided for the endianness of the -local platform. This is convenient when serializing data for use and -conversions are not desired. - -# Examples - -Read unsigned 16 bit big-endian integers from a [`Read`] type: - -```rust -use std::io::Cursor; -use byteorder::{BigEndian, ReadBytesExt}; - -let mut rdr = Cursor::new(vec![2, 5, 3, 0]); -// Note that we use type parameters to indicate which kind of byte order -// we want! -assert_eq!(517, rdr.read_u16::().unwrap()); -assert_eq!(768, rdr.read_u16::().unwrap()); -``` - -Write unsigned 16 bit little-endian integers to a [`Write`] type: - -```rust -use byteorder::{LittleEndian, WriteBytesExt}; - -let mut wtr = vec![]; -wtr.write_u16::(517).unwrap(); -wtr.write_u16::(768).unwrap(); -assert_eq!(wtr, vec![5, 2, 0, 3]); -``` - -# Optional Features - -This crate optionally provides support for 128 bit values (`i128` and `u128`) -when built with the `i128` feature enabled. - -This crate can also be used without the standard library. - -# Alternatives - -Note that as of Rust 1.32, the standard numeric types provide built-in methods -like `to_le_bytes` and `from_le_bytes`, which support some of the same use -cases. - -[big-endian or little-endian order]: https://en.wikipedia.org/wiki/Endianness -[`ByteOrder`]: trait.ByteOrder.html -[`BigEndian`]: enum.BigEndian.html -[`LittleEndian`]: enum.LittleEndian.html -[`ReadBytesExt`]: trait.ReadBytesExt.html -[`WriteBytesExt`]: trait.WriteBytesExt.html -[`NetworkEndian`]: type.NetworkEndian.html -[`NativeEndian`]: type.NativeEndian.html -[`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html -[`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -*/ - -#![deny(missing_docs)] -#![cfg_attr(not(feature = "std"), no_std)] - -use core::{ - convert::TryInto, fmt::Debug, hash::Hash, ptr::copy_nonoverlapping, slice, -}; - -#[cfg(feature = "std")] -pub use crate::io::{ReadBytesExt, WriteBytesExt}; - -#[cfg(feature = "std")] -mod io; - -#[inline] -fn extend_sign(val: u64, nbytes: usize) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -#[inline] -fn extend_sign128(val: u128, nbytes: usize) -> i128 { - let shift = (16 - nbytes) * 8; - (val << shift) as i128 >> shift -} - -#[inline] -fn unextend_sign(val: i64, nbytes: usize) -> u64 { - let shift = (8 - nbytes) * 8; - (val << shift) as u64 >> shift -} - -#[inline] -fn unextend_sign128(val: i128, nbytes: usize) -> u128 { - let shift = (16 - nbytes) * 8; - (val << shift) as u128 >> shift -} - -#[inline] -fn pack_size(n: u64) -> usize { - if n < 1 << 8 { - 1 - } else if n < 1 << 16 { - 2 - } else if n < 1 << 24 { - 3 - } else if n < 1 << 32 { - 4 - } else if n < 1 << 40 { - 5 - } else if n < 1 << 48 { - 6 - } else if n < 1 << 56 { - 7 - } else { - 8 - } -} - -#[inline] -fn pack_size128(n: u128) -> usize { - if n < 1 << 8 { - 1 - } else if n < 1 << 16 { - 2 - } else if n < 1 << 24 { - 3 - } else if n < 1 << 32 { - 4 - } else if n < 1 << 40 { - 5 - } else if n < 1 << 48 { - 6 - } else if n < 1 << 56 { - 7 - } else if n < 1 << 64 { - 8 - } else if n < 1 << 72 { - 9 - } else if n < 1 << 80 { - 10 - } else if n < 1 << 88 { - 11 - } else if n < 1 << 96 { - 12 - } else if n < 1 << 104 { - 13 - } else if n < 1 << 112 { - 14 - } else if n < 1 << 120 { - 15 - } else { - 16 - } -} - -mod private { - /// Sealed stops crates other than byteorder from implementing any traits - /// that use it. - pub trait Sealed {} - impl Sealed for super::LittleEndian {} - impl Sealed for super::BigEndian {} -} - -/// `ByteOrder` describes types that can serialize integers as bytes. -/// -/// Note that `Self` does not appear anywhere in this trait's definition! -/// Therefore, in order to use it, you'll need to use syntax like -/// `T::read_u16(&[0, 1])` where `T` implements `ByteOrder`. -/// -/// This crate provides two types that implement `ByteOrder`: [`BigEndian`] -/// and [`LittleEndian`]. -/// This trait is sealed and cannot be implemented for callers to avoid -/// breaking backwards compatibility when adding new derived traits. -/// -/// # Examples -/// -/// Write and read `u32` numbers in little endian order: -/// -/// ```rust -/// use byteorder::{ByteOrder, LittleEndian}; -/// -/// let mut buf = [0; 4]; -/// LittleEndian::write_u32(&mut buf, 1_000_000); -/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); -/// ``` -/// -/// Write and read `i16` numbers in big endian order: -/// -/// ```rust -/// use byteorder::{ByteOrder, BigEndian}; -/// -/// let mut buf = [0; 2]; -/// BigEndian::write_i16(&mut buf, -5_000); -/// assert_eq!(-5_000, BigEndian::read_i16(&buf)); -/// ``` -/// -/// [`BigEndian`]: enum.BigEndian.html -/// [`LittleEndian`]: enum.LittleEndian.html -pub trait ByteOrder: - Clone - + Copy - + Debug - + Default - + Eq - + Hash - + Ord - + PartialEq - + PartialOrd - + private::Sealed -{ - /// Reads an unsigned 16 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - fn read_u16(buf: &[u8]) -> u16; - - /// Reads an unsigned 24 bit integer from `buf`, stored in u32. - /// - /// # Panics - /// - /// Panics when `buf.len() < 3`. - /// - /// # Examples - /// - /// Write and read 24 bit `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_u24(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf)); - /// ``` - fn read_u24(buf: &[u8]) -> u32 { - Self::read_uint(buf, 3) as u32 - } - - /// Reads an unsigned 32 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 4]; - /// LittleEndian::write_u32(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); - /// ``` - fn read_u32(buf: &[u8]) -> u32; - - /// Reads an unsigned 48 bit integer from `buf`, stored in u64. - /// - /// # Panics - /// - /// Panics when `buf.len() < 6`. - /// - /// # Examples - /// - /// Write and read 48 bit `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 6]; - /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000); - /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf)); - /// ``` - fn read_u48(buf: &[u8]) -> u64 { - Self::read_uint(buf, 6) as u64 - } - - /// Reads an unsigned 64 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 8]; - /// LittleEndian::write_u64(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf)); - /// ``` - fn read_u64(buf: &[u8]) -> u64; - - /// Reads an unsigned 128 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 16`. - /// - /// # Examples - /// - /// Write and read `u128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 16]; - /// LittleEndian::write_u128(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf)); - /// ``` - fn read_u128(buf: &[u8]) -> u128; - - /// Reads an unsigned n-bytes integer from `buf`. - /// - /// # Panics - /// - /// Panics when `nbytes < 1` or `nbytes > 8` or - /// `buf.len() < nbytes` - /// - /// # Examples - /// - /// Write and read an n-byte number in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_uint(&mut buf, 1_000_000, 3); - /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3)); - /// ``` - fn read_uint(buf: &[u8], nbytes: usize) -> u64; - - /// Reads an unsigned n-bytes integer from `buf`. - /// - /// # Panics - /// - /// Panics when `nbytes < 1` or `nbytes > 16` or - /// `buf.len() < nbytes` - /// - /// # Examples - /// - /// Write and read an n-byte number in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3); - /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3)); - /// ``` - fn read_uint128(buf: &[u8], nbytes: usize) -> u128; - - /// Writes an unsigned 16 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - /// - /// # Examples - /// - /// Write and read `u16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 2]; - /// LittleEndian::write_u16(&mut buf, 1_000); - /// assert_eq!(1_000, LittleEndian::read_u16(&buf)); - /// ``` - fn write_u16(buf: &mut [u8], n: u16); - - /// Writes an unsigned 24 bit integer `n` to `buf`, stored in u32. - /// - /// # Panics - /// - /// Panics when `buf.len() < 3`. - /// - /// # Examples - /// - /// Write and read 24 bit `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_u24(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf)); - /// ``` - fn write_u24(buf: &mut [u8], n: u32) { - Self::write_uint(buf, n as u64, 3) - } - - /// Writes an unsigned 32 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 4]; - /// LittleEndian::write_u32(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); - /// ``` - fn write_u32(buf: &mut [u8], n: u32); - - /// Writes an unsigned 48 bit integer `n` to `buf`, stored in u64. - /// - /// # Panics - /// - /// Panics when `buf.len() < 6`. - /// - /// # Examples - /// - /// Write and read 48 bit `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 6]; - /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000); - /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf)); - /// ``` - fn write_u48(buf: &mut [u8], n: u64) { - Self::write_uint(buf, n as u64, 6) - } - - /// Writes an unsigned 64 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 8]; - /// LittleEndian::write_u64(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf)); - /// ``` - fn write_u64(buf: &mut [u8], n: u64); - - /// Writes an unsigned 128 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 16`. - /// - /// # Examples - /// - /// Write and read `u128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 16]; - /// LittleEndian::write_u128(&mut buf, 1_000_000); - /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf)); - /// ``` - fn write_u128(buf: &mut [u8], n: u128); - - /// Writes an unsigned integer `n` to `buf` using only `nbytes`. - /// - /// # Panics - /// - /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then - /// this method panics. - /// - /// # Examples - /// - /// Write and read an n-byte number in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_uint(&mut buf, 1_000_000, 3); - /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3)); - /// ``` - fn write_uint(buf: &mut [u8], n: u64, nbytes: usize); - - /// Writes an unsigned integer `n` to `buf` using only `nbytes`. - /// - /// # Panics - /// - /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then - /// this method panics. - /// - /// # Examples - /// - /// Write and read an n-byte number in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3); - /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3)); - /// ``` - fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize); - - /// Reads a signed 16 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - /// - /// # Examples - /// - /// Write and read `i16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 2]; - /// LittleEndian::write_i16(&mut buf, -1_000); - /// assert_eq!(-1_000, LittleEndian::read_i16(&buf)); - /// ``` - #[inline] - fn read_i16(buf: &[u8]) -> i16 { - Self::read_u16(buf) as i16 - } - - /// Reads a signed 24 bit integer from `buf`, stored in i32. - /// - /// # Panics - /// - /// Panics when `buf.len() < 3`. - /// - /// # Examples - /// - /// Write and read 24 bit `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_i24(&mut buf, -1_000_000); - /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf)); - /// ``` - #[inline] - fn read_i24(buf: &[u8]) -> i32 { - Self::read_int(buf, 3) as i32 - } - - /// Reads a signed 32 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 4]; - /// LittleEndian::write_i32(&mut buf, -1_000_000); - /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf)); - /// ``` - #[inline] - fn read_i32(buf: &[u8]) -> i32 { - Self::read_u32(buf) as i32 - } - - /// Reads a signed 48 bit integer from `buf`, stored in i64. - /// - /// # Panics - /// - /// Panics when `buf.len() < 6`. - /// - /// # Examples - /// - /// Write and read 48 bit `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 6]; - /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000); - /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf)); - /// ``` - #[inline] - fn read_i48(buf: &[u8]) -> i64 { - Self::read_int(buf, 6) as i64 - } - - /// Reads a signed 64 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 8]; - /// LittleEndian::write_i64(&mut buf, -1_000_000_000); - /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf)); - /// ``` - #[inline] - fn read_i64(buf: &[u8]) -> i64 { - Self::read_u64(buf) as i64 - } - - /// Reads a signed 128 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 16`. - /// - /// # Examples - /// - /// Write and read `i128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 16]; - /// LittleEndian::write_i128(&mut buf, -1_000_000_000); - /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf)); - /// ``` - #[inline] - fn read_i128(buf: &[u8]) -> i128 { - Self::read_u128(buf) as i128 - } - - /// Reads a signed n-bytes integer from `buf`. - /// - /// # Panics - /// - /// Panics when `nbytes < 1` or `nbytes > 8` or - /// `buf.len() < nbytes` - /// - /// # Examples - /// - /// Write and read n-length signed numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_int(&mut buf, -1_000, 3); - /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3)); - /// ``` - #[inline] - fn read_int(buf: &[u8], nbytes: usize) -> i64 { - extend_sign(Self::read_uint(buf, nbytes), nbytes) - } - - /// Reads a signed n-bytes integer from `buf`. - /// - /// # Panics - /// - /// Panics when `nbytes < 1` or `nbytes > 16` or - /// `buf.len() < nbytes` - /// - /// # Examples - /// - /// Write and read n-length signed numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_int128(&mut buf, -1_000, 3); - /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3)); - /// ``` - #[inline] - fn read_int128(buf: &[u8], nbytes: usize) -> i128 { - extend_sign128(Self::read_uint128(buf, nbytes), nbytes) - } - - /// Reads a IEEE754 single-precision (4 bytes) floating point number. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `f32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let e = 2.71828; - /// let mut buf = [0; 4]; - /// LittleEndian::write_f32(&mut buf, e); - /// assert_eq!(e, LittleEndian::read_f32(&buf)); - /// ``` - #[inline] - fn read_f32(buf: &[u8]) -> f32 { - f32::from_bits(Self::read_u32(buf)) - } - - /// Reads a IEEE754 double-precision (8 bytes) floating point number. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `f64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let phi = 1.6180339887; - /// let mut buf = [0; 8]; - /// LittleEndian::write_f64(&mut buf, phi); - /// assert_eq!(phi, LittleEndian::read_f64(&buf)); - /// ``` - #[inline] - fn read_f64(buf: &[u8]) -> f64 { - f64::from_bits(Self::read_u64(buf)) - } - - /// Writes a signed 16 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - /// - /// # Examples - /// - /// Write and read `i16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 2]; - /// LittleEndian::write_i16(&mut buf, -1_000); - /// assert_eq!(-1_000, LittleEndian::read_i16(&buf)); - /// ``` - #[inline] - fn write_i16(buf: &mut [u8], n: i16) { - Self::write_u16(buf, n as u16) - } - - /// Writes a signed 24 bit integer `n` to `buf`, stored in i32. - /// - /// # Panics - /// - /// Panics when `buf.len() < 3`. - /// - /// # Examples - /// - /// Write and read 24 bit `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_i24(&mut buf, -1_000_000); - /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf)); - /// ``` - #[inline] - fn write_i24(buf: &mut [u8], n: i32) { - Self::write_int(buf, n as i64, 3) - } - - /// Writes a signed 32 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 4]; - /// LittleEndian::write_i32(&mut buf, -1_000_000); - /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf)); - /// ``` - #[inline] - fn write_i32(buf: &mut [u8], n: i32) { - Self::write_u32(buf, n as u32) - } - - /// Writes a signed 48 bit integer `n` to `buf`, stored in i64. - /// - /// # Panics - /// - /// Panics when `buf.len() < 6`. - /// - /// # Examples - /// - /// Write and read 48 bit `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 6]; - /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000); - /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf)); - /// ``` - #[inline] - fn write_i48(buf: &mut [u8], n: i64) { - Self::write_int(buf, n as i64, 6) - } - - /// Writes a signed 64 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 8]; - /// LittleEndian::write_i64(&mut buf, -1_000_000_000); - /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf)); - /// ``` - #[inline] - fn write_i64(buf: &mut [u8], n: i64) { - Self::write_u64(buf, n as u64) - } - - /// Writes a signed 128 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 16`. - /// - /// # Examples - /// - /// Write and read n-byte `i128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 16]; - /// LittleEndian::write_i128(&mut buf, -1_000_000_000); - /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf)); - /// ``` - #[inline] - fn write_i128(buf: &mut [u8], n: i128) { - Self::write_u128(buf, n as u128) - } - - /// Writes a signed integer `n` to `buf` using only `nbytes`. - /// - /// # Panics - /// - /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then - /// this method panics. - /// - /// # Examples - /// - /// Write and read an n-byte number in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_int(&mut buf, -1_000, 3); - /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3)); - /// ``` - #[inline] - fn write_int(buf: &mut [u8], n: i64, nbytes: usize) { - Self::write_uint(buf, unextend_sign(n, nbytes), nbytes) - } - - /// Writes a signed integer `n` to `buf` using only `nbytes`. - /// - /// # Panics - /// - /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then - /// this method panics. - /// - /// # Examples - /// - /// Write and read n-length signed numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut buf = [0; 3]; - /// LittleEndian::write_int128(&mut buf, -1_000, 3); - /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3)); - /// ``` - #[inline] - fn write_int128(buf: &mut [u8], n: i128, nbytes: usize) { - Self::write_uint128(buf, unextend_sign128(n, nbytes), nbytes) - } - - /// Writes a IEEE754 single-precision (4 bytes) floating point number. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - /// - /// # Examples - /// - /// Write and read `f32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let e = 2.71828; - /// let mut buf = [0; 4]; - /// LittleEndian::write_f32(&mut buf, e); - /// assert_eq!(e, LittleEndian::read_f32(&buf)); - /// ``` - #[inline] - fn write_f32(buf: &mut [u8], n: f32) { - Self::write_u32(buf, n.to_bits()) - } - - /// Writes a IEEE754 double-precision (8 bytes) floating point number. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - /// - /// # Examples - /// - /// Write and read `f64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let phi = 1.6180339887; - /// let mut buf = [0; 8]; - /// LittleEndian::write_f64(&mut buf, phi); - /// assert_eq!(phi, LittleEndian::read_f64(&buf)); - /// ``` - #[inline] - fn write_f64(buf: &mut [u8], n: f64) { - Self::write_u64(buf, n.to_bits()) - } - - /// Reads unsigned 16 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 2*dst.len()`. - /// - /// # Examples - /// - /// Write and read `u16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 8]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u16_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u16_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn read_u16_into(src: &[u8], dst: &mut [u16]); - - /// Reads unsigned 32 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 4*dst.len()`. - /// - /// # Examples - /// - /// Write and read `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn read_u32_into(src: &[u8], dst: &mut [u32]); - - /// Reads unsigned 64 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 8*dst.len()`. - /// - /// # Examples - /// - /// Write and read `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn read_u64_into(src: &[u8], dst: &mut [u64]); - - /// Reads unsigned 128 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 16*dst.len()`. - /// - /// # Examples - /// - /// Write and read `u128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 64]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u128_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u128_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn read_u128_into(src: &[u8], dst: &mut [u128]); - - /// Reads signed 16 bit integers from `src` to `dst`. - /// - /// # Panics - /// - /// Panics when `buf.len() != 2*dst.len()`. - /// - /// # Examples - /// - /// Write and read `i16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 8]; - /// let numbers_given = [1, 2, 0x0f, 0xee]; - /// LittleEndian::write_i16_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i16_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_i16_into(src: &[u8], dst: &mut [i16]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u16, dst.len()) - }; - Self::read_u16_into(src, dst) - } - - /// Reads signed 32 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 4*dst.len()`. - /// - /// # Examples - /// - /// Write and read `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_i32_into(src: &[u8], dst: &mut [i32]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len()) - }; - Self::read_u32_into(src, dst); - } - - /// Reads signed 64 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 8*dst.len()`. - /// - /// # Examples - /// - /// Write and read `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_i64_into(src: &[u8], dst: &mut [i64]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len()) - }; - Self::read_u64_into(src, dst); - } - - /// Reads signed 128 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 16*dst.len()`. - /// - /// # Examples - /// - /// Write and read `i128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 64]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i128_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i128_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_i128_into(src: &[u8], dst: &mut [i128]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u128, dst.len()) - }; - Self::read_u128_into(src, dst); - } - - /// Reads IEEE754 single-precision (4 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 4*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; - /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_f32_into(src: &[u8], dst: &mut [f32]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len()) - }; - Self::read_u32_into(src, dst); - } - - /// **DEPRECATED**. - /// - /// This method is deprecated. Use `read_f32_into` instead. - /// Reads IEEE754 single-precision (4 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 4*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; - /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f32_into_unchecked(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - #[deprecated(since = "1.3.0", note = "please use `read_f32_into` instead")] - fn read_f32_into_unchecked(src: &[u8], dst: &mut [f32]) { - Self::read_f32_into(src, dst); - } - - /// Reads IEEE754 single-precision (4 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 8*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91]; - /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - fn read_f64_into(src: &[u8], dst: &mut [f64]) { - let dst = unsafe { - slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len()) - }; - Self::read_u64_into(src, dst); - } - - /// **DEPRECATED**. - /// - /// This method is deprecated. Use `read_f64_into` instead. - /// - /// Reads IEEE754 single-precision (4 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 8*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91]; - /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f64_into_unchecked(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - #[inline] - #[deprecated(since = "1.3.0", note = "please use `read_f64_into` instead")] - fn read_f64_into_unchecked(src: &[u8], dst: &mut [f64]) { - Self::read_f64_into(src, dst); - } - - /// Writes unsigned 16 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 2*src.len()`. - /// - /// # Examples - /// - /// Write and read `u16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 8]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u16_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u16_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_u16_into(src: &[u16], dst: &mut [u8]); - - /// Writes unsigned 32 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 4*src.len()`. - /// - /// # Examples - /// - /// Write and read `u32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_u32_into(src: &[u32], dst: &mut [u8]); - - /// Writes unsigned 64 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 8*src.len()`. - /// - /// # Examples - /// - /// Write and read `u64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_u64_into(src: &[u64], dst: &mut [u8]); - - /// Writes unsigned 128 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 16*src.len()`. - /// - /// # Examples - /// - /// Write and read `u128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 64]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_u128_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_u128_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_u128_into(src: &[u128], dst: &mut [u8]); - - /// Writes signed 8 bit integers from `src` into `dst`. - /// - /// Note that since each `i8` is a single byte, no byte order conversions - /// are used. This method is included because it provides a safe, simple - /// way for the caller to write from a `&[i8]` buffer. (Without this - /// method, the caller would have to either use `unsafe` code or convert - /// each byte to `u8` individually.) - /// - /// # Panics - /// - /// Panics when `buf.len() != src.len()`. - /// - /// # Examples - /// - /// Write and read `i8` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian, ReadBytesExt}; - /// - /// let mut bytes = [0; 4]; - /// let numbers_given = [1, 2, 0xf, 0xe]; - /// LittleEndian::write_i8_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// bytes.as_ref().read_i8_into(&mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_i8_into(src: &[i8], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u8, src.len()) - }; - dst.copy_from_slice(src); - } - - /// Writes signed 16 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `buf.len() != 2*src.len()`. - /// - /// # Examples - /// - /// Write and read `i16` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 8]; - /// let numbers_given = [1, 2, 0x0f, 0xee]; - /// LittleEndian::write_i16_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i16_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_i16_into(src: &[i16], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u16, src.len()) - }; - Self::write_u16_into(src, dst); - } - - /// Writes signed 32 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 4*src.len()`. - /// - /// # Examples - /// - /// Write and read `i32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_i32_into(src: &[i32], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u32, src.len()) - }; - Self::write_u32_into(src, dst); - } - - /// Writes signed 64 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 8*src.len()`. - /// - /// # Examples - /// - /// Write and read `i64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_i64_into(src: &[i64], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u64, src.len()) - }; - Self::write_u64_into(src, dst); - } - - /// Writes signed 128 bit integers from `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `dst.len() != 16*src.len()`. - /// - /// # Examples - /// - /// Write and read `i128` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 64]; - /// let numbers_given = [1, 2, 0xf00f, 0xffee]; - /// LittleEndian::write_i128_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0; 4]; - /// LittleEndian::read_i128_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_i128_into(src: &[i128], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u128, src.len()) - }; - Self::write_u128_into(src, dst); - } - - /// Writes IEEE754 single-precision (4 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 4*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f32` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 16]; - /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; - /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f32_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_f32_into(src: &[f32], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u32, src.len()) - }; - Self::write_u32_into(src, dst); - } - - /// Writes IEEE754 double-precision (8 bytes) floating point numbers from - /// `src` into `dst`. - /// - /// # Panics - /// - /// Panics when `src.len() != 8*dst.len()`. - /// - /// # Examples - /// - /// Write and read `f64` numbers in little endian order: - /// - /// ```rust - /// use byteorder::{ByteOrder, LittleEndian}; - /// - /// let mut bytes = [0; 32]; - /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91]; - /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); - /// - /// let mut numbers_got = [0.0; 4]; - /// LittleEndian::read_f64_into(&bytes, &mut numbers_got); - /// assert_eq!(numbers_given, numbers_got); - /// ``` - fn write_f64_into(src: &[f64], dst: &mut [u8]) { - let src = unsafe { - slice::from_raw_parts(src.as_ptr() as *const u64, src.len()) - }; - Self::write_u64_into(src, dst); - } - - /// Converts the given slice of unsigned 16 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_u16(&mut numbers); - /// assert_eq!(numbers, [5u16.to_be(), 65000u16.to_be()]); - /// ``` - fn from_slice_u16(numbers: &mut [u16]); - - /// Converts the given slice of unsigned 32 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_u32(&mut numbers); - /// assert_eq!(numbers, [5u32.to_be(), 65000u32.to_be()]); - /// ``` - fn from_slice_u32(numbers: &mut [u32]); - - /// Converts the given slice of unsigned 64 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_u64(&mut numbers); - /// assert_eq!(numbers, [5u64.to_be(), 65000u64.to_be()]); - /// ``` - fn from_slice_u64(numbers: &mut [u64]); - - /// Converts the given slice of unsigned 128 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_u128(&mut numbers); - /// assert_eq!(numbers, [5u128.to_be(), 65000u128.to_be()]); - /// ``` - fn from_slice_u128(numbers: &mut [u128]); - - /// Converts the given slice of signed 16 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 6500]; - /// BigEndian::from_slice_i16(&mut numbers); - /// assert_eq!(numbers, [5i16.to_be(), 6500i16.to_be()]); - /// ``` - #[inline] - fn from_slice_i16(src: &mut [i16]) { - let src = unsafe { - slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u16, src.len()) - }; - Self::from_slice_u16(src); - } - - /// Converts the given slice of signed 32 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_i32(&mut numbers); - /// assert_eq!(numbers, [5i32.to_be(), 65000i32.to_be()]); - /// ``` - #[inline] - fn from_slice_i32(src: &mut [i32]) { - let src = unsafe { - slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u32, src.len()) - }; - Self::from_slice_u32(src); - } - - /// Converts the given slice of signed 64 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_i64(&mut numbers); - /// assert_eq!(numbers, [5i64.to_be(), 65000i64.to_be()]); - /// ``` - #[inline] - fn from_slice_i64(src: &mut [i64]) { - let src = unsafe { - slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u64, src.len()) - }; - Self::from_slice_u64(src); - } - - /// Converts the given slice of signed 128 bit integers to a particular - /// endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - /// - /// # Examples - /// - /// Convert the host platform's endianness to big-endian: - /// - /// ```rust - /// use byteorder::{ByteOrder, BigEndian}; - /// - /// let mut numbers = [5, 65000]; - /// BigEndian::from_slice_i128(&mut numbers); - /// assert_eq!(numbers, [5i128.to_be(), 65000i128.to_be()]); - /// ``` - #[inline] - fn from_slice_i128(src: &mut [i128]) { - let src = unsafe { - slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u128, src.len()) - }; - Self::from_slice_u128(src); - } - - /// Converts the given slice of IEEE754 single-precision (4 bytes) floating - /// point numbers to a particular endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - fn from_slice_f32(numbers: &mut [f32]); - - /// Converts the given slice of IEEE754 double-precision (8 bytes) floating - /// point numbers to a particular endianness. - /// - /// If the endianness matches the endianness of the host platform, then - /// this is a no-op. - fn from_slice_f64(numbers: &mut [f64]); -} - -/// Defines big-endian serialization. -/// -/// Note that this type has no value constructor. It is used purely at the -/// type level. -/// -/// # Examples -/// -/// Write and read `u32` numbers in big endian order: -/// -/// ```rust -/// use byteorder::{ByteOrder, BigEndian}; -/// -/// let mut buf = [0; 4]; -/// BigEndian::write_u32(&mut buf, 1_000_000); -/// assert_eq!(1_000_000, BigEndian::read_u32(&buf)); -/// ``` -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum BigEndian {} - -impl Default for BigEndian { - fn default() -> BigEndian { - panic!("BigEndian default") - } -} - -/// A type alias for [`BigEndian`]. -/// -/// [`BigEndian`]: enum.BigEndian.html -pub type BE = BigEndian; - -/// Defines little-endian serialization. -/// -/// Note that this type has no value constructor. It is used purely at the -/// type level. -/// -/// # Examples -/// -/// Write and read `u32` numbers in little endian order: -/// -/// ```rust -/// use byteorder::{ByteOrder, LittleEndian}; -/// -/// let mut buf = [0; 4]; -/// LittleEndian::write_u32(&mut buf, 1_000_000); -/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); -/// ``` -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum LittleEndian {} - -impl Default for LittleEndian { - fn default() -> LittleEndian { - panic!("LittleEndian default") - } -} - -/// A type alias for [`LittleEndian`]. -/// -/// [`LittleEndian`]: enum.LittleEndian.html -pub type LE = LittleEndian; - -/// Defines network byte order serialization. -/// -/// Network byte order is defined by [RFC 1700][1] to be big-endian, and is -/// referred to in several protocol specifications. This type is an alias of -/// [`BigEndian`]. -/// -/// [1]: https://tools.ietf.org/html/rfc1700 -/// -/// Note that this type has no value constructor. It is used purely at the -/// type level. -/// -/// # Examples -/// -/// Write and read `i16` numbers in big endian order: -/// -/// ```rust -/// use byteorder::{ByteOrder, NetworkEndian, BigEndian}; -/// -/// let mut buf = [0; 2]; -/// BigEndian::write_i16(&mut buf, -5_000); -/// assert_eq!(-5_000, NetworkEndian::read_i16(&buf)); -/// ``` -/// -/// [`BigEndian`]: enum.BigEndian.html -pub type NetworkEndian = BigEndian; - -/// Defines system native-endian serialization. -/// -/// Note that this type has no value constructor. It is used purely at the -/// type level. -/// -/// On this platform, this is an alias for [`LittleEndian`]. -/// -/// [`LittleEndian`]: enum.LittleEndian.html -#[cfg(target_endian = "little")] -pub type NativeEndian = LittleEndian; - -/// Defines system native-endian serialization. -/// -/// Note that this type has no value constructor. It is used purely at the -/// type level. -/// -/// On this platform, this is an alias for [`BigEndian`]. -/// -/// [`BigEndian`]: enum.BigEndian.html -#[cfg(target_endian = "big")] -pub type NativeEndian = BigEndian; - -/// Copies $size bytes from a number $n to a &mut [u8] $dst. $ty represents the -/// numeric type of $n and $which must be either to_be or to_le, depending on -/// which endianness one wants to use when writing to $dst. -/// -/// This macro is only safe to call when $ty is a numeric type and $size == -/// size_of::<$ty>() and where $dst is a &mut [u8]. -macro_rules! unsafe_write_num_bytes { - ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => {{ - assert!($size <= $dst.len()); - unsafe { - // N.B. https://github.com/rust-lang/rust/issues/22776 - let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); - copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); - } - }}; -} - -/// Copies a &[u8] $src into a &mut [] $dst for the endianness given -/// by $which (must be either to_be or to_le). -/// -/// This macro is only safe to call when $src and $dst are &[u8] and &mut [u8], -/// respectively. The macro will panic if $src.len() != $size * $dst.len(), -/// where $size represents the size of the integers encoded in $src. -macro_rules! unsafe_read_slice { - ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ - assert_eq!($src.len(), $size * $dst.len()); - - unsafe { - copy_nonoverlapping( - $src.as_ptr(), - $dst.as_mut_ptr() as *mut u8, - $src.len(), - ); - } - for v in $dst.iter_mut() { - *v = v.$which(); - } - }}; -} - -/// Copies a &[$ty] $src into a &mut [u8] $dst, where $ty must be a numeric -/// type. This panics if size_of::<$ty>() * $src.len() != $dst.len(). -/// -/// This macro is only safe to call when $src is a slice of numeric types and -/// $dst is a &mut [u8] and where $ty represents the type of the integers in -/// $src. -macro_rules! unsafe_write_slice_native { - ($src:expr, $dst:expr, $ty:ty) => {{ - let size = core::mem::size_of::<$ty>(); - assert_eq!(size * $src.len(), $dst.len()); - - unsafe { - copy_nonoverlapping( - $src.as_ptr() as *const u8, - $dst.as_mut_ptr(), - $dst.len(), - ); - } - }}; -} - -macro_rules! write_slice { - ($src:expr, $dst:expr, $ty:ty, $size:expr, $write:expr) => {{ - assert!($size == ::core::mem::size_of::<$ty>()); - assert_eq!($size * $src.len(), $dst.len()); - - for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { - $write(chunk, n); - } - }}; -} - -impl ByteOrder for BigEndian { - #[inline] - fn read_u16(buf: &[u8]) -> u16 { - u16::from_be_bytes(buf[..2].try_into().unwrap()) - } - - #[inline] - fn read_u32(buf: &[u8]) -> u32 { - u32::from_be_bytes(buf[..4].try_into().unwrap()) - } - - #[inline] - fn read_u64(buf: &[u8]) -> u64 { - u64::from_be_bytes(buf[..8].try_into().unwrap()) - } - - #[inline] - fn read_u128(buf: &[u8]) -> u128 { - u128::from_be_bytes(buf[..16].try_into().unwrap()) - } - - #[inline] - fn read_uint(buf: &[u8], nbytes: usize) -> u64 { - assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); - let mut out = 0u64; - let ptr_out = &mut out as *mut u64 as *mut u8; - unsafe { - copy_nonoverlapping( - buf.as_ptr(), - ptr_out.offset((8 - nbytes) as isize), - nbytes, - ); - } - out.to_be() - } - - #[inline] - fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { - assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); - let mut out: u128 = 0; - let ptr_out = &mut out as *mut u128 as *mut u8; - unsafe { - copy_nonoverlapping( - buf.as_ptr(), - ptr_out.offset((16 - nbytes) as isize), - nbytes, - ); - } - out.to_be() - } - - #[inline] - fn write_u16(buf: &mut [u8], n: u16) { - unsafe_write_num_bytes!(u16, 2, n, buf, to_be); - } - - #[inline] - fn write_u32(buf: &mut [u8], n: u32) { - unsafe_write_num_bytes!(u32, 4, n, buf, to_be); - } - - #[inline] - fn write_u64(buf: &mut [u8], n: u64) { - unsafe_write_num_bytes!(u64, 8, n, buf, to_be); - } - - #[inline] - fn write_u128(buf: &mut [u8], n: u128) { - unsafe_write_num_bytes!(u128, 16, n, buf, to_be); - } - - #[inline] - fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) { - assert!(pack_size(n) <= nbytes && nbytes <= 8); - assert!(nbytes <= buf.len()); - unsafe { - let bytes = *(&n.to_be() as *const u64 as *const [u8; 8]); - copy_nonoverlapping( - bytes.as_ptr().offset((8 - nbytes) as isize), - buf.as_mut_ptr(), - nbytes, - ); - } - } - - #[inline] - fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) { - assert!(pack_size128(n) <= nbytes && nbytes <= 16); - assert!(nbytes <= buf.len()); - unsafe { - let bytes = *(&n.to_be() as *const u128 as *const [u8; 16]); - copy_nonoverlapping( - bytes.as_ptr().offset((16 - nbytes) as isize), - buf.as_mut_ptr(), - nbytes, - ); - } - } - - #[inline] - fn read_u16_into(src: &[u8], dst: &mut [u16]) { - unsafe_read_slice!(src, dst, 2, to_be); - } - - #[inline] - fn read_u32_into(src: &[u8], dst: &mut [u32]) { - unsafe_read_slice!(src, dst, 4, to_be); - } - - #[inline] - fn read_u64_into(src: &[u8], dst: &mut [u64]) { - unsafe_read_slice!(src, dst, 8, to_be); - } - - #[inline] - fn read_u128_into(src: &[u8], dst: &mut [u128]) { - unsafe_read_slice!(src, dst, 16, to_be); - } - - #[inline] - fn write_u16_into(src: &[u16], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u16); - } else { - write_slice!(src, dst, u16, 2, Self::write_u16); - } - } - - #[inline] - fn write_u32_into(src: &[u32], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u32); - } else { - write_slice!(src, dst, u32, 4, Self::write_u32); - } - } - - #[inline] - fn write_u64_into(src: &[u64], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u64); - } else { - write_slice!(src, dst, u64, 8, Self::write_u64); - } - } - - #[inline] - fn write_u128_into(src: &[u128], dst: &mut [u8]) { - if cfg!(target_endian = "big") { - unsafe_write_slice_native!(src, dst, u128); - } else { - write_slice!(src, dst, u128, 16, Self::write_u128); - } - } - - #[inline] - fn from_slice_u16(numbers: &mut [u16]) { - if cfg!(target_endian = "little") { - for n in numbers { - *n = n.to_be(); - } - } - } - - #[inline] - fn from_slice_u32(numbers: &mut [u32]) { - if cfg!(target_endian = "little") { - for n in numbers { - *n = n.to_be(); - } - } - } - - #[inline] - fn from_slice_u64(numbers: &mut [u64]) { - if cfg!(target_endian = "little") { - for n in numbers { - *n = n.to_be(); - } - } - } - - #[inline] - fn from_slice_u128(numbers: &mut [u128]) { - if cfg!(target_endian = "little") { - for n in numbers { - *n = n.to_be(); - } - } - } - - #[inline] - fn from_slice_f32(numbers: &mut [f32]) { - if cfg!(target_endian = "little") { - for n in numbers { - unsafe { - let int = *(n as *const f32 as *const u32); - *n = *(&int.to_be() as *const u32 as *const f32); - } - } - } - } - - #[inline] - fn from_slice_f64(numbers: &mut [f64]) { - if cfg!(target_endian = "little") { - for n in numbers { - unsafe { - let int = *(n as *const f64 as *const u64); - *n = *(&int.to_be() as *const u64 as *const f64); - } - } - } - } -} - -impl ByteOrder for LittleEndian { - #[inline] - fn read_u16(buf: &[u8]) -> u16 { - u16::from_le_bytes(buf[..2].try_into().unwrap()) - } - - #[inline] - fn read_u32(buf: &[u8]) -> u32 { - u32::from_le_bytes(buf[..4].try_into().unwrap()) - } - - #[inline] - fn read_u64(buf: &[u8]) -> u64 { - u64::from_le_bytes(buf[..8].try_into().unwrap()) - } - - #[inline] - fn read_u128(buf: &[u8]) -> u128 { - u128::from_le_bytes(buf[..16].try_into().unwrap()) - } - - #[inline] - fn read_uint(buf: &[u8], nbytes: usize) -> u64 { - assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); - let mut out = 0u64; - let ptr_out = &mut out as *mut u64 as *mut u8; - unsafe { - copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); - } - out.to_le() - } - - #[inline] - fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { - assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); - let mut out: u128 = 0; - let ptr_out = &mut out as *mut u128 as *mut u8; - unsafe { - copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); - } - out.to_le() - } - - #[inline] - fn write_u16(buf: &mut [u8], n: u16) { - unsafe_write_num_bytes!(u16, 2, n, buf, to_le); - } - - #[inline] - fn write_u32(buf: &mut [u8], n: u32) { - unsafe_write_num_bytes!(u32, 4, n, buf, to_le); - } - - #[inline] - fn write_u64(buf: &mut [u8], n: u64) { - unsafe_write_num_bytes!(u64, 8, n, buf, to_le); - } - - #[inline] - fn write_u128(buf: &mut [u8], n: u128) { - unsafe_write_num_bytes!(u128, 16, n, buf, to_le); - } - - #[inline] - fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) { - assert!(pack_size(n as u64) <= nbytes && nbytes <= 8); - assert!(nbytes <= buf.len()); - unsafe { - let bytes = *(&n.to_le() as *const u64 as *const [u8; 8]); - copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes); - } - } - - #[inline] - fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) { - assert!(pack_size128(n as u128) <= nbytes && nbytes <= 16); - assert!(nbytes <= buf.len()); - unsafe { - let bytes = *(&n.to_le() as *const u128 as *const [u8; 16]); - copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes); - } - } - - #[inline] - fn read_u16_into(src: &[u8], dst: &mut [u16]) { - unsafe_read_slice!(src, dst, 2, to_le); - } - - #[inline] - fn read_u32_into(src: &[u8], dst: &mut [u32]) { - unsafe_read_slice!(src, dst, 4, to_le); - } - - #[inline] - fn read_u64_into(src: &[u8], dst: &mut [u64]) { - unsafe_read_slice!(src, dst, 8, to_le); - } - - #[inline] - fn read_u128_into(src: &[u8], dst: &mut [u128]) { - unsafe_read_slice!(src, dst, 16, to_le); - } - - #[inline] - fn write_u16_into(src: &[u16], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u16); - } else { - write_slice!(src, dst, u16, 2, Self::write_u16); - } - } - - #[inline] - fn write_u32_into(src: &[u32], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u32); - } else { - write_slice!(src, dst, u32, 4, Self::write_u32); - } - } - - #[inline] - fn write_u64_into(src: &[u64], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u64); - } else { - write_slice!(src, dst, u64, 8, Self::write_u64); - } - } - - #[inline] - fn write_u128_into(src: &[u128], dst: &mut [u8]) { - if cfg!(target_endian = "little") { - unsafe_write_slice_native!(src, dst, u128); - } else { - write_slice!(src, dst, u128, 16, Self::write_u128); - } - } - - #[inline] - fn from_slice_u16(numbers: &mut [u16]) { - if cfg!(target_endian = "big") { - for n in numbers { - *n = n.to_le(); - } - } - } - - #[inline] - fn from_slice_u32(numbers: &mut [u32]) { - if cfg!(target_endian = "big") { - for n in numbers { - *n = n.to_le(); - } - } - } - - #[inline] - fn from_slice_u64(numbers: &mut [u64]) { - if cfg!(target_endian = "big") { - for n in numbers { - *n = n.to_le(); - } - } - } - - #[inline] - fn from_slice_u128(numbers: &mut [u128]) { - if cfg!(target_endian = "big") { - for n in numbers { - *n = n.to_le(); - } - } - } - - #[inline] - fn from_slice_f32(numbers: &mut [f32]) { - if cfg!(target_endian = "big") { - for n in numbers { - unsafe { - let int = *(n as *const f32 as *const u32); - *n = *(&int.to_le() as *const u32 as *const f32); - } - } - } - } - - #[inline] - fn from_slice_f64(numbers: &mut [f64]) { - if cfg!(target_endian = "big") { - for n in numbers { - unsafe { - let int = *(n as *const f64 as *const u64); - *n = *(&int.to_le() as *const u64 as *const f64); - } - } - } - } -} - -#[cfg(test)] -mod test { - use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen, Testable}; - use rand::{thread_rng, Rng}; - - pub const U24_MAX: u32 = 16_777_215; - pub const I24_MAX: i32 = 8_388_607; - pub const U48_MAX: u64 = 281_474_976_710_655; - pub const I48_MAX: i64 = 140_737_488_355_327; - - pub const U64_MAX: u64 = ::core::u64::MAX; - pub const I64_MAX: u64 = ::core::i64::MAX as u64; - - macro_rules! calc_max { - ($max:expr, $bytes:expr) => { - calc_max!($max, $bytes, 8) - }; - ($max:expr, $bytes:expr, $maxbytes:expr) => { - ($max - 1) >> (8 * ($maxbytes - $bytes)) - }; - } - - #[derive(Clone, Debug)] - pub struct Wi128(pub T); - - impl Wi128 { - pub fn clone(&self) -> T { - self.0.clone() - } - } - - impl PartialEq for Wi128 { - fn eq(&self, other: &T) -> bool { - self.0.eq(other) - } - } - - impl Arbitrary for Wi128 { - fn arbitrary(gen: &mut G) -> Wi128 { - let max = calc_max!(::core::u128::MAX, gen.size(), 16); - let output = (gen.gen::() as u128) - | ((gen.gen::() as u128) << 64); - Wi128(output & (max - 1)) - } - } - - impl Arbitrary for Wi128 { - fn arbitrary(gen: &mut G) -> Wi128 { - let max = calc_max!(::core::i128::MAX, gen.size(), 16); - let output = (gen.gen::() as i128) - | ((gen.gen::() as i128) << 64); - Wi128(output & (max - 1)) - } - } - - pub fn qc_sized(f: A, size: u64) { - QuickCheck::new() - .gen(StdGen::new(thread_rng(), size as usize)) - .tests(1_00) - .max_tests(10_000) - .quickcheck(f); - } - - macro_rules! qc_byte_order { - ($name:ident, $ty_int:ty, $max:expr, - $bytes:expr, $read:ident, $write:ident) => { - mod $name { - #[allow(unused_imports)] - use super::{qc_sized, Wi128}; - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - - #[test] - fn big_endian() { - fn prop(n: $ty_int) -> bool { - let mut buf = [0; 16]; - BigEndian::$write(&mut buf, n.clone(), $bytes); - n == BigEndian::$read(&buf[..$bytes], $bytes) - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - - #[test] - fn little_endian() { - fn prop(n: $ty_int) -> bool { - let mut buf = [0; 16]; - LittleEndian::$write(&mut buf, n.clone(), $bytes); - n == LittleEndian::$read(&buf[..$bytes], $bytes) - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - - #[test] - fn native_endian() { - fn prop(n: $ty_int) -> bool { - let mut buf = [0; 16]; - NativeEndian::$write(&mut buf, n.clone(), $bytes); - n == NativeEndian::$read(&buf[..$bytes], $bytes) - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - } - }; - ($name:ident, $ty_int:ty, $max:expr, - $read:ident, $write:ident) => { - mod $name { - #[allow(unused_imports)] - use super::{qc_sized, Wi128}; - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - use core::mem::size_of; - - #[test] - fn big_endian() { - fn prop(n: $ty_int) -> bool { - let bytes = size_of::<$ty_int>(); - let mut buf = [0; 16]; - BigEndian::$write(&mut buf[16 - bytes..], n.clone()); - n == BigEndian::$read(&buf[16 - bytes..]) - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - - #[test] - fn little_endian() { - fn prop(n: $ty_int) -> bool { - let bytes = size_of::<$ty_int>(); - let mut buf = [0; 16]; - LittleEndian::$write(&mut buf[..bytes], n.clone()); - n == LittleEndian::$read(&buf[..bytes]) - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - - #[test] - fn native_endian() { - fn prop(n: $ty_int) -> bool { - let bytes = size_of::<$ty_int>(); - let mut buf = [0; 16]; - NativeEndian::$write(&mut buf[..bytes], n.clone()); - n == NativeEndian::$read(&buf[..bytes]) - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - } - }; - } - - qc_byte_order!( - prop_u16, - u16, - ::core::u16::MAX as u64, - read_u16, - write_u16 - ); - qc_byte_order!( - prop_i16, - i16, - ::core::i16::MAX as u64, - read_i16, - write_i16 - ); - qc_byte_order!( - prop_u24, - u32, - crate::test::U24_MAX as u64, - read_u24, - write_u24 - ); - qc_byte_order!( - prop_i24, - i32, - crate::test::I24_MAX as u64, - read_i24, - write_i24 - ); - qc_byte_order!( - prop_u32, - u32, - ::core::u32::MAX as u64, - read_u32, - write_u32 - ); - qc_byte_order!( - prop_i32, - i32, - ::core::i32::MAX as u64, - read_i32, - write_i32 - ); - qc_byte_order!( - prop_u48, - u64, - crate::test::U48_MAX as u64, - read_u48, - write_u48 - ); - qc_byte_order!( - prop_i48, - i64, - crate::test::I48_MAX as u64, - read_i48, - write_i48 - ); - qc_byte_order!( - prop_u64, - u64, - ::core::u64::MAX as u64, - read_u64, - write_u64 - ); - qc_byte_order!( - prop_i64, - i64, - ::core::i64::MAX as u64, - read_i64, - write_i64 - ); - qc_byte_order!( - prop_f32, - f32, - ::core::u64::MAX as u64, - read_f32, - write_f32 - ); - qc_byte_order!( - prop_f64, - f64, - ::core::i64::MAX as u64, - read_f64, - write_f64 - ); - - qc_byte_order!(prop_u128, Wi128, 16 + 1, read_u128, write_u128); - qc_byte_order!(prop_i128, Wi128, 16 + 1, read_i128, write_i128); - - qc_byte_order!( - prop_uint_1, - u64, - calc_max!(super::U64_MAX, 1), - 1, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_2, - u64, - calc_max!(super::U64_MAX, 2), - 2, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_3, - u64, - calc_max!(super::U64_MAX, 3), - 3, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_4, - u64, - calc_max!(super::U64_MAX, 4), - 4, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_5, - u64, - calc_max!(super::U64_MAX, 5), - 5, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_6, - u64, - calc_max!(super::U64_MAX, 6), - 6, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_7, - u64, - calc_max!(super::U64_MAX, 7), - 7, - read_uint, - write_uint - ); - qc_byte_order!( - prop_uint_8, - u64, - calc_max!(super::U64_MAX, 8), - 8, - read_uint, - write_uint - ); - - qc_byte_order!( - prop_uint128_1, - Wi128, - 1, - 1, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_2, - Wi128, - 2, - 2, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_3, - Wi128, - 3, - 3, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_4, - Wi128, - 4, - 4, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_5, - Wi128, - 5, - 5, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_6, - Wi128, - 6, - 6, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_7, - Wi128, - 7, - 7, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_8, - Wi128, - 8, - 8, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_9, - Wi128, - 9, - 9, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_10, - Wi128, - 10, - 10, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_11, - Wi128, - 11, - 11, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_12, - Wi128, - 12, - 12, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_13, - Wi128, - 13, - 13, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_14, - Wi128, - 14, - 14, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_15, - Wi128, - 15, - 15, - read_uint128, - write_uint128 - ); - qc_byte_order!( - prop_uint128_16, - Wi128, - 16, - 16, - read_uint128, - write_uint128 - ); - - qc_byte_order!( - prop_int_1, - i64, - calc_max!(super::I64_MAX, 1), - 1, - read_int, - write_int - ); - qc_byte_order!( - prop_int_2, - i64, - calc_max!(super::I64_MAX, 2), - 2, - read_int, - write_int - ); - qc_byte_order!( - prop_int_3, - i64, - calc_max!(super::I64_MAX, 3), - 3, - read_int, - write_int - ); - qc_byte_order!( - prop_int_4, - i64, - calc_max!(super::I64_MAX, 4), - 4, - read_int, - write_int - ); - qc_byte_order!( - prop_int_5, - i64, - calc_max!(super::I64_MAX, 5), - 5, - read_int, - write_int - ); - qc_byte_order!( - prop_int_6, - i64, - calc_max!(super::I64_MAX, 6), - 6, - read_int, - write_int - ); - qc_byte_order!( - prop_int_7, - i64, - calc_max!(super::I64_MAX, 7), - 7, - read_int, - write_int - ); - qc_byte_order!( - prop_int_8, - i64, - calc_max!(super::I64_MAX, 8), - 8, - read_int, - write_int - ); - - qc_byte_order!( - prop_int128_1, - Wi128, - 1, - 1, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_2, - Wi128, - 2, - 2, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_3, - Wi128, - 3, - 3, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_4, - Wi128, - 4, - 4, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_5, - Wi128, - 5, - 5, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_6, - Wi128, - 6, - 6, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_7, - Wi128, - 7, - 7, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_8, - Wi128, - 8, - 8, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_9, - Wi128, - 9, - 9, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_10, - Wi128, - 10, - 10, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_11, - Wi128, - 11, - 11, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_12, - Wi128, - 12, - 12, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_13, - Wi128, - 13, - 13, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_14, - Wi128, - 14, - 14, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_15, - Wi128, - 15, - 15, - read_int128, - write_int128 - ); - qc_byte_order!( - prop_int128_16, - Wi128, - 16, - 16, - read_int128, - write_int128 - ); - - // Test that all of the byte conversion functions panic when given a - // buffer that is too small. - // - // These tests are critical to ensure safety, otherwise we might end up - // with a buffer overflow. - macro_rules! too_small { - ($name:ident, $maximally_small:expr, $zero:expr, - $read:ident, $write:ident) => { - mod $name { - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - - #[test] - #[should_panic] - fn read_big_endian() { - let buf = [0; $maximally_small]; - BigEndian::$read(&buf); - } - - #[test] - #[should_panic] - fn read_little_endian() { - let buf = [0; $maximally_small]; - LittleEndian::$read(&buf); - } - - #[test] - #[should_panic] - fn read_native_endian() { - let buf = [0; $maximally_small]; - NativeEndian::$read(&buf); - } - - #[test] - #[should_panic] - fn write_big_endian() { - let mut buf = [0; $maximally_small]; - BigEndian::$write(&mut buf, $zero); - } - - #[test] - #[should_panic] - fn write_little_endian() { - let mut buf = [0; $maximally_small]; - LittleEndian::$write(&mut buf, $zero); - } - - #[test] - #[should_panic] - fn write_native_endian() { - let mut buf = [0; $maximally_small]; - NativeEndian::$write(&mut buf, $zero); - } - } - }; - ($name:ident, $maximally_small:expr, $read:ident) => { - mod $name { - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - - #[test] - #[should_panic] - fn read_big_endian() { - let buf = [0; $maximally_small]; - BigEndian::$read(&buf, $maximally_small + 1); - } - - #[test] - #[should_panic] - fn read_little_endian() { - let buf = [0; $maximally_small]; - LittleEndian::$read(&buf, $maximally_small + 1); - } - - #[test] - #[should_panic] - fn read_native_endian() { - let buf = [0; $maximally_small]; - NativeEndian::$read(&buf, $maximally_small + 1); - } - } - }; - } - - too_small!(small_u16, 1, 0, read_u16, write_u16); - too_small!(small_i16, 1, 0, read_i16, write_i16); - too_small!(small_u32, 3, 0, read_u32, write_u32); - too_small!(small_i32, 3, 0, read_i32, write_i32); - too_small!(small_u64, 7, 0, read_u64, write_u64); - too_small!(small_i64, 7, 0, read_i64, write_i64); - too_small!(small_f32, 3, 0.0, read_f32, write_f32); - too_small!(small_f64, 7, 0.0, read_f64, write_f64); - too_small!(small_u128, 15, 0, read_u128, write_u128); - too_small!(small_i128, 15, 0, read_i128, write_i128); - - too_small!(small_uint_1, 1, read_uint); - too_small!(small_uint_2, 2, read_uint); - too_small!(small_uint_3, 3, read_uint); - too_small!(small_uint_4, 4, read_uint); - too_small!(small_uint_5, 5, read_uint); - too_small!(small_uint_6, 6, read_uint); - too_small!(small_uint_7, 7, read_uint); - - too_small!(small_uint128_1, 1, read_uint128); - too_small!(small_uint128_2, 2, read_uint128); - too_small!(small_uint128_3, 3, read_uint128); - too_small!(small_uint128_4, 4, read_uint128); - too_small!(small_uint128_5, 5, read_uint128); - too_small!(small_uint128_6, 6, read_uint128); - too_small!(small_uint128_7, 7, read_uint128); - too_small!(small_uint128_8, 8, read_uint128); - too_small!(small_uint128_9, 9, read_uint128); - too_small!(small_uint128_10, 10, read_uint128); - too_small!(small_uint128_11, 11, read_uint128); - too_small!(small_uint128_12, 12, read_uint128); - too_small!(small_uint128_13, 13, read_uint128); - too_small!(small_uint128_14, 14, read_uint128); - too_small!(small_uint128_15, 15, read_uint128); - - too_small!(small_int_1, 1, read_int); - too_small!(small_int_2, 2, read_int); - too_small!(small_int_3, 3, read_int); - too_small!(small_int_4, 4, read_int); - too_small!(small_int_5, 5, read_int); - too_small!(small_int_6, 6, read_int); - too_small!(small_int_7, 7, read_int); - - too_small!(small_int128_1, 1, read_int128); - too_small!(small_int128_2, 2, read_int128); - too_small!(small_int128_3, 3, read_int128); - too_small!(small_int128_4, 4, read_int128); - too_small!(small_int128_5, 5, read_int128); - too_small!(small_int128_6, 6, read_int128); - too_small!(small_int128_7, 7, read_int128); - too_small!(small_int128_8, 8, read_int128); - too_small!(small_int128_9, 9, read_int128); - too_small!(small_int128_10, 10, read_int128); - too_small!(small_int128_11, 11, read_int128); - too_small!(small_int128_12, 12, read_int128); - too_small!(small_int128_13, 13, read_int128); - too_small!(small_int128_14, 14, read_int128); - too_small!(small_int128_15, 15, read_int128); - - // Test that reading/writing slices enforces the correct lengths. - macro_rules! slice_lengths { - ($name:ident, $read:ident, $write:ident, - $num_bytes:expr, $numbers:expr) => { - mod $name { - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - - #[test] - #[should_panic] - fn read_big_endian() { - let bytes = [0; $num_bytes]; - let mut numbers = $numbers; - BigEndian::$read(&bytes, &mut numbers); - } - - #[test] - #[should_panic] - fn read_little_endian() { - let bytes = [0; $num_bytes]; - let mut numbers = $numbers; - LittleEndian::$read(&bytes, &mut numbers); - } - - #[test] - #[should_panic] - fn read_native_endian() { - let bytes = [0; $num_bytes]; - let mut numbers = $numbers; - NativeEndian::$read(&bytes, &mut numbers); - } - - #[test] - #[should_panic] - fn write_big_endian() { - let mut bytes = [0; $num_bytes]; - let numbers = $numbers; - BigEndian::$write(&numbers, &mut bytes); - } - - #[test] - #[should_panic] - fn write_little_endian() { - let mut bytes = [0; $num_bytes]; - let numbers = $numbers; - LittleEndian::$write(&numbers, &mut bytes); - } - - #[test] - #[should_panic] - fn write_native_endian() { - let mut bytes = [0; $num_bytes]; - let numbers = $numbers; - NativeEndian::$write(&numbers, &mut bytes); - } - } - }; - } - - slice_lengths!( - slice_len_too_small_u16, - read_u16_into, - write_u16_into, - 3, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_u16, - read_u16_into, - write_u16_into, - 5, - [0, 0] - ); - slice_lengths!( - slice_len_too_small_i16, - read_i16_into, - write_i16_into, - 3, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_i16, - read_i16_into, - write_i16_into, - 5, - [0, 0] - ); - - slice_lengths!( - slice_len_too_small_u32, - read_u32_into, - write_u32_into, - 7, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_u32, - read_u32_into, - write_u32_into, - 9, - [0, 0] - ); - slice_lengths!( - slice_len_too_small_i32, - read_i32_into, - write_i32_into, - 7, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_i32, - read_i32_into, - write_i32_into, - 9, - [0, 0] - ); - - slice_lengths!( - slice_len_too_small_u64, - read_u64_into, - write_u64_into, - 15, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_u64, - read_u64_into, - write_u64_into, - 17, - [0, 0] - ); - slice_lengths!( - slice_len_too_small_i64, - read_i64_into, - write_i64_into, - 15, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_i64, - read_i64_into, - write_i64_into, - 17, - [0, 0] - ); - - slice_lengths!( - slice_len_too_small_u128, - read_u128_into, - write_u128_into, - 31, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_u128, - read_u128_into, - write_u128_into, - 33, - [0, 0] - ); - slice_lengths!( - slice_len_too_small_i128, - read_i128_into, - write_i128_into, - 31, - [0, 0] - ); - slice_lengths!( - slice_len_too_big_i128, - read_i128_into, - write_i128_into, - 33, - [0, 0] - ); - - #[test] - fn uint_bigger_buffer() { - use crate::{ByteOrder, LittleEndian}; - let n = LittleEndian::read_uint(&[1, 2, 3, 4, 5, 6, 7, 8], 5); - assert_eq!(n, 0x05_0403_0201); - } - - #[test] - fn regression173_array_impl() { - use crate::{BigEndian, ByteOrder, LittleEndian}; - - let xs = [0; 100]; - - let x = BigEndian::read_u16(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_u32(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_u64(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_u128(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_i16(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_i32(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_i64(&xs); - assert_eq!(x, 0); - let x = BigEndian::read_i128(&xs); - assert_eq!(x, 0); - - let x = LittleEndian::read_u16(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_u32(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_u64(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_u128(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_i16(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_i32(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_i64(&xs); - assert_eq!(x, 0); - let x = LittleEndian::read_i128(&xs); - assert_eq!(x, 0); - } -} - -#[cfg(test)] -#[cfg(feature = "std")] -mod stdtests { - extern crate quickcheck; - extern crate rand; - - use self::quickcheck::{QuickCheck, StdGen, Testable}; - use self::rand::thread_rng; - - fn qc_unsized(f: A) { - QuickCheck::new() - .gen(StdGen::new(thread_rng(), 16)) - .tests(1_00) - .max_tests(10_000) - .quickcheck(f); - } - - macro_rules! calc_max { - ($max:expr, $bytes:expr) => { - ($max - 1) >> (8 * (8 - $bytes)) - }; - } - - macro_rules! qc_bytes_ext { - ($name:ident, $ty_int:ty, $max:expr, - $bytes:expr, $read:ident, $write:ident) => { - mod $name { - #[allow(unused_imports)] - use crate::test::{qc_sized, Wi128}; - use crate::{ - BigEndian, LittleEndian, NativeEndian, ReadBytesExt, - WriteBytesExt, - }; - use std::io::Cursor; - - #[test] - fn big_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let offset = wtr.len() - $bytes; - let mut rdr = Cursor::new(&mut wtr[offset..]); - n == rdr.$read::($bytes).unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - - #[test] - fn little_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let mut rdr = Cursor::new(wtr); - n == rdr.$read::($bytes).unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - - #[test] - fn native_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let offset = if cfg!(target_endian = "big") { - wtr.len() - $bytes - } else { - 0 - }; - let mut rdr = Cursor::new(&mut wtr[offset..]); - n == rdr.$read::($bytes).unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max); - } - } - }; - ($name:ident, $ty_int:ty, $max:expr, $read:ident, $write:ident) => { - mod $name { - #[allow(unused_imports)] - use crate::test::{qc_sized, Wi128}; - use crate::{ - BigEndian, LittleEndian, NativeEndian, ReadBytesExt, - WriteBytesExt, - }; - use std::io::Cursor; - - #[test] - fn big_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let mut rdr = Cursor::new(wtr); - n == rdr.$read::().unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - - #[test] - fn little_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let mut rdr = Cursor::new(wtr); - n == rdr.$read::().unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - - #[test] - fn native_endian() { - fn prop(n: $ty_int) -> bool { - let mut wtr = vec![]; - wtr.$write::(n.clone()).unwrap(); - let mut rdr = Cursor::new(wtr); - n == rdr.$read::().unwrap() - } - qc_sized(prop as fn($ty_int) -> bool, $max - 1); - } - } - }; - } - - qc_bytes_ext!( - prop_ext_u16, - u16, - ::std::u16::MAX as u64, - read_u16, - write_u16 - ); - qc_bytes_ext!( - prop_ext_i16, - i16, - ::std::i16::MAX as u64, - read_i16, - write_i16 - ); - qc_bytes_ext!( - prop_ext_u32, - u32, - ::std::u32::MAX as u64, - read_u32, - write_u32 - ); - qc_bytes_ext!( - prop_ext_i32, - i32, - ::std::i32::MAX as u64, - read_i32, - write_i32 - ); - qc_bytes_ext!( - prop_ext_u64, - u64, - ::std::u64::MAX as u64, - read_u64, - write_u64 - ); - qc_bytes_ext!( - prop_ext_i64, - i64, - ::std::i64::MAX as u64, - read_i64, - write_i64 - ); - qc_bytes_ext!( - prop_ext_f32, - f32, - ::std::u64::MAX as u64, - read_f32, - write_f32 - ); - qc_bytes_ext!( - prop_ext_f64, - f64, - ::std::i64::MAX as u64, - read_f64, - write_f64 - ); - - qc_bytes_ext!(prop_ext_u128, Wi128, 16 + 1, read_u128, write_u128); - qc_bytes_ext!(prop_ext_i128, Wi128, 16 + 1, read_i128, write_i128); - - qc_bytes_ext!( - prop_ext_uint_1, - u64, - calc_max!(crate::test::U64_MAX, 1), - 1, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_2, - u64, - calc_max!(crate::test::U64_MAX, 2), - 2, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_3, - u64, - calc_max!(crate::test::U64_MAX, 3), - 3, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_4, - u64, - calc_max!(crate::test::U64_MAX, 4), - 4, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_5, - u64, - calc_max!(crate::test::U64_MAX, 5), - 5, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_6, - u64, - calc_max!(crate::test::U64_MAX, 6), - 6, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_7, - u64, - calc_max!(crate::test::U64_MAX, 7), - 7, - read_uint, - write_u64 - ); - qc_bytes_ext!( - prop_ext_uint_8, - u64, - calc_max!(crate::test::U64_MAX, 8), - 8, - read_uint, - write_u64 - ); - - qc_bytes_ext!( - prop_ext_uint128_1, - Wi128, - 1, - 1, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_2, - Wi128, - 2, - 2, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_3, - Wi128, - 3, - 3, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_4, - Wi128, - 4, - 4, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_5, - Wi128, - 5, - 5, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_6, - Wi128, - 6, - 6, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_7, - Wi128, - 7, - 7, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_8, - Wi128, - 8, - 8, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_9, - Wi128, - 9, - 9, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_10, - Wi128, - 10, - 10, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_11, - Wi128, - 11, - 11, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_12, - Wi128, - 12, - 12, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_13, - Wi128, - 13, - 13, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_14, - Wi128, - 14, - 14, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_15, - Wi128, - 15, - 15, - read_uint128, - write_u128 - ); - qc_bytes_ext!( - prop_ext_uint128_16, - Wi128, - 16, - 16, - read_uint128, - write_u128 - ); - - qc_bytes_ext!( - prop_ext_int_1, - i64, - calc_max!(crate::test::I64_MAX, 1), - 1, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_2, - i64, - calc_max!(crate::test::I64_MAX, 2), - 2, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_3, - i64, - calc_max!(crate::test::I64_MAX, 3), - 3, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_4, - i64, - calc_max!(crate::test::I64_MAX, 4), - 4, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_5, - i64, - calc_max!(crate::test::I64_MAX, 5), - 5, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_6, - i64, - calc_max!(crate::test::I64_MAX, 6), - 6, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_7, - i64, - calc_max!(crate::test::I64_MAX, 1), - 7, - read_int, - write_i64 - ); - qc_bytes_ext!( - prop_ext_int_8, - i64, - calc_max!(crate::test::I64_MAX, 8), - 8, - read_int, - write_i64 - ); - - qc_bytes_ext!( - prop_ext_int128_1, - Wi128, - 1, - 1, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_2, - Wi128, - 2, - 2, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_3, - Wi128, - 3, - 3, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_4, - Wi128, - 4, - 4, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_5, - Wi128, - 5, - 5, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_6, - Wi128, - 6, - 6, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_7, - Wi128, - 7, - 7, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_8, - Wi128, - 8, - 8, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_9, - Wi128, - 9, - 9, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_10, - Wi128, - 10, - 10, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_11, - Wi128, - 11, - 11, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_12, - Wi128, - 12, - 12, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_13, - Wi128, - 13, - 13, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_14, - Wi128, - 14, - 14, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_15, - Wi128, - 15, - 15, - read_int128, - write_i128 - ); - qc_bytes_ext!( - prop_ext_int128_16, - Wi128, - 16, - 16, - read_int128, - write_i128 - ); - - // Test slice serialization/deserialization. - macro_rules! qc_slice { - ($name:ident, $ty_int:ty, $read:ident, $write:ident, $zero:expr) => { - mod $name { - use super::qc_unsized; - #[allow(unused_imports)] - use crate::test::Wi128; - use crate::{ - BigEndian, ByteOrder, LittleEndian, NativeEndian, - }; - use core::mem::size_of; - - #[test] - fn big_endian() { - #[allow(unused_unsafe)] - fn prop(numbers: Vec<$ty_int>) -> bool { - let numbers: Vec<_> = - numbers.into_iter().map(|x| x.clone()).collect(); - let num_bytes = size_of::<$ty_int>() * numbers.len(); - let mut bytes = vec![0; num_bytes]; - - BigEndian::$write(&numbers, &mut bytes); - - let mut got = vec![$zero; numbers.len()]; - unsafe { - BigEndian::$read(&bytes, &mut got); - } - - numbers == got - } - qc_unsized(prop as fn(_) -> bool); - } - - #[test] - fn little_endian() { - #[allow(unused_unsafe)] - fn prop(numbers: Vec<$ty_int>) -> bool { - let numbers: Vec<_> = - numbers.into_iter().map(|x| x.clone()).collect(); - let num_bytes = size_of::<$ty_int>() * numbers.len(); - let mut bytes = vec![0; num_bytes]; - - LittleEndian::$write(&numbers, &mut bytes); - - let mut got = vec![$zero; numbers.len()]; - unsafe { - LittleEndian::$read(&bytes, &mut got); - } - - numbers == got - } - qc_unsized(prop as fn(_) -> bool); - } - - #[test] - fn native_endian() { - #[allow(unused_unsafe)] - fn prop(numbers: Vec<$ty_int>) -> bool { - let numbers: Vec<_> = - numbers.into_iter().map(|x| x.clone()).collect(); - let num_bytes = size_of::<$ty_int>() * numbers.len(); - let mut bytes = vec![0; num_bytes]; - - NativeEndian::$write(&numbers, &mut bytes); - - let mut got = vec![$zero; numbers.len()]; - unsafe { - NativeEndian::$read(&bytes, &mut got); - } - - numbers == got - } - qc_unsized(prop as fn(_) -> bool); - } - } - }; - } - - qc_slice!(prop_slice_u16, u16, read_u16_into, write_u16_into, 0); - qc_slice!(prop_slice_i16, i16, read_i16_into, write_i16_into, 0); - qc_slice!(prop_slice_u32, u32, read_u32_into, write_u32_into, 0); - qc_slice!(prop_slice_i32, i32, read_i32_into, write_i32_into, 0); - qc_slice!(prop_slice_u64, u64, read_u64_into, write_u64_into, 0); - qc_slice!(prop_slice_i64, i64, read_i64_into, write_i64_into, 0); - qc_slice!( - prop_slice_u128, - Wi128, - read_u128_into, - write_u128_into, - 0 - ); - qc_slice!( - prop_slice_i128, - Wi128, - read_i128_into, - write_i128_into, - 0 - ); - - qc_slice!(prop_slice_f32, f32, read_f32_into, write_f32_into, 0.0); - qc_slice!(prop_slice_f64, f64, read_f64_into, write_f64_into, 0.0); -} diff --git a/vendor/camino/.cargo-checksum.json b/vendor/camino/.cargo-checksum.json index 1de1f0c97..81a1f0f60 100644 --- a/vendor/camino/.cargo-checksum.json +++ b/vendor/camino/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"886087c5abaa1078e179e173b997fd4bffd93e47b2914defd8148f3f396e98f0","CODE_OF_CONDUCT.md":"f51e207c2961ec061cac5c8aa9dd3098c3437de2c106d740c2aae90771bc0f86","Cargo.toml":"17bc7f765ef82a295aff4292261d23dc0c6c75b44e6c3016631cc087d5fe20f6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"84762d717d0f2358c56f54ee46a6ca5f1582b7d3843f7a4d6e553ea04a57ca1b","build.rs":"4e46d73efd79ec269ddc1b2578cad051c66195225bfdf012e4ed430f9f98a3ab","clippy.toml":"818cba7332cc56b019d59e09805a3498f523da788f51454742905f1987c0b563","rustfmt.toml":"bf9776adb152b3fdc0d75c0929ede148c3e28c58f909a7d052865bc332e8958f","src/lib.rs":"a59a425a4bf1e2ae8f16bc0349fadf0fe3f7ec2effa44137bd59e17c3ff15456","src/proptest_impls.rs":"aa17bad810abe4a7b6c7a2c3163ae9749b03dd8bcef5043b0c4b9d00977f981c","src/serde_impls.rs":"eb7f00d1ceb7135506047dbefd7e6acee0364b5a9194111f49dbf2d1eb3661ac","src/tests.rs":"d6108c540dc93446b17d297b50372f799ef777c2cb0280fd37824a102ec24533","tests/integration_tests.rs":"b664a7555d2e5ac9ab71384e3ccfb73c01abe4c401f8de32e234c03b4d19d0f8"},"package":"869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"} \ No newline at end of file +{"files":{"CHANGELOG.md":"2530b12d7ddf3395bbc4c10557e57531498039ba28528b91ffc3f3deefc76f77","CODE_OF_CONDUCT.md":"f51e207c2961ec061cac5c8aa9dd3098c3437de2c106d740c2aae90771bc0f86","Cargo.toml":"7bf7de17ab10cd95aadf102f37c0b8a58f0c31f90cfeee81126ead8ad3cb0a26","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"84762d717d0f2358c56f54ee46a6ca5f1582b7d3843f7a4d6e553ea04a57ca1b","build.rs":"ca6914ad35e69842b6fba6e436d0417f39dbe6ee18694d4dd89b372d31cbf715","clippy.toml":"818cba7332cc56b019d59e09805a3498f523da788f51454742905f1987c0b563","rustfmt.toml":"bf9776adb152b3fdc0d75c0929ede148c3e28c58f909a7d052865bc332e8958f","src/lib.rs":"3a744ca7df473bb8bd97e1f4a961d517cb7379b8756e38893dd9d53a169c41e1","src/proptest_impls.rs":"aa17bad810abe4a7b6c7a2c3163ae9749b03dd8bcef5043b0c4b9d00977f981c","src/serde_impls.rs":"eb7f00d1ceb7135506047dbefd7e6acee0364b5a9194111f49dbf2d1eb3661ac","src/tests.rs":"d6108c540dc93446b17d297b50372f799ef777c2cb0280fd37824a102ec24533","tests/integration_tests.rs":"b664a7555d2e5ac9ab71384e3ccfb73c01abe4c401f8de32e234c03b4d19d0f8"},"package":"88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"} \ No newline at end of file diff --git a/vendor/camino/CHANGELOG.md b/vendor/camino/CHANGELOG.md index b9a04de7a..67c2ea8d3 100644 --- a/vendor/camino/CHANGELOG.md +++ b/vendor/camino/CHANGELOG.md @@ -3,6 +3,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.1] - 2022-08-12 + +### Fixed + +- Fixed a build regression on older nightlies in the 1.63 series + ([#22](https://github.com/camino-rs/camino/issues/22)). +- Documentation fixes. + +## [1.1.0] - 2022-08-11 + +### Added + +- New methods, mirroring those in recent versions of Rust: + - `Utf8Path::try_exists` checks whether a path exists. Note that while `std::path::Path` only provides this method for Rust 1.58 and above, `camino` backfills the method for all Rust versions it supports. + - `Utf8PathBuf::shrink_to` shrinks a `Utf8PathBuf` to a given size. This was added in, and is gated on, Rust 1.56+. + - `Utf8PathBuf::try_reserve` and `Utf8PathBuf::try_reserve_exact` implement fallible allocations. These were added in, and are gated on, Rust 1.63+. +- A number of `#[must_use]` annotations to APIs, mirroring those added to `Path` and `PathBuf` in recent versions of Rust. The minor version bump is due to this change. + ## [1.0.9] - 2022-05-19 ### Fixed @@ -24,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `Utf8Path::is_symlink` checks whether a path is a symlink. Note that while `std::path::Path` only - provides this method for version 1.58 and above, `camino` polyfills the method for all Rust versions + provides this method for version 1.58 and above, `camino` backfills the method for all Rust versions it supports. ### Changed @@ -83,6 +101,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Initial release. +[1.1.1]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.1 +[1.1.0]: https://github.com/camino-rs/camino/releases/tag/camino-1.1.0 [1.0.9]: https://github.com/camino-rs/camino/releases/tag/camino-1.0.9 [1.0.8]: https://github.com/camino-rs/camino/releases/tag/camino-1.0.8 [1.0.7]: https://github.com/camino-rs/camino/releases/tag/camino-1.0.7 diff --git a/vendor/camino/Cargo.toml b/vendor/camino/Cargo.toml index cd2bd9fea..28c007855 100644 --- a/vendor/camino/Cargo.toml +++ b/vendor/camino/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "camino" -version = "1.0.9" +version = "1.1.1" authors = [ "Without Boats ", "Ashley Williams ", diff --git a/vendor/camino/build.rs b/vendor/camino/build.rs index bc3e4480d..7f5cbdf9b 100644 --- a/vendor/camino/build.rs +++ b/vendor/camino/build.rs @@ -21,10 +21,28 @@ fn main() { if compiler.minor >= 44 { println!("cargo:rustc-cfg=path_buf_capacity"); } + if compiler.minor >= 56 { + println!("cargo:rustc-cfg=shrink_to"); + } + // Stable and beta 1.63 have a stable try_reserve_2. + if (compiler.minor >= 63 + && (compiler.channel == ReleaseChannel::Stable || compiler.channel == ReleaseChannel::Beta)) + || compiler.minor >= 64 + { + println!("cargo:rustc-cfg=try_reserve_2"); + } } struct Compiler { minor: u32, + channel: ReleaseChannel, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum ReleaseChannel { + Stable, + Beta, + Nightly, } fn rustc_version() -> Option { @@ -36,5 +54,12 @@ fn rustc_version() -> Option { return None; } let minor = pieces.next()?.parse().ok()?; - Some(Compiler { minor }) + let channel = if version.contains("nightly") { + ReleaseChannel::Nightly + } else if version.contains("beta") { + ReleaseChannel::Beta + } else { + ReleaseChannel::Stable + }; + Some(Compiler { minor, channel }) } diff --git a/vendor/camino/src/lib.rs b/vendor/camino/src/lib.rs index 4a1b6dfd7..fcfba3805 100644 --- a/vendor/camino/src/lib.rs +++ b/vendor/camino/src/lib.rs @@ -120,6 +120,7 @@ impl Utf8PathBuf { /// /// let path = Utf8PathBuf::new(); /// ``` + #[must_use] pub fn new() -> Utf8PathBuf { Utf8PathBuf(PathBuf::new()) } @@ -177,6 +178,7 @@ impl Utf8PathBuf { /// let new_utf8_path_buf = Utf8PathBuf::from_path_buf(std_path_buf).unwrap(); /// assert_eq!(new_utf8_path_buf, "foo.txt"); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_std_path_buf(self) -> PathBuf { self.into() } @@ -202,6 +204,7 @@ impl Utf8PathBuf { /// /// [`with_capacity`]: PathBuf::with_capacity #[cfg(path_buf_capacity)] + #[must_use] pub fn with_capacity(capacity: usize) -> Utf8PathBuf { Utf8PathBuf(PathBuf::with_capacity(capacity)) } @@ -216,6 +219,7 @@ impl Utf8PathBuf { /// let p = Utf8PathBuf::from("/test"); /// assert_eq!(Utf8Path::new("/test"), p.as_path()); /// ``` + #[must_use] pub fn as_path(&self) -> &Utf8Path { // SAFETY: every Utf8PathBuf constructor ensures that self is valid UTF-8 unsafe { Utf8Path::assume_utf8(&*self.0) } @@ -347,6 +351,7 @@ impl Utf8PathBuf { /// let s = p.into_string(); /// assert_eq!(s, "/the/head"); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_string(self) -> String { self.into_os_string().into_string().unwrap() } @@ -363,11 +368,13 @@ impl Utf8PathBuf { /// let s = p.into_os_string(); /// assert_eq!(s, OsStr::new("/the/head")); /// ``` + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_os_string(self) -> OsString { self.0.into_os_string() } /// Converts this `Utf8PathBuf` into a [boxed](Box) [`Utf8Path`]. + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_boxed_path(self) -> Box { let ptr = Box::into_raw(self.0.into_boxed_path()) as *mut Utf8Path; // SAFETY: @@ -384,6 +391,7 @@ impl Utf8PathBuf { /// /// [`capacity`]: PathBuf::capacity #[cfg(path_buf_capacity)] + #[must_use] pub fn capacity(&self) -> usize { self.0.capacity() } @@ -408,6 +416,20 @@ impl Utf8PathBuf { self.0.reserve(additional) } + /// Invokes [`try_reserve`] on the underlying instance of [`PathBuf`]. + /// + /// *Requires Rust 1.63 or newer.* + /// + /// [`try_reserve`]: PathBuf::try_reserve + #[cfg(try_reserve_2)] + #[inline] + pub fn try_reserve( + &mut self, + additional: usize, + ) -> Result<(), std::collections::TryReserveError> { + self.0.try_reserve(additional) + } + /// Invokes [`reserve_exact`] on the underlying instance of [`PathBuf`]. /// /// *Requires Rust 1.44 or newer.* @@ -418,6 +440,20 @@ impl Utf8PathBuf { self.0.reserve_exact(additional) } + /// Invokes [`try_reserve_exact`] on the underlying instance of [`PathBuf`]. + /// + /// *Requires Rust 1.63 or newer.* + /// + /// [`try_reserve_exact`]: PathBuf::try_reserve_exact + #[cfg(try_reserve_2)] + #[inline] + pub fn try_reserve_exact( + &mut self, + additional: usize, + ) -> Result<(), std::collections::TryReserveError> { + self.0.try_reserve_exact(additional) + } + /// Invokes [`shrink_to_fit`] on the underlying instance of [`PathBuf`]. /// /// *Requires Rust 1.44 or newer.* @@ -427,6 +463,17 @@ impl Utf8PathBuf { pub fn shrink_to_fit(&mut self) { self.0.shrink_to_fit() } + + /// Invokes [`shrink_to`] on the underlying instance of [`PathBuf`]. + /// + /// *Requires Rust 1.56 or newer.* + /// + /// [`shrink_to`]: PathBuf::shrink_to + #[cfg(shrink_to)] + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.0.shrink_to(min_capacity) + } } impl Deref for Utf8PathBuf { @@ -586,6 +633,7 @@ impl Utf8Path { /// ``` /// /// [`str`]: str + #[must_use] pub fn as_str(&self) -> &str { // SAFETY: every Utf8Path constructor ensures that self is valid UTF-8 unsafe { assume_utf8(self.as_os_str()) } @@ -601,6 +649,7 @@ impl Utf8Path { /// let os_str = Utf8Path::new("foo.txt").as_os_str(); /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); /// ``` + #[must_use] pub fn as_os_str(&self) -> &OsStr { self.0.as_os_str() } @@ -615,6 +664,8 @@ impl Utf8Path { /// let path_buf = Utf8Path::new("foo.txt").to_path_buf(); /// assert_eq!(path_buf, Utf8PathBuf::from("foo.txt")); /// ``` + #[must_use = "this returns the result of the operation, \ + without modifying the original"] pub fn to_path_buf(&self) -> Utf8PathBuf { Utf8PathBuf(self.0.to_path_buf()) } @@ -637,6 +688,7 @@ impl Utf8Path { /// ``` /// /// [`has_root`]: Utf8Path::has_root + #[must_use] pub fn is_absolute(&self) -> bool { self.0.is_absolute() } @@ -654,6 +706,7 @@ impl Utf8Path { /// ``` /// /// [`is_absolute`]: Utf8Path::is_absolute + #[must_use] pub fn is_relative(&self) -> bool { self.0.is_relative() } @@ -674,6 +727,7 @@ impl Utf8Path { /// /// assert!(Utf8Path::new("/etc/passwd").has_root()); /// ``` + #[must_use] pub fn has_root(&self) -> bool { self.0.has_root() } @@ -695,6 +749,7 @@ impl Utf8Path { /// assert_eq!(grand_parent, Utf8Path::new("/")); /// assert_eq!(grand_parent.parent(), None); /// ``` + #[must_use] pub fn parent(&self) -> Option<&Utf8Path> { self.0.parent().map(|path| { // SAFETY: self is valid UTF-8, so parent is valid UTF-8 as well @@ -753,6 +808,7 @@ impl Utf8Path { /// assert_eq!(None, Utf8Path::new("foo.txt/..").file_name()); /// assert_eq!(None, Utf8Path::new("/").file_name()); /// ``` + #[must_use] pub fn file_name(&self) -> Option<&str> { self.0.file_name().map(|s| { // SAFETY: self is valid UTF-8, so file_name is valid UTF-8 as well @@ -818,6 +874,7 @@ impl Utf8Path { /// /// assert!(!Utf8Path::new("/etc/foo.rs").starts_with("/etc/foo")); /// ``` + #[must_use] pub fn starts_with(&self, base: impl AsRef) -> bool { self.0.starts_with(base) } @@ -840,6 +897,7 @@ impl Utf8Path { /// assert!(!path.ends_with("/resolv.conf")); /// assert!(!path.ends_with("conf")); // use .extension() instead /// ``` + #[must_use] pub fn ends_with(&self, base: impl AsRef) -> bool { self.0.ends_with(base) } @@ -863,6 +921,7 @@ impl Utf8Path { /// assert_eq!("foo", Utf8Path::new("foo.rs").file_stem().unwrap()); /// assert_eq!("foo.tar", Utf8Path::new("foo.tar.gz").file_stem().unwrap()); /// ``` + #[must_use] pub fn file_stem(&self) -> Option<&str> { self.0.file_stem().map(|s| { // SAFETY: self is valid UTF-8, so file_stem is valid UTF-8 as well @@ -889,6 +948,7 @@ impl Utf8Path { /// assert_eq!("rs", Utf8Path::new("foo.rs").extension().unwrap()); /// assert_eq!("gz", Utf8Path::new("foo.tar.gz").extension().unwrap()); /// ``` + #[must_use] pub fn extension(&self) -> Option<&str> { self.0.extension().map(|s| { // SAFETY: self is valid UTF-8, so extension is valid UTF-8 as well @@ -907,6 +967,7 @@ impl Utf8Path { /// /// assert_eq!(Utf8Path::new("/etc").join("passwd"), Utf8PathBuf::from("/etc/passwd")); /// ``` + #[must_use] pub fn join(&self, path: impl AsRef) -> Utf8PathBuf { Utf8PathBuf(self.0.join(&path.as_ref().0)) } @@ -923,6 +984,7 @@ impl Utf8Path { /// /// assert_eq!(Utf8Path::new("/etc").join_os("passwd"), PathBuf::from("/etc/passwd")); /// ``` + #[must_use] pub fn join_os(&self, path: impl AsRef) -> PathBuf { self.0.join(path) } @@ -942,6 +1004,7 @@ impl Utf8Path { /// let path = Utf8Path::new("/tmp"); /// assert_eq!(path.with_file_name("var"), Utf8PathBuf::from("/var")); /// ``` + #[must_use] pub fn with_file_name(&self, file_name: impl AsRef) -> Utf8PathBuf { Utf8PathBuf(self.0.with_file_name(file_name.as_ref())) } @@ -1223,6 +1286,9 @@ impl Utf8Path { /// Returns `true` if the path points at an existing entity. /// + /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! + /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs. + /// /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// @@ -1240,10 +1306,51 @@ impl Utf8Path { /// /// This is a convenience function that coerces errors to false. If you want to /// check errors, call [`fs::metadata`]. + /// + /// [`try_exists()`]: Self::try_exists + #[must_use] pub fn exists(&self) -> bool { self.0.exists() } + /// Returns `Ok(true)` if the path points at an existing entity. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. In case of broken symbolic links this will return `Ok(false)`. + /// + /// As opposed to the [`exists()`] method, this one doesn't silently ignore errors + /// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission + /// denied on some of the parent directories.) + /// + /// Note that while this avoids some pitfalls of the `exists()` method, it still can not + /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios + /// where those bugs are not an issue. + /// + /// # Examples + /// + /// ```no_run + /// use camino::Utf8Path; + /// assert!(!Utf8Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt")); + /// assert!(Utf8Path::new("/root/secret_file.txt").try_exists().is_err()); + /// ``` + /// + /// [`exists()`]: Self::exists + #[inline] + pub fn try_exists(&self) -> io::Result { + // Note: this block is written this way rather than with a pattern guard to appease Rust + // 1.34. + match fs::metadata(self) { + Ok(_) => Ok(true), + Err(error) => { + if error.kind() == io::ErrorKind::NotFound { + Ok(false) + } else { + Err(error) + } + } + } + } + /// Returns `true` if the path exists on disk and is pointing at a regular file. /// /// This function will traverse symbolic links to query information about the @@ -1271,6 +1378,7 @@ impl Utf8Path { /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on /// a Unix-like system for example. See [`fs::File::open`] or /// [`fs::OpenOptions::open`] for more information. + #[must_use] pub fn is_file(&self) -> bool { self.0.is_file() } @@ -1296,6 +1404,7 @@ impl Utf8Path { /// This is a convenience function that coerces errors to false. If you want to /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call /// [`fs::Metadata::is_dir`] if it was [`Ok`]. + #[must_use] pub fn is_dir(&self) -> bool { self.0.is_dir() } @@ -1334,6 +1443,7 @@ impl Utf8Path { } /// Converts a `Box` into a [`Utf8PathBuf`] without copying or allocating. + #[must_use = "`self` will be dropped if the result is not used"] pub fn into_path_buf(self: Box) -> Utf8PathBuf { let ptr = Box::into_raw(self) as *mut Path; // SAFETY: @@ -1397,6 +1507,7 @@ impl fmt::Debug for Utf8Path { /// /// [`ancestors`]: Utf8Path::ancestors #[derive(Copy, Clone)] +#[must_use = "iterators are lazy and do nothing unless consumed"] #[repr(transparent)] pub struct Utf8Ancestors<'a>(Ancestors<'a>); @@ -1439,6 +1550,7 @@ impl<'a> FusedIterator for Utf8Ancestors<'a> {} /// /// [`components`]: Utf8Path::components #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct Utf8Components<'a>(Components<'a>); impl<'a> Utf8Components<'a> { @@ -1455,6 +1567,7 @@ impl<'a> Utf8Components<'a> { /// /// assert_eq!(Utf8Path::new("foo/bar.txt"), components.as_path()); /// ``` + #[must_use] pub fn as_path(&self) -> &'a Utf8Path { // SAFETY: Utf8Components was constructed from a Utf8Path, so it is guaranteed to be valid // UTF-8 @@ -1523,6 +1636,7 @@ impl AsRef for Utf8Components<'_> { /// /// [`iter`]: Utf8Path::iter #[derive(Clone)] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct Iter<'a> { inner: Utf8Components<'a>, } @@ -1557,6 +1671,7 @@ impl<'a> Iter<'a> { /// /// assert_eq!(Utf8Path::new("foo/bar.txt"), iter.as_path()); /// ``` + #[must_use] pub fn as_path(&self) -> &'a Utf8Path { self.inner.as_path() } @@ -1674,6 +1789,7 @@ impl<'a> Utf8Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + #[must_use] pub fn as_str(&self) -> &'a str { // SAFETY: Utf8Component was constructed from a Utf8Path, so it is guaranteed to be // valid UTF-8 @@ -1691,6 +1807,7 @@ impl<'a> Utf8Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + #[must_use] pub fn as_os_str(&self) -> &'a OsStr { match *self { Utf8Component::Prefix(prefix) => prefix.as_os_str(), @@ -1821,6 +1938,7 @@ impl<'a> Utf8Prefix<'a> { /// assert!(!UNC("server", "share").is_verbatim()); /// assert!(!Disk(b'C').is_verbatim()); /// ``` + #[must_use] pub fn is_verbatim(&self) -> bool { use Utf8Prefix::*; match self { @@ -1872,6 +1990,7 @@ impl<'a> Utf8PrefixComponent<'a> { /// /// See [`Utf8Prefix`]'s documentation for more information on the different /// kinds of prefixes. + #[must_use] pub fn kind(&self) -> Utf8Prefix<'a> { // SAFETY for all the below unsafe blocks: the path self was originally constructed from was // UTF-8 so any parts of it are valid UTF-8 @@ -1894,6 +2013,7 @@ impl<'a> Utf8PrefixComponent<'a> { } /// Returns the [`str`] slice for this prefix. + #[must_use] pub fn as_str(&self) -> &'a str { // SAFETY: Utf8PrefixComponent was constructed from a Utf8Path, so it is guaranteed to be // valid UTF-8 @@ -1901,6 +2021,7 @@ impl<'a> Utf8PrefixComponent<'a> { } /// Returns the raw [`OsStr`] slice for this prefix. + #[must_use] pub fn as_os_str(&self) -> &'a OsStr { self.0.as_os_str() } @@ -2596,6 +2717,7 @@ impl<'a> IntoIterator for &'a Utf8Path { macro_rules! impl_cmp { ($lhs:ty, $rhs: ty) => { + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { @@ -2603,6 +2725,7 @@ macro_rules! impl_cmp { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { @@ -2610,6 +2733,7 @@ macro_rules! impl_cmp { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { @@ -2617,6 +2741,7 @@ macro_rules! impl_cmp { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -2634,6 +2759,7 @@ impl_cmp!(Cow<'a, Utf8Path>, Utf8PathBuf); macro_rules! impl_cmp_std_path { ($lhs:ty, $rhs: ty) => { + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { @@ -2641,6 +2767,7 @@ macro_rules! impl_cmp_std_path { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { @@ -2648,6 +2775,7 @@ macro_rules! impl_cmp_std_path { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { @@ -2655,6 +2783,7 @@ macro_rules! impl_cmp_std_path { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -2679,6 +2808,7 @@ impl_cmp_std_path!(&'a Utf8Path, PathBuf); macro_rules! impl_cmp_str { ($lhs:ty, $rhs: ty) => { + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { @@ -2686,6 +2816,7 @@ macro_rules! impl_cmp_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { @@ -2693,6 +2824,7 @@ macro_rules! impl_cmp_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { @@ -2700,6 +2832,7 @@ macro_rules! impl_cmp_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -2724,6 +2857,7 @@ impl_cmp_str!(&'a Utf8Path, String); macro_rules! impl_cmp_os_str { ($lhs:ty, $rhs: ty) => { + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { @@ -2731,6 +2865,7 @@ macro_rules! impl_cmp_os_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { @@ -2738,6 +2873,7 @@ macro_rules! impl_cmp_os_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { @@ -2745,6 +2881,7 @@ macro_rules! impl_cmp_os_str { } } + #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { diff --git a/vendor/clap/.cargo-checksum.json b/vendor/clap/.cargo-checksum.json index 729aee79b..22fa24875 100644 --- a/vendor/clap/.cargo-checksum.json +++ b/vendor/clap/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"6d96d441076749454963df06d637e5680e5ecdcdd36026f160c2d181aaca3bdc","Cargo.toml":"cb59c1e945c5606119203d907c01a40606070414b8913440f32e250c5db8c211","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"b5d5ba727e9f1a8797016bb041bc7888a209099d7dc42e445a89b1f8d3ac510d","examples/README.md":"9d19f6dfb53aadbe18aca773136d34bd28352b8efd69dfee217f26ee0eb9269a","examples/cargo-example-derive.md":"53a35e48cd04dfa10d70f99eb6d97d0d74110958f7f9e4ffc460fca87a256a73","examples/cargo-example-derive.rs":"627a74b7dc6d829b8facd314d0de46418b2420c6998e883f71a3cb7639d3a22d","examples/cargo-example.md":"1f270b0a0ac9122feb9cdac0887c1c1bcf1b654fed27147871c9cfe71851a4d9","examples/cargo-example.rs":"66293c7e200a87fceca691ab858293142c8a1536ef1d2c0dd14a6056289866a2","examples/demo.md":"3e986afca0863142fdd4cc092b5969fba32a70fac8adf84a55bd652f4b30eedb","examples/demo.rs":"5361cac70b662dd6d4d785738b99cfadf1f838c90507f19ea1aeef05aba0ee72","examples/derive_ref/README.md":"be2cfd81b9e2dc5e5910243f4b2f032e0b2c8af0592dcd050705e8718be8038d","examples/derive_ref/augment_args.rs":"69057536807ceb08e35802f8cf65c0f6ddd260a66a90000c8c6294031d466be3","examples/derive_ref/augment_subcommands.rs":"5535f8ca1893101acb5eba8edc311497431ff9aa26f62f1d9743bdc147bef7a4","examples/derive_ref/custom-bool.md":"d92e441199c7584d4b888c45124366cc4802ec8ea67cdcbb3423ffaa3c5268ac","examples/derive_ref/custom-bool.rs":"f88e9c68d2447a24bc98e05124fea17836155f32cff30a2b8a03ad254383247c","examples/derive_ref/flatten_hand_args.rs":"c09b751eb4e89e825af4de25a67d735c7b4794536bcff96b0ab8ee816c34413a","examples/derive_ref/hand_subcommand.rs":"1a5464b9c5791361930b5591adeb6fcf6f14b83abdfa6443d2c80bcf0c097b3e","examples/derive_ref/interop_tests.md":"3a357e82cfc155f71e0348be33f78295aa77839c3e3a5b7c1783cbd1259e6a61","examples/escaped-positional-derive.md":"b2190ada5ad2634c3ceb7f9d98293512628762545f9519579cbee9867c6a406a","examples/escaped-positional-derive.rs":"ac3127e8cc7a8953886778824a4d6e12470488546f10eeac6f9817ecaef1532e","examples/escaped-positional.md":"b6a5c103f5cea1464b5ac8e63e1964f032a4dbb4a908e45b9b391f4857fe2684","examples/escaped-positional.rs":"aaf106cdbe8f1eb5d9f3032df485d5661885f95402f026a34c42431f98a08323","examples/git-derive.md":"1a20f30d1c6df28d7e48b527b0726e9440f54d55a1e0b9e059b2322a7960ee72","examples/git-derive.rs":"225a33b0cd84840de2ba623b6b506b2fa4b02a9f5fbf62cdc2b2626e661501bd","examples/git.md":"acb3a44f954a6e2160f8989952981fb4baea8b97b921e4227c67896bc64d5e4a","examples/git.rs":"293b1289550ea38eabf1af7c6a855065170ff785e97be113928f045c50c1a3e9","examples/multicall-busybox.md":"3cb9d00ad110fc99c298dac4aa471e2f7a304aecef51d2eda67f5fbf36c41293","examples/multicall-busybox.rs":"709f71a82295a539d0a239371d35d1eeb517eaa3bb0a4db406bb7e5d3541a4a5","examples/multicall-hostname.md":"8c2d95fa8b940d4f788f96cf6b08b81bb2541bf12adff63bdff90dfc24567c7e","examples/multicall-hostname.rs":"cc58a924dd2e57281f36e30481a1cbc8186952adbf149f9e1e13f9c673614fd9","examples/pacman.md":"e583ef465e55fa2fffef3b121e4a90835b8905ef3ffe2ec9ae91702832b7392d","examples/pacman.rs":"4aea4eed4408458d57d3ff91f0e7f8833eeee30dd71043f5a6d06968c6c9712e","examples/repl.rs":"d50c1da634c237b26989994b1efa6fd1a087874a82d1fc8c1863be4ea8deaa8c","examples/tutorial_builder/01_quick.rs":"2734001dc1f67842f8ff3486397738f10dcbdf4bdd15326c13aebd5fafe0dabd","examples/tutorial_builder/02_app_settings.rs":"ca7e0b49019a444053ed13a7df8108d460430819b4fb04c4c6097225dc630293","examples/tutorial_builder/02_apps.rs":"a7016469d10259ae0025fb6ad5b9d3c732cf082869348005d4774d2bb0722d2d","examples/tutorial_builder/02_crate.rs":"5d7397901ebf82e3975626b3737fca3a95868cde42ce74d41bb3c96429878906","examples/tutorial_builder/03_01_flag_bool.rs":"1e904b39c7aaafc407a841ab8b549152263073a1af11773d13dc04d43fd541ef","examples/tutorial_builder/03_01_flag_count.rs":"02778a53afd6170c7ef7d358909237d4fe548adc5d7e650916d26f765040c25b","examples/tutorial_builder/03_02_option.rs":"7bca1c12b4904f89516ebdb88019c959c5adcf2a84244047f988b71f82760bd4","examples/tutorial_builder/03_03_positional.rs":"290921224b17df7f77326df06421b2100462da143e7b5dbe014f7e8b6d727d2b","examples/tutorial_builder/03_04_subcommands.rs":"1d5769847403661b1bb82d7a39713c52e1decbe4027dfc3866d63f5cf6ae8a55","examples/tutorial_builder/03_05_default_values.rs":"5a4768214c57996b27989cd5af57c7b79cbccfab2f285a88a415c2b67b589e4b","examples/tutorial_builder/04_01_enum.rs":"813ce1cf91e2cacd7eb5bd7018b1125d41cd9b29970dfa3638a7cf73c06659a0","examples/tutorial_builder/04_01_possible.rs":"2ccba0ab59f6339bcd761160d17a1c7ec935716fbe137408338694c7d3ee56f0","examples/tutorial_builder/04_02_parse.rs":"9d022cb3a3af3e00fd6c7d647ee0915a275ce79e379676e98bebcd3484be344b","examples/tutorial_builder/04_02_validate.rs":"4450e7e1af3581be631ffe9afa363c88b44ee20a90ecbb4608246972d3f7fd93","examples/tutorial_builder/04_03_relations.rs":"90db469ca8a3f1c5eb90548e8c1c0afe796d163891bdac90f2d307949a400047","examples/tutorial_builder/04_04_custom.rs":"461a06cae62f5972937f71b42d04df44240dabd62e23058322f04026beceaec5","examples/tutorial_builder/05_01_assert.rs":"73c57b051550366ed412c8986f40549fd43dacf3894df7751313c5de16f46af1","examples/tutorial_builder/README.md":"027d95d9f951d4ffed9ec54a3950919ea4a3d9fd471bbda721151ed6ff6c5731","examples/tutorial_derive/01_quick.rs":"e17262c915199c4507d8950d5eafb73f3047e09b6dee2abbfe9f82ebf1b7ddd5","examples/tutorial_derive/02_app_settings.rs":"7e81f4c1640b0bfbd87aedd3eda79ae7c47c669dee79b643b35e54c1dc076ee8","examples/tutorial_derive/02_apps.rs":"e8cd02b5983b2203f1585b96858fade4cedfb124e366171d6b21fcb3f05b514e","examples/tutorial_derive/02_crate.rs":"c156589c36a8b21654b1a41f5f10240411053d3273e7af3797e91ca53fa61d28","examples/tutorial_derive/03_01_flag_bool.rs":"07c31218d0332d7437d80e19c7e3c7be711bf0f56bee3ffb1c4d6f7f253b9304","examples/tutorial_derive/03_01_flag_count.rs":"945be42994845145b9c579b3834f8c6375f239293ded84fba35754bbe9fdcf9b","examples/tutorial_derive/03_02_option.rs":"48be4cf49b498173200ad86d5d3cd64ce9381f86fdaaab70f05fc471f64a2185","examples/tutorial_derive/03_03_positional.rs":"f368ab1465ee4d84b84d175b97af6f64ce0676bec2482adef3ce966d2d8de26a","examples/tutorial_derive/03_04_subcommands.rs":"b25c8aec8f3816923b1154be91caafe0c2d2841fc1af5f0ef048f03d1273879e","examples/tutorial_derive/03_04_subcommands_alt.rs":"7ba6e81c2af6085b7e2721254500b34ee3e8622e20790b3c6f2786e165151b70","examples/tutorial_derive/03_05_default_values.rs":"0ba14153a3c72a2435ac3688b990171a1670eb3f2f7cef21886732e489fad435","examples/tutorial_derive/04_01_enum.rs":"a665af77196af86ba87f1725703011392fc27f24e3d442bbb5dfc4c0d4892c15","examples/tutorial_derive/04_02_parse.rs":"fbb23ef2d98d3cb401cec9dd29d5818e4c189cc9f54fe961a2fbd08632a9634c","examples/tutorial_derive/04_02_validate.rs":"87d9c465f912b69e5839ea87404a221a39421404012c1a7fd6e327b03ceb12f0","examples/tutorial_derive/04_03_relations.rs":"bfc12e66ad9c17182bed2ef86cd668242e6e87ab4ee20fa9bf3d2aa99385d61a","examples/tutorial_derive/04_04_custom.rs":"0e745c6dab0881c62190e82e01409b70cf3286dd0983db4a612f1be88fdd1a8d","examples/tutorial_derive/05_01_assert.rs":"4742d883a3446f32068d96c142ed18df40a50ad6ed4989e39980011f3d1adbdf","examples/tutorial_derive/README.md":"7902da25a153aa0032184e4ca54185d1a5d4c6aa53686b10a210b4decc276791","examples/typed-derive.md":"cf3ee8313709937cc9c5462e3826cca8679946a658d684e8a36e66b0950100a7","examples/typed-derive.rs":"67034bd557c0efb2a0b61ced263cab3ddddb4e4a2bff2f2901d4832f6961e17d","src/bin/stdio-fixture.rs":"e8f10afbfe1857bcf986d2f55be0ca19a50c905d9f650c6e1fd42dbacf219b04","src/builder/action.rs":"64633d218202f799a08fb43ce7f1fae6105ae5ed43386caf4aca2d8ac5352fc1","src/builder/app_settings.rs":"5a27df52d765b50f83ad1173525b66f92b156415aee62b238306b3b57c086e50","src/builder/arg.rs":"808037bb9e7084c27f9f136059653ab049630d07d9851e5e700c8a775655bd05","src/builder/arg_group.rs":"263d9c79e03015fe4e2fab4616fc73089be60fb2ec17aa2a06f3d6a24740432c","src/builder/arg_predicate.rs":"8c9fd14780cd42465f32f2e8927b97c06e686d09b5927ba3cd5bbd792af7a13d","src/builder/arg_settings.rs":"af739627b9b1451c633eb66b09536008d8b095cba518a4f28b82ea480e9400d6","src/builder/command.rs":"72d0031bce35aa6d6ebd6a2006fe26a9b222852fe5a58a23854d9ab7f27150c5","src/builder/debug_asserts.rs":"d1d5adc82cb8269445b2ef197f1e566f61e7f13d6a24afaad928e45e95aed170","src/builder/macros.rs":"904e42e72c49107ae324f45d5df24fbff13b9c7d4589f1a4ae38594add704434","src/builder/mod.rs":"205367cb5ba5d5ba7894091535ce3a5dd23b35fd436e003196d89523e7705566","src/builder/possible_value.rs":"62268b9da9eec8f4d1904ebfbd3a288fb78cfa71c357efadced28f0378bcfb93","src/builder/regex.rs":"b18891310186ecdcca9bb611833b7188cc80fe72e9fef27b63fa076b880a1acb","src/builder/tests.rs":"995c7d6be608b94c6f392f1356eba0cb8adb9ca661ffeebf7ebe6e8ad01a868c","src/builder/usage_parser.rs":"91d1af89196116aac2c0fb021f42f43f954aa3252df264e19a02a0cf5911d16b","src/builder/value_hint.rs":"0dd974d495c313430898d28b79991a70983c9aa44e88fa9aa1776d3308935438","src/builder/value_parser.rs":"1d731b5bf4e25344ae1de23c474255a310852721ecf66a98c5ef2cbca1452437","src/derive.rs":"cf3e108adf7022ef4a269a0ede687d19f8f549168e1f36c3592fbee40da51e61","src/error/context.rs":"1dc561c7877d7f9b90f04bb7915744f0b3cc4ac2aa928ae100b2825a97077142","src/error/kind.rs":"deba40c24adf04e67e87e383463d103907b7f8cc69f842fd3a5d8d81015d33c1","src/error/mod.rs":"c7bdd28240ee2fac6d9ae2c3d849483fabc3c64d5d577c0bc297c996f122a217","src/lib.rs":"9522f2b17cd505623468c5ff847f5aa906a40ae19dde0329c459a417c2b82a2b","src/macros.rs":"d39619976c3cf3b2b28eef3dfffd449080f4fcfbaa164b01901bf3e10d1a5a07","src/mkeymap.rs":"3565a5bae5d6cdcf8ba41a24eb602c510a14e150c4a6d3085ad72a35778e9c5f","src/output/fmt.rs":"efb741b5854500d946c6c09763ece1badc2b9cd3efa616cb58012039836c2b7f","src/output/help.rs":"ebdd123d6b70279c25af4b08432b547498834853adf99821ff6c6cd65dd87d4e","src/output/mod.rs":"3a61f89a4568e95114a3ab839da8f3c4c92de2a228549308f5d1be076a474917","src/output/usage.rs":"370d3544cf58a09f8d3b0bcc2d894531d7152d716eaffa745a858c6ba2e03b7c","src/parser/arg_matcher.rs":"79ab36a164df07e565d2c44b836f647ee2009463d0d55bd2e822cb72b5e009a7","src/parser/error.rs":"4568fb6b8bb05b43e81c5df4fba5f4cb8b19bfa06e6b8fc6b5af6ca4074766cf","src/parser/features/mod.rs":"6ed075e97af56bff22f22ed1ee83ff6479360e05f9d3661a3145f822c242b694","src/parser/features/suggestions.rs":"79127956b2f1adb9d658925e2779ebebfe9ddea434408762fefb60afdb545f47","src/parser/matches/any_value.rs":"7b6e711fe205e8808394c562dd6a260b56ce350cf9298a308ba9727ab012b664","src/parser/matches/arg_matches.rs":"a24fa086537ef72951821fbf1dc455a04270606ee411685991e79aaae509558c","src/parser/matches/matched_arg.rs":"fb12eb2afaf631bb60aa8c4e42b0f510a877d35a9eaa07a7afd253280c27c251","src/parser/matches/mod.rs":"1467aa752cb1c79d30e4aeaaa55e10a0bb9dcf6f3980496234251431c79c49e6","src/parser/matches/value_source.rs":"e6a477ae36f2f7155960239a97b7d142eef4eb227c41c9eefea147289547d713","src/parser/mod.rs":"358f46d3b7f43dec2563d4c35bd2536fab2491f28e300a9bcdeaf6ca0513ce12","src/parser/parser.rs":"c1339fdf44253b6cbf81fcf71f99bb68300f8d5eb5ab7f0d0d02d222ee63a873","src/parser/validator.rs":"30066cb41ab23800231fb6b028cbce57d118570859659ebc67affbe5226f31f9","src/util/color.rs":"63df5e1cda1001b4c536dc0b04e09dd85dae6d317e34e660abbe3c71e17eaa29","src/util/fnv.rs":"82492d91d990f38b62de8b3c3e67f1fad55919117b1f448aa28acf6d21919fd7","src/util/graph.rs":"f35396b6e2a427377dcbbca69b1b98737d89684a3834cfda98cbf8cc70ff9c2f","src/util/id.rs":"fc498c65887385d92a51359a2f72556c2e508ee49b8cac4b3f827512795d690d","src/util/mod.rs":"8d328a15ef06989d0ce5e65cf3b7ec79c083984b25c0b31ba177bdb22df28a10","src/util/str_to_bool.rs":"1ce90b4939a884eeefc73392722bdfcf906e3070c4398e1557c586c10c684cd0"},"package":"d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7"} \ No newline at end of file +{"files":{"Cargo.lock":"60560d6b2bec73734ebea64f8b916cbe9361e672157119801ba0e2f89334453c","Cargo.toml":"5def59eada2aa1a035cb39b38da4ba02baec2dd9271e4ef16731a8ef06c4d58f","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"0d687e1f07b58fe68bda74668ff6326125e5e5efa184cce755cd84ac535b7058","README.md":"ee049ee3ccab683cd3fa7c980db71c22ed8577378433cad5a93c1bc2a9dbe20f","examples/cargo-example-derive.md":"8305e66dd56619ec3a1d116951c893965cc8435574f5bf8baea923492357c626","examples/cargo-example-derive.rs":"a94003c9fadd1a11c35616ea4e5132c768bad08650e207848e1de56bffd86c8f","examples/cargo-example.md":"b7e51be8f05538ae39ce232ef12c873af81ab5abb5740c079d09b7cdd27a3b71","examples/cargo-example.rs":"be19a1ccb9d91882d76e7553f692ef89fa2a7acbbc1500232ce9fb60b6e8a85b","examples/demo.md":"9db305e9ff333f5e783dcc3142683280816d7bc111a57e9dcc4127f07ca44055","examples/demo.rs":"8a18ab15a235b84efd82017e51a891ed2df5f0154adbfce2806dcac089296b64","examples/derive_ref/augment_args.rs":"93fa1e122328a5d12ca4f921d17902dff6ec47b69fb2140124e2a00809ec4a1a","examples/derive_ref/augment_subcommands.rs":"5535f8ca1893101acb5eba8edc311497431ff9aa26f62f1d9743bdc147bef7a4","examples/derive_ref/custom-bool.md":"d92e441199c7584d4b888c45124366cc4802ec8ea67cdcbb3423ffaa3c5268ac","examples/derive_ref/custom-bool.rs":"f88e9c68d2447a24bc98e05124fea17836155f32cff30a2b8a03ad254383247c","examples/derive_ref/flatten_hand_args.rs":"abdb4e55b0cb71e5c4d14fe20ae0930df6888b2dca01225a02d3c6828bcbc791","examples/derive_ref/hand_subcommand.rs":"1a5464b9c5791361930b5591adeb6fcf6f14b83abdfa6443d2c80bcf0c097b3e","examples/derive_ref/interop_tests.md":"3a357e82cfc155f71e0348be33f78295aa77839c3e3a5b7c1783cbd1259e6a61","examples/escaped-positional-derive.md":"64329a454ad399cfde7cae37c2419fb68f1dfcdf2b7d809e113bab69c5f9b947","examples/escaped-positional-derive.rs":"68b0b474509d0d0b19a2ad756c15a18a9d3b30278390ddf1b7bc11b40fe5f937","examples/escaped-positional.md":"a8259da128ad7ad1f898527bb9e3c1c55541fdc2a59a8599fcddbe9cf58a3563","examples/escaped-positional.rs":"ca33f37267df8de835eeb5817e906a957e96c4ee9bd95b97abee3af25639f3c2","examples/git-derive.md":"280909b56757f102cad3a3274a92c884a0cec4e698c0f8718d2edee73fbbd810","examples/git-derive.rs":"2e8310364f2622b1b11c916643dda7392ec4a4fd585f30d537672d2fed48ea6e","examples/git.md":"31c172433b05ce581179aaba10d610de5cf097b0da894f1330a0437ef332feab","examples/git.rs":"9da386531604fc2afbd375685e213200ad10e34100ec92b4bfa6fb5730283aa1","examples/multicall-busybox.md":"0e07a2f79f94daf4586db85bf207b4bd8f0653b59858d6b4f0b66956a5b2178f","examples/multicall-busybox.rs":"709f71a82295a539d0a239371d35d1eeb517eaa3bb0a4db406bb7e5d3541a4a5","examples/multicall-hostname.md":"b547e42135269ab1e8be8dea4da6a4e99dfaa006a320fa319198d5934e1e97ab","examples/multicall-hostname.rs":"cc58a924dd2e57281f36e30481a1cbc8186952adbf149f9e1e13f9c673614fd9","examples/pacman.md":"c91e1582caf8a2cdeca208c856d1ede3f3ff26948b288a98ef69ea695f12f555","examples/pacman.rs":"f249824b950e1c34fae37afe04389143a037452a1f699c215172ac20e0285984","examples/repl.rs":"d50c1da634c237b26989994b1efa6fd1a087874a82d1fc8c1863be4ea8deaa8c","examples/tutorial_builder/01_quick.md":"80878c8630e0ecf7bb172c2645c2c17480ca5a37e5f4f481ab99e88d3a37da8e","examples/tutorial_builder/01_quick.rs":"c19b165fce9468fb3c9d3d9354a2b9829ceea7ffba6b7134d4941a6e986429a9","examples/tutorial_builder/02_app_settings.md":"f0f7b48afa7a97c9270f9d63a0e9e0f3117733ee0201639eae2199a4aca4944e","examples/tutorial_builder/02_app_settings.rs":"dd770d131726c3f37e202c9b10c969cc4eba90249c54a05594535cea6efe2749","examples/tutorial_builder/02_apps.md":"815a9197925d403b1d93969ace87e80e32667333fa83f2c86abcbdfa17cf0d7e","examples/tutorial_builder/02_apps.rs":"a7016469d10259ae0025fb6ad5b9d3c732cf082869348005d4774d2bb0722d2d","examples/tutorial_builder/02_crate.md":"086581912b34d305bb7cf3c5a35238c151bd366fac4c0923057883253731c250","examples/tutorial_builder/02_crate.rs":"2742c6a3f1946b89b4f1146893e126d68e1cf55ad4130fb94105091900421273","examples/tutorial_builder/03_01_flag_bool.md":"068378b1e76ce624dd0153dfaa9a7ae2d1a84205b1e169f5f1a16bebd50715cf","examples/tutorial_builder/03_01_flag_bool.rs":"d49b30b527faa6a383b334e572d546fab5c4b298a5549842073ab42a33a05c94","examples/tutorial_builder/03_01_flag_count.md":"8d62fbef076eac962a1d0082afa4916de22277aee973d693de33e9fd73b16669","examples/tutorial_builder/03_01_flag_count.rs":"2bfaac3aa9bcbbf37e18e74a40d966391e208d44b45a1e9c4ab61d22fd14dd40","examples/tutorial_builder/03_02_option.md":"585793524138da00c25b9fdd883b25eb8addfaf8742365d84cde63169a9289a7","examples/tutorial_builder/03_02_option.rs":"ce43934605e0438f1e8706e5e970cfcd930f76c4ebee02450ffc63de520994bd","examples/tutorial_builder/03_03_positional.md":"46fe5085841342243efd9614e80db7db3c52ae5af7c6cdd402b569d310e63fe9","examples/tutorial_builder/03_03_positional.rs":"fc7538d0fe8501c56070f0f22be699f128890636aa4ff8478cd6c7beeea279da","examples/tutorial_builder/03_04_subcommands.md":"fc5a92c5290b3cc119a6421779cdd8f4791465a1d3f50f4f29ccb08f3063a6f5","examples/tutorial_builder/03_04_subcommands.rs":"a309a332004edbed6dc14b64b1ba6cc0cd42871f3c5b8da7daab772764839c68","examples/tutorial_builder/03_05_default_values.md":"431800610a29d9a5587b74b30d709e67af5a0b8980900de20e5876fb9491144c","examples/tutorial_builder/03_05_default_values.rs":"b277be9cfe5d87958f9cf2e8a178bb007b070723528bedc8b81163aedb3a2880","examples/tutorial_builder/04_01_enum.md":"d1310efc5c8acb5ca9c86b57deebbcbd8766869284d2e8ea51e32b3eeac38439","examples/tutorial_builder/04_01_enum.rs":"596aa44bc401674a4ccf091b81b2df79b911dbb01d61fd167fd270d1e21a3609","examples/tutorial_builder/04_01_possible.md":"308cd6530b3c389bf2a82b2b66ad33025be230d84d94835273af35a90eb6a753","examples/tutorial_builder/04_01_possible.rs":"3d781b26d257061b55a957744c2dbd99c1d2346c151230fb18fe5f576d19585c","examples/tutorial_builder/04_02_parse.md":"ea14a355913fd7a8af5aac4be2bdecfda72c039b62ccadfb91ff8d39a447955e","examples/tutorial_builder/04_02_parse.rs":"a65f596341e65f41d555b38a6f5e22a5e03aac6faa4e8b3e3c85fa0e0935a2d7","examples/tutorial_builder/04_02_validate.md":"7536f4fb1a11ab94e54b6b98b7364c77912b7600803aeda5988c5b29f3f037c8","examples/tutorial_builder/04_02_validate.rs":"af6d9f748c6956aaa1006ce96834e0d013a9dbfb6d0acc63df5eb63caac56eef","examples/tutorial_builder/04_03_relations.md":"ffc6b8a2d606856fbb6cce677c5280e08eaffbe6a4c8e40cd68ce35959370ed7","examples/tutorial_builder/04_03_relations.rs":"a2dbb6d77587f64775ef57c4bb3869a2760e5c124e2870898bbf1191ef349b99","examples/tutorial_builder/04_04_custom.md":"d562fd072b5d91e8ea145771a2b6eb0284d3d21bfac707ba48ee00e92d76ad2d","examples/tutorial_builder/04_04_custom.rs":"ea0879629da2dab2d2e7fd25bdde53386d863a3e2d468e7ea306a6f8240a5522","examples/tutorial_builder/05_01_assert.rs":"69fc5a3d330be1f90055f886d65684204d7f0585459f362cf3c43b5caf4bbd7b","examples/tutorial_derive/01_quick.md":"1416029b09409468ba6b39ae5f91c41547f7f389c2534961f867ab17260638da","examples/tutorial_derive/01_quick.rs":"e17262c915199c4507d8950d5eafb73f3047e09b6dee2abbfe9f82ebf1b7ddd5","examples/tutorial_derive/02_app_settings.md":"3f4a81ebc7b674482768763bab70acf9bc31f68cc3ecb118c6f5493feaff3d42","examples/tutorial_derive/02_app_settings.rs":"7e81f4c1640b0bfbd87aedd3eda79ae7c47c669dee79b643b35e54c1dc076ee8","examples/tutorial_derive/02_apps.md":"27d22d45e438f60b346d34508a75783871e0fe9b1ae41ec759e56118a10feff7","examples/tutorial_derive/02_apps.rs":"e8cd02b5983b2203f1585b96858fade4cedfb124e366171d6b21fcb3f05b514e","examples/tutorial_derive/02_crate.md":"eb396e17db1dd68eb7689bcd806b63dbfe01ad48dfc12c285f00c42e1d4b8c1f","examples/tutorial_derive/02_crate.rs":"0b12a0790d23cee1e5d275893f428cc0af36d5532c2af00806e64c18ef9d309c","examples/tutorial_derive/03_01_flag_bool.md":"f6dd5ab050f0f1ac5924949a4ba45f248b2d4b1bd77210d78b9d8e9b3395d111","examples/tutorial_derive/03_01_flag_bool.rs":"07c31218d0332d7437d80e19c7e3c7be711bf0f56bee3ffb1c4d6f7f253b9304","examples/tutorial_derive/03_01_flag_count.md":"74d5c8a79581ceb7e6a11ec20ae59fa8c7f42591e10464aad50bbdd3d06916fc","examples/tutorial_derive/03_01_flag_count.rs":"945be42994845145b9c579b3834f8c6375f239293ded84fba35754bbe9fdcf9b","examples/tutorial_derive/03_02_option.md":"034b65008d05c1598fe3c1918f23d654d7a14cb610dd636a3c649d9d7a3b1559","examples/tutorial_derive/03_02_option.rs":"48be4cf49b498173200ad86d5d3cd64ce9381f86fdaaab70f05fc471f64a2185","examples/tutorial_derive/03_03_positional.md":"14f6b36eee218a38733b534e7b621f68a6f799bd96682a82980cba9f6e99a40e","examples/tutorial_derive/03_03_positional.rs":"f368ab1465ee4d84b84d175b97af6f64ce0676bec2482adef3ce966d2d8de26a","examples/tutorial_derive/03_04_subcommands.md":"3e1870fb10c78a01b63903060b1164f3f4d0e51c052e449abe11e2d06c252811","examples/tutorial_derive/03_04_subcommands.rs":"b25c8aec8f3816923b1154be91caafe0c2d2841fc1af5f0ef048f03d1273879e","examples/tutorial_derive/03_04_subcommands_alt.rs":"7ba6e81c2af6085b7e2721254500b34ee3e8622e20790b3c6f2786e165151b70","examples/tutorial_derive/03_05_default_values.md":"9ac52230ba7d9c214dcb64922cbf161970947d9650e8e7ea8d0ee949eba99c0e","examples/tutorial_derive/03_05_default_values.rs":"0ba14153a3c72a2435ac3688b990171a1670eb3f2f7cef21886732e489fad435","examples/tutorial_derive/04_01_enum.md":"ee57dc12a88a560d70f344629ac79cc497f96e967e97b4c643467747c8075172","examples/tutorial_derive/04_01_enum.rs":"d30abd8570357be26871c06939dee8173d34408250b6bdc3b1e76f1cbc06f888","examples/tutorial_derive/04_02_parse.md":"f191e6c77e6b133f78bd1123cec2b09c8dfe8bb17198d6348e26adade7465daf","examples/tutorial_derive/04_02_parse.rs":"fbb23ef2d98d3cb401cec9dd29d5818e4c189cc9f54fe961a2fbd08632a9634c","examples/tutorial_derive/04_02_validate.md":"c88670017d06261d454818ff18f21a06275f35d564e637c5346ce3b7fca8a02b","examples/tutorial_derive/04_02_validate.rs":"87d9c465f912b69e5839ea87404a221a39421404012c1a7fd6e327b03ceb12f0","examples/tutorial_derive/04_03_relations.md":"5657bbeee193f21a312db682cfa216f1001a94ace024c56a959985feb2e29069","examples/tutorial_derive/04_03_relations.rs":"eb8e737733261d3d1b7f4def7a05c37ba7c1c010357c7de33ee42c8adfdf6dc2","examples/tutorial_derive/04_04_custom.md":"9627d0025c5c063682387d8e00b3fb097114d1431c1ce8808038be34f781576a","examples/tutorial_derive/04_04_custom.rs":"0e745c6dab0881c62190e82e01409b70cf3286dd0983db4a612f1be88fdd1a8d","examples/tutorial_derive/05_01_assert.rs":"653450ff2e528f29b6b31d979fd7da094ea8e74b8b61a4657935c9ac2efbc28e","examples/typed-derive.md":"c22bb8da2e294f1d3725624e0c442713e5f263b10a2ee76a22ffa07f89af735a","examples/typed-derive.rs":"1c88bb1c8cec4e2e7a452552fa52675d96ffd6f201f5384b4e98d0a70fce1e4c","src/_cookbook/cargo_example.rs":"fe7594a5233e9106a159aa1f5d5f0cde0d844356f630d55c78b8ef322327d4e5","src/_cookbook/cargo_example_derive":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/_cookbook/cargo_example_derive.rs":"badf3e931ef5d5b7f5addc4912aca057ba83ee6302c43d7eeecd1661673fd407","src/_cookbook/escaped_positional.rs":"2789d8fea126355805b29e76b52c6cea4982565014087a46e0d48e4ddfbed7ab","src/_cookbook/escaped_positional_derive.rs":"802d0b672f4ed48152235d4a26a64c97fa921b361177bdd3a1a33cbac96f665d","src/_cookbook/git.rs":"372977252a22fc776e3acaa4629e964114ccd6a49b8ef334d2b6646f12e8b5ee","src/_cookbook/git_derive.rs":"4ab7c0197efda06607ca60c2a85ea743aed3494f5fe9e408d935ea0500a345fc","src/_cookbook/mod.rs":"34c53c6273512976676a82dded921f8d99e0312dd3e823ae1549606754625827","src/_cookbook/multicall_busybox.rs":"56176b4fa15e7a39c433706971d4e68aaf26ddc2a5790078b6dbe722ee13efee","src/_cookbook/multicall_hostname.rs":"907f8decf81ea4d4cbf81639ea4cd2f925eda64d4831454a7656369b65522780","src/_cookbook/pacman.rs":"863125b2d3d7931a9e4541c8ab1242b8bfcb421d8b5c604ea681efd805f68da7","src/_cookbook/repl.rs":"1393209b2cc5c203296d57c5a065b764b4318be7855e48baf16de851e250cf90","src/_cookbook/typed_derive.rs":"3d28e78cd0b068b4fcb32a7fea6244de176f2fe75dfcb59e99c33b66a7ae4864","src/_derive/_tutorial.rs":"237d316ad5f9838dc011283e454afce24d47bf2e9c5038ba5402bafeb2959090","src/_derive/mod.rs":"7f1f6b59332044681324f0753dfb51641e52f46dee74a21b8c94a413bc06be02","src/_faq.rs":"06d10de865ae34305fa973db9b00dc31f54e0f63f8fe039805aa371c36a796b9","src/_features.rs":"bbcbf1b256136d20f89e4f8a16ff37b04f07dfee0d2d4f2b013f445467628032","src/_tutorial.rs":"e7c7359b6b6c86cf6e18f4bdc3c90ce440b82bf07ce304ca2e127fb2a04cbf9f","src/bin/stdio-fixture.rs":"e8f10afbfe1857bcf986d2f55be0ca19a50c905d9f650c6e1fd42dbacf219b04","src/builder/action.rs":"beab4d8dca6337dfd64f387ee3198a88a6dcb71ec94f5bbbfe6bb4c0175ab9ee","src/builder/app_settings.rs":"17b094a5c044b2387467706bade1b19b5703bf99fc5081ac9508f410f871a1f2","src/builder/arg.rs":"e7120b60bf72d2572fc1f325b377a32da9ece4d7ac00b4a580a0f6a42c08ea8a","src/builder/arg_group.rs":"263d9c79e03015fe4e2fab4616fc73089be60fb2ec17aa2a06f3d6a24740432c","src/builder/arg_predicate.rs":"8c9fd14780cd42465f32f2e8927b97c06e686d09b5927ba3cd5bbd792af7a13d","src/builder/arg_settings.rs":"b7966dfea529a1be1164ca2d76494b1712cb2f73b024d2a23307dcd473933887","src/builder/command.rs":"57f0076465feb3cf6a0a16610b345fae8dbde8d248e4ef94111a27051c40789b","src/builder/debug_asserts.rs":"d1d5adc82cb8269445b2ef197f1e566f61e7f13d6a24afaad928e45e95aed170","src/builder/macros.rs":"904e42e72c49107ae324f45d5df24fbff13b9c7d4589f1a4ae38594add704434","src/builder/mod.rs":"205367cb5ba5d5ba7894091535ce3a5dd23b35fd436e003196d89523e7705566","src/builder/possible_value.rs":"62268b9da9eec8f4d1904ebfbd3a288fb78cfa71c357efadced28f0378bcfb93","src/builder/regex.rs":"b18891310186ecdcca9bb611833b7188cc80fe72e9fef27b63fa076b880a1acb","src/builder/tests.rs":"995c7d6be608b94c6f392f1356eba0cb8adb9ca661ffeebf7ebe6e8ad01a868c","src/builder/usage_parser.rs":"91d1af89196116aac2c0fb021f42f43f954aa3252df264e19a02a0cf5911d16b","src/builder/value_hint.rs":"0dd974d495c313430898d28b79991a70983c9aa44e88fa9aa1776d3308935438","src/builder/value_parser.rs":"64bb7f4808bdf65f30cb434198038a06db556e5ca045d900da392cc1a3186896","src/derive.rs":"11eaddc27a06229322a6bbce4458cb1424e6a5805c79166cba342c2905093b51","src/error/context.rs":"1dc561c7877d7f9b90f04bb7915744f0b3cc4ac2aa928ae100b2825a97077142","src/error/kind.rs":"3b4f9dfe5be5843cec8380c8f8965dcb9d0beee0aaa02cadf8dcffd400626ede","src/error/mod.rs":"e5b60fee401975d95c460c2567d09e17972eaae336154a8b90d9c806083f63fa","src/lib.rs":"4a197eab3f447c58a266af4f9a787af5c98b18f4612f33d9189cce52f4f9de18","src/macros.rs":"72585e32051a6872bbb29e39f7e9f9a88334a03f39ec3c768984db2f38211001","src/mkeymap.rs":"3565a5bae5d6cdcf8ba41a24eb602c510a14e150c4a6d3085ad72a35778e9c5f","src/output/fmt.rs":"efb741b5854500d946c6c09763ece1badc2b9cd3efa616cb58012039836c2b7f","src/output/help.rs":"ebdd123d6b70279c25af4b08432b547498834853adf99821ff6c6cd65dd87d4e","src/output/mod.rs":"3a61f89a4568e95114a3ab839da8f3c4c92de2a228549308f5d1be076a474917","src/output/usage.rs":"1921d2fa362f111b3f9613fc98eb5e24686483fe112b337855da7eb17b643f71","src/parser/arg_matcher.rs":"0c9ae639ed241e8ff1f62cd9e5eab2de9e5db1be0e86f58d5d94619d6dad05fd","src/parser/error.rs":"51e8fbd7cc73bba78cca50417e9b4fb25e11eefc60ff4b957940176bdb995e5c","src/parser/features/mod.rs":"6ed075e97af56bff22f22ed1ee83ff6479360e05f9d3661a3145f822c242b694","src/parser/features/suggestions.rs":"79127956b2f1adb9d658925e2779ebebfe9ddea434408762fefb60afdb545f47","src/parser/matches/any_value.rs":"7b6e711fe205e8808394c562dd6a260b56ce350cf9298a308ba9727ab012b664","src/parser/matches/arg_matches.rs":"666e3640b5347aba5806fc15b5caa599b171e684ee15d933ddc7f8185a0d2032","src/parser/matches/matched_arg.rs":"fb12eb2afaf631bb60aa8c4e42b0f510a877d35a9eaa07a7afd253280c27c251","src/parser/matches/mod.rs":"1467aa752cb1c79d30e4aeaaa55e10a0bb9dcf6f3980496234251431c79c49e6","src/parser/matches/value_source.rs":"e6a477ae36f2f7155960239a97b7d142eef4eb227c41c9eefea147289547d713","src/parser/mod.rs":"358f46d3b7f43dec2563d4c35bd2536fab2491f28e300a9bcdeaf6ca0513ce12","src/parser/parser.rs":"9e338dfd60aa8bfbcfbbda15c73d4722767a4d2e7b8f8ed3a07c296ddd98762c","src/parser/validator.rs":"30066cb41ab23800231fb6b028cbce57d118570859659ebc67affbe5226f31f9","src/util/color.rs":"63df5e1cda1001b4c536dc0b04e09dd85dae6d317e34e660abbe3c71e17eaa29","src/util/fnv.rs":"82492d91d990f38b62de8b3c3e67f1fad55919117b1f448aa28acf6d21919fd7","src/util/graph.rs":"f35396b6e2a427377dcbbca69b1b98737d89684a3834cfda98cbf8cc70ff9c2f","src/util/id.rs":"fc498c65887385d92a51359a2f72556c2e508ee49b8cac4b3f827512795d690d","src/util/mod.rs":"8d328a15ef06989d0ce5e65cf3b7ec79c083984b25c0b31ba177bdb22df28a10","src/util/str_to_bool.rs":"1ce90b4939a884eeefc73392722bdfcf906e3070c4398e1557c586c10c684cd0"},"package":"23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"} \ No newline at end of file diff --git a/vendor/clap/Cargo.lock b/vendor/clap/Cargo.lock index 269dea5ad..57d007104 100644 --- a/vendor/clap/Cargo.lock +++ b/vendor/clap/Cargo.lock @@ -45,9 +45,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", @@ -66,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" [[package]] name = "cc" @@ -84,7 +84,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.5" +version = "3.2.20" dependencies = [ "atty", "backtrace", @@ -98,6 +98,7 @@ dependencies = [ "rustversion", "shlex", "snapbox", + "static_assertions", "strsim", "termcolor", "terminal_size", @@ -110,9 +111,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.5" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -123,9 +124,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] @@ -159,9 +160,9 @@ checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449" [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -180,33 +181,33 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", "memoffset", + "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ "cfg-if", - "lazy_static", + "once_cell", ] [[package]] name = "either" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" [[package]] name = "escargot" @@ -222,9 +223,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" [[package]] name = "glob" @@ -234,9 +235,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -271,9 +272,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -290,27 +291,21 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] -name = "lazy_static" -version = "1.4.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "libc" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "log" @@ -338,9 +333,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", ] @@ -363,18 +358,18 @@ dependencies = [ [[package]] name = "object" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "os_pipe" @@ -418,27 +413,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -448,9 +443,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -460,9 +455,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -471,9 +466,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rustc-demangle" @@ -483,15 +478,15 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "scopeguard" @@ -501,18 +496,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" dependencies = [ "proc-macro2", "quote", @@ -521,9 +516,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa", "ryu", @@ -563,6 +558,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -571,13 +572,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.92" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -620,9 +621,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba98375fd631b83696f87c64e4ed8e29e6a1f3404d6aed95fa95163bad38e705" +checksum = "5376256e44f2443f8896ac012507c19a012df0fe8758b55246ae51a2279db51f" dependencies = [ "combine", "indexmap", @@ -632,9 +633,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc92f558afb6d1d7c6f175eb8d615b8ef49c227543e68e19c123d4ee43d8a7d" +checksum = "764b9e244b482a9b81bde596aa37aa6f1347bf8007adab25e59f901b32b4e0a0" dependencies = [ "glob", "once_cell", @@ -672,16 +673,16 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.1.9" +name = "unicode-ident" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" [[package]] -name = "unicode-xid" -version = "0.2.3" +name = "unicode-width" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "version_check" diff --git a/vendor/clap/Cargo.toml b/vendor/clap/Cargo.toml index aba082f3a..197454c07 100644 --- a/vendor/clap/Cargo.toml +++ b/vendor/clap/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56.0" +rust-version = "1.56.1" name = "clap" -version = "3.2.5" +version = "3.2.20" include = [ "build.rs", "src/**/*", @@ -24,7 +24,6 @@ include = [ "examples/**/*", ] description = "A simple to use, efficient, and full-featured Command Line Argument Parser" -documentation = "https://docs.rs/clap/" readme = "README.md" keywords = [ "argument", @@ -91,27 +90,6 @@ replace = """ [Unreleased]: https://github.com/clap-rs/clap/compare/{{tag_name}}...HEAD""" exactly = 1 -[[package.metadata.release.pre-release-replacements]] -file = "README.md" -search = "github.com/clap-rs/clap/blob/[^/]+/" -replace = "github.com/clap-rs/clap/blob/{{tag_name}}/" -exactly = 13 -prerelease = true - -[[package.metadata.release.pre-release-replacements]] -file = "README.md" -search = 'version = "[a-z0-9\.-]+"' -replace = "version = \"{{version}}\"" -exactly = 1 -prerelease = true - -[[package.metadata.release.pre-release-replacements]] -file = "src/derive.rs" -search = "github.com/clap-rs/clap/blob/[^/]+/" -replace = "github.com/clap-rs/clap/blob/{{tag_name}}/" -exactly = 4 -prerelease = true - [profile.bench] lto = true codegen-units = 1 @@ -219,10 +197,7 @@ required-features = ["cargo"] [[example]] name = "04_01_enum" path = "examples/tutorial_builder/04_01_enum.rs" -required-features = [ - "cargo", - "derive", -] +required-features = ["cargo"] [[example]] name = "04_02_parse" @@ -373,7 +348,7 @@ optional = true version = "1.2" [dependencies.clap_derive] -version = "=3.2.5" +version = "=3.2.18" optional = true [dependencies.clap_lex] @@ -430,6 +405,9 @@ version = "1.1.0" [dev-dependencies.snapbox] version = "0.2.9" +[dev-dependencies.static_assertions] +version = "1.1.0" + [dev-dependencies.trybuild] version = "1.0.18" diff --git a/vendor/clap/LICENSE-MIT b/vendor/clap/LICENSE-MIT index 5acedf041..7b05b8453 100644 --- a/vendor/clap/LICENSE-MIT +++ b/vendor/clap/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2016 Kevin B. Knapp +Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/clap/README.md b/vendor/clap/README.md index 48b7a3cbd..eea6ba6f0 100644 --- a/vendor/clap/README.md +++ b/vendor/clap/README.md @@ -1,160 +1,24 @@ - # clap > **Command Line Argument Parser for Rust** [![Crates.io](https://img.shields.io/crates/v/clap?style=flat-square)](https://crates.io/crates/clap) [![Crates.io](https://img.shields.io/crates/d/clap?style=flat-square)](https://crates.io/crates/clap) -[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.2.5/LICENSE-APACHE) -[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.2.5/LICENSE-MIT) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](LICENSE-APACHE) +[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE-MIT) [![Build Status](https://img.shields.io/github/workflow/status/clap-rs/clap/CI/staging?style=flat-square)](https://github.com/clap-rs/clap/actions/workflows/ci.yml?query=branch%3Astaging) [![Coverage Status](https://img.shields.io/coveralls/github/clap-rs/clap/master?style=flat-square)](https://coveralls.io/github/clap-rs/clap?branch=master) [![Contributors](https://img.shields.io/github/contributors/clap-rs/clap?style=flat-square)](https://github.com/clap-rs/clap/graphs/contributors) Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT). -1. [About](#about) -2. Tutorial: [Builder API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_builder/README.md), [Derive API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_derive/README.md) -3. [Examples](https://github.com/clap-rs/clap/blob/v3.2.5/examples/README.md) -4. [API Reference](https://docs.rs/clap) - - [Derive Reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) - - [Feature Flags](#feature-flags) -5. [CHANGELOG](https://github.com/clap-rs/clap/blob/v3.2.5/CHANGELOG.md) -6. [FAQ](https://github.com/clap-rs/clap/blob/v3.2.5/docs/FAQ.md) -7. [Questions & Discussions](https://github.com/clap-rs/clap/discussions) -8. [Contributing](https://github.com/clap-rs/clap/blob/v3.2.5/CONTRIBUTING.md) -8. [Sponsors](#sponsors) - ## About Create your command-line parser, with all of the bells and whistles, declaratively or procedurally. -### Example - -This uses our -[Derive API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_derive/README.md) -which provides access to the [Builder API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_builder/README.md) as attributes on a `struct`: - - -```rust,no_run -use clap::Parser; - -/// Simple program to greet a person -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct Args { - /// Name of the person to greet - #[clap(short, long, value_parser)] - name: String, - - /// Number of times to greet - #[clap(short, long, value_parser, default_value_t = 1)] - count: u8, -} - -fn main() { - let args = Args::parse(); - - for _ in 0..args.count { - println!("Hello {}!", args.name) - } -} -``` -Add this to `Cargo.toml`: -```toml -[dependencies] -clap = { version = "3.2.5", features = ["derive"] } -``` -```bash -$ demo --help -clap [..] -Simple program to greet a person - -USAGE: - demo[EXE] [OPTIONS] --name - -OPTIONS: - -c, --count Number of times to greet [default: 1] - -h, --help Print help information - -n, --name Name of the person to greet - -V, --version Print version information -``` -*(version number and `.exe` extension on windows replaced by placeholders)* - -### Aspirations - -- Out of the box, users get a polished CLI experience - - Including common argument behavior, help generation, suggested fixes for users, colored output, [shell completions](https://github.com/clap-rs/clap/tree/master/clap_complete), etc -- Flexible enough to port your existing CLI interface - - However, we won't necessarily streamline support for each use case -- Reasonable parse performance -- Resilient maintainership, including - - Willing to break compatibility rather than batching up breaking changes in large releases - - Leverage feature flags to keep to one active branch - - Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor -- We follow semver and will wait about 6-9 months between major breaking changes -- We will support the last two minor Rust releases (MSRV, currently 1.56.0) - -While these aspirations can be at odds with fast build times and low binary -size, we will still strive to keep these reasonable for the flexibility you -get. Check out the -[argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for -CLI parsers optimized for other use cases. - -### Selecting an API - -Why use the declarative [Derive API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_derive/README.md): -- Easier to read, write, and modify -- Easier to keep the argument declaration and reading of argument in sync -- Easier to reuse, e.g. [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag) - -Why use the procedural [Builder API](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_builder/README.md): -- Faster compile times if you aren't already using other procedural macros -- More flexible, e.g. you can look up how many times an argument showed up, - what its values were, and what were the indexes of those values. The Derive - API can only report presence, number of occurrences, or values but no indices - or combinations of data. - -### Related Projects - -- [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux -- [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files) -- [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version` -- [clap_lex](https://crates.io/crates/clap_lex) for a lighter-weight, battle-tested CLI parser -- [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff) -- [clap_complete](https://crates.io/crates/clap_complete) for shell completion support -- [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag) -- [clap-cargo](https://crates.io/crates/clap-cargo) -- [concolor-clap](https://crates.io/crates/concolor-clap) -- [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book -- [`trycmd`](https://crates.io/crates/trycmd): Snapshot testing - - Or for more control, [`assert_cmd`](https://crates.io/crates/assert_cmd) and [`assert_fs`](https://crates.io/crates/assert_fs) - -## Feature Flags - -### Default Features - -* **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner. -* **color**: Turns on colored error messages. -* **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. - -#### Optional features - -* **deprecated**: Guided experience to prepare for next breaking release (at different stages of development, this may become default) -* **derive**: Enables the custom derive (i.e. `#[derive(Parser)]`). Without this you must use one of the other methods of creating a `clap` CLI listed above. -* **cargo**: Turns on macros that read values from `CARGO_*` environment variables. -* **env**: Turns on the usage of environment variables during parsing. -* **regex**: Enables regex validators. -* **unicode**: Turns on support for unicode characters (including emoji) in arguments and help messages. -* **wrap_help**: Turns on the help text wrapping feature, based on the terminal size. - -#### Experimental features - -**Warning:** These may contain breaking changes between minor releases. - -* **unstable-replace**: Enable [`Command::replace`](https://github.com/clap-rs/clap/issues/2836) -* **unstable-grouped**: Enable [`ArgMatches::grouped_values_of`](https://github.com/clap-rs/clap/issues/2924) -* **unstable-v4**: Preview features which will be stable on the v4.0 release +For more details, see: +- [docs.rs](https://docs.rs/clap/latest/clap/) +- [examples](examples/) ## Sponsors diff --git a/vendor/clap/examples/README.md b/vendor/clap/examples/README.md deleted file mode 100644 index 2034ab80e..000000000 --- a/vendor/clap/examples/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Examples - -- Basic demo: [derive](demo.md) -- Typed arguments: [derive](typed-derive.md) - - Topics: - - Custom `parse()` -- Custom cargo command: [builder](cargo-example.md), [derive](cargo-example-derive.md) - - Topics: - - Subcommands - - Cargo plugins -- git-like interface: [builder](git.md), [derive](git-derive.md) - - Topics: - - Subcommands - - External subcommands - - Optional subcommands - - Default subcommands -- pacman-like interface: [builder](pacman.md) - - Topics: - - Flag subcommands - - Conflicting arguments -- Escaped positionals with `--`: [builder](escaped-positional.md), [derive](escaped-positional-derive.md) -- Multi-call - - busybox: [builder](multicall-busybox.md) - - Topics: - - Subcommands - - hostname: [builder](multicall-hostname.md) - - Topics: - - Subcommands -- repl: [builder](repl.rs) - - Topics: - - Read-Eval-Print Loops / Custom command lines - -## Contributing - -New examples: -- Building: They must be added to [Cargo.toml](../Cargo.toml) with the appropriate `required-features`. -- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax -- Link the `.md` file from here - -See also the general [CONTRIBUTING](../CONTRIBUTING.md). diff --git a/vendor/clap/examples/cargo-example-derive.md b/vendor/clap/examples/cargo-example-derive.md index 994c6d4d8..2c7a11b88 100644 --- a/vendor/clap/examples/cargo-example-derive.md +++ b/vendor/clap/examples/cargo-example-derive.md @@ -1,5 +1,3 @@ -*Jump to [source](cargo-example-derive.rs)* - For more on creating a custom subcommand, see [the cargo book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands). The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in diff --git a/vendor/clap/examples/cargo-example-derive.rs b/vendor/clap/examples/cargo-example-derive.rs index 6667a4a7d..f0aad29c7 100644 --- a/vendor/clap/examples/cargo-example-derive.rs +++ b/vendor/clap/examples/cargo-example-derive.rs @@ -1,8 +1,6 @@ -// Note: this requires the `derive` feature - use clap::Parser; -#[derive(Parser)] +#[derive(Parser)] // requires `derive` feature #[clap(name = "cargo")] #[clap(bin_name = "cargo")] enum Cargo { diff --git a/vendor/clap/examples/cargo-example.md b/vendor/clap/examples/cargo-example.md index 9279cc492..6fb6a3c4d 100644 --- a/vendor/clap/examples/cargo-example.md +++ b/vendor/clap/examples/cargo-example.md @@ -1,5 +1,3 @@ -*Jump to [source](cargo-example.rs)* - For more on creating a custom subcommand, see [the cargo book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands). The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in diff --git a/vendor/clap/examples/cargo-example.rs b/vendor/clap/examples/cargo-example.rs index 45ae67c81..d9a909f4f 100644 --- a/vendor/clap/examples/cargo-example.rs +++ b/vendor/clap/examples/cargo-example.rs @@ -1,5 +1,3 @@ -// Note: this requires the `cargo` feature - fn main() { let cmd = clap::Command::new("cargo") .bin_name("cargo") diff --git a/vendor/clap/examples/demo.md b/vendor/clap/examples/demo.md index 9b0e7e260..93ee49c37 100644 --- a/vendor/clap/examples/demo.md +++ b/vendor/clap/examples/demo.md @@ -1,8 +1,3 @@ -*Jump to [source](demo.rs)* - -**This requires enabling the `derive` feature flag.** - -Used to validate README.md's content ```console $ demo --help clap [..] @@ -17,4 +12,8 @@ OPTIONS: -n, --name Name of the person to greet -V, --version Print version information +$ demo --name Me +Hello Me! + ``` +*(version number and `.exe` extension on windows replaced by placeholders)* diff --git a/vendor/clap/examples/demo.rs b/vendor/clap/examples/demo.rs index 957489724..a7cecfb0c 100644 --- a/vendor/clap/examples/demo.rs +++ b/vendor/clap/examples/demo.rs @@ -1,5 +1,3 @@ -// Note: this requires the `derive` feature - use clap::Parser; /// Simple program to greet a person diff --git a/vendor/clap/examples/derive_ref/README.md b/vendor/clap/examples/derive_ref/README.md deleted file mode 100644 index a3b0c084d..000000000 --- a/vendor/clap/examples/derive_ref/README.md +++ /dev/null @@ -1,440 +0,0 @@ -# Derive Reference - -1. [Overview](#overview) -2. [Attributes](#attributes) - 1. [Terminology](#terminology) - 2. [Command Attributes](#command-attributes) - 3. [Arg Attributes](#arg-attributes) - 4. [Arg Enum Attributes](#arg-enum-attributes) - 5. [Possible Value Attributes](#possible-value-attributes) -3. [Arg Types](#arg-types) -4. [Doc Comments](#doc-comments) -5. [Tips](#tips) -6. [Mixing Builder and Derive APIS](#mixing-builder-and-derive-apis) - -## Overview - -To derive `clap` types, you need to enable the `derive` feature flag. - -See [demo.rs](../demo.rs) and [demo.md](../demo.md) for a brief example. - -Let's start by breaking down the anatomy of the derive attributes: -```rust -use clap::{Parser, Args, Subcommand, ValueEnum}; - -/// Doc comment -#[derive(Parser)] -#[clap(APP ATTRIBUTE)] -struct Cli { - /// Doc comment - #[clap(ARG ATTRIBUTE)] - field: UserType, - - #[clap(value_enum, ARG ATTRIBUTE...)] - field: EnumValues, - - #[clap(flatten)] - delegate: Struct, - - #[clap(subcommand)] - command: Command, -} - -/// Doc comment -#[derive(Args)] -#[clap(PARENT APP ATTRIBUTE)] -struct Struct { - /// Doc comment - #[clap(ARG ATTRIBUTE)] - field: UserType, -} - -/// Doc comment -#[derive(Subcommand)] -#[clap(PARENT APP ATTRIBUTE)] -enum Command { - /// Doc comment - #[clap(APP ATTRIBUTE)] - Variant1(Struct), - - /// Doc comment - #[clap(APP ATTRIBUTE)] - Variant2 { - /// Doc comment - #[clap(ARG ATTRIBUTE)] - field: UserType, - } -} - -/// Doc comment -#[derive(ValueEnum)] -#[clap(ARG ENUM ATTRIBUTE)] -enum EnumValues { - /// Doc comment - #[clap(POSSIBLE VALUE ATTRIBUTE)] - Variant1, -} - -fn main() { - let cli = Cli::parse(); -} -``` - -- `Parser` parses arguments into a `struct` (arguments) or `enum` (subcommands). -- `Args` allows defining a set of re-usable arguments that get merged into their parent container. -- `Subcommand` defines available subcommands. - - Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant. -- `ValueEnum` allows parsing a value directly into an `enum`, erroring on unsupported values. - - The derive doesn't work on enums that contain non-unit variants, unless they are skipped - -See also the [tutorial](../tutorial_derive/README.md) and [examples](../README.md). - -## Attributes - -### Terminology - -**Raw attributes** are forwarded directly to the underlying `clap` builder. Any -`Command`, `Arg`, or `PossibleValue` method can be used as an attribute. - -Raw attributes come in two different syntaxes: -```rust -#[clap( - global = true, // name = arg form, neat for one-arg methods - required_if_eq("out", "file") // name(arg1, arg2, ...) form. -)] -``` - -- `method = arg` can only be used for methods which take only one argument. -- `method(arg1, arg2)` can be used with any method. - -As long as `method_name` is not one of the magical methods - it will be -translated into a mere method call. - -**Magic attributes** have post-processing done to them, whether that is -- Providing of defaults -- Special behavior is triggered off of it - -Magic attributes are more constrained in the syntax they support, usually just -` = ` though some use `()` instead. See the specific -magic attributes documentation for details. This allows users to access the -raw behavior of an attribute via `()` syntax. - -**NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc -Comments](#doc-comments). Explicit attributes take precedence over inferred -attributes. - -### Command Attributes - -These correspond to a `clap::Command` which is used for both top-level parsers and -when defining subcommands. - -**Raw attributes:** Any [`Command` method](https://docs.rs/clap/latest/clap/type.Command.html) can also be used as an attribute, see [Terminology](#terminology) for syntax. -- e.g. `#[clap(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)` - -**Magic attributes:** -- `name = `: `clap::Command::name` - - When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (`Parser` container), variant name (`Subcommand` variant) -- `version [= ]`: `clap::Command::version` - - When not present: no version set - - Without ``: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field) -- `author [= ]`: `clap::Command::author` - - When not present: no author set - - Without ``: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field) -- `about [= ]`: `clap::Command::about` - - When not present: [Doc comment summary](#doc-comments) - - Without ``: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) (`Parser` container) - - **TIP:** When a doc comment is also present, you most likely want to add - `#[clap(long_about = None)]` to clear the doc comment so only `about` - gets shown with both `-h` and `--help`. -- `long_about = `: `clap::Command::long_about` - - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing -- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `about` / `long_about` -- `next_display_order`: `clap::Command::next_display_order` -- `next_help_heading`: `clap::Command::next_help_heading` - - When `flatten`ing `Args`, this is scoped to just the args in this struct and any struct `flatten`ed into it -- `rename_all = `: Override default field / variant name case conversion for `Command::name` / `Arg::name` - - When not present: `kebab-case` - - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim` -- `rename_all_env = `: Override default field name case conversion for env variables for `clap::Arg::env` - - When not present: `SCREAMING_SNAKE_CASE` - - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim` - -And for `Subcommand` variants: -- `skip`: Ignore this variant -- `flatten`: Delegates to the variant for more subcommands (must implement `Subcommand`) -- `subcommand`: Nest subcommands under the current set of subcommands (must implement `Subcommand`) -- `external_subcommand`: `clap::Command::allow_external_subcommand(true)` - - Variant must be either `Variant(Vec)` or `Variant(Vec)` - -### Arg Attributes - -These correspond to a `clap::Arg`. - -**Raw attributes:** Any [`Arg` method](https://docs.rs/clap/latest/clap/struct.Arg.html) can also be used as an attribute, see [Terminology](#terminology) for syntax. -- e.g. `#[clap(max_values(3))]` would translate to `arg.max_values(3)` - -**Magic attributes**: -- `name = `: `clap::Arg::new` - - When not present: case-converted field name is used -- `value_parser [= ]`: `clap::Arg::value_parser` - - When not present: will auto-select an implementation based on the field type - - To register a custom type's `ValueParser`, implement `ValueParserFactory` - - When present, implies `#[clap(action)]` -- `action [= ]`: `clap::Arg::action` - - When not present: will auto-select an action based on the field type - - When present, implies `#[clap(value_parser)]` -- `help = `: `clap::Arg::help` - - When not present: [Doc comment summary](#doc-comments) -- `long_help = `: `clap::Arg::long_help` - - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing -- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `help` / `long_help` -- `short [= ]`: `clap::Arg::short` - - When not present: no short set - - Without ``: defaults to first character in the case-converted field name -- `long [= ]`: `clap::Arg::long` - - When not present: no long set - - Without ``: defaults to the case-converted field name -- `env [= ]`: `clap::Arg::env` (needs `env` feature enabled) - - When not present: no env set - - Without ``: defaults to the case-converted field name -- `flatten`: Delegates to the field for more arguments (must implement `Args`) - - Only `help_heading` can be used with `flatten`. See - [clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why - arg attributes are not generally supported. - - **Tip:** Though we do apply a flattened `Args`'s Parent Command Attributes, this - makes reuse harder. Generally prefer putting the cmd attributes on the `Parser` - or on the flattened field. -- `subcommand`: Delegates definition of subcommands to the field (must implement `Subcommand`) - - When `Option`, the subcommand becomes optional -- `from_global`: Read a `clap::Arg::global` argument (raw attribute), regardless of what subcommand you are in -- `parse( [= ])`: `clap::Arg::validator` and `clap::ArgMatches::values_of_t` - - **Deprecated:** - - Use `value_parser(...)` for `from_str`, `try_from_str`, `from_os_str`, and `try_from_os_str` - - Use `action(ArgAction::Count` for `from_occurrences` - - Use `action(ArgAction::SetTrue` for `from_flag` - - Default: `try_from_str` - - Warning: for `Path` / `OsString`, be sure to use `try_from_os_str` - - See [Arg Types](#arg-types) for more details -- `value_enum`: Parse the value using the `ValueEnum` trait -- `skip [= ]`: Ignore this field, filling in with `` - - Without ``: fills the field with `Default::default()` -- `default_value = `: `clap::Arg::default_value` and `clap::Arg::required(false)` -- `default_value_t [= ]`: `clap::Arg::default_value` and `clap::Arg::required(false)` - - Requires `std::fmt::Display` or `#[clap(value_enum)]` - - Without ``, relies on `Default::default()` -- `default_value_os_t [= ]`: `clap::Arg::default_value_os` and `clap::Arg::required(false)` - - Requires `std::convert::Into` or `#[clap(value_enum)]` - - Without ``, relies on `Default::default()` - -### Arg Enum Attributes - -- `rename_all = `: Override default field / variant name case conversion for `PossibleValue::new` - - When not present: `kebab-case` - - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim` - -### Possible Value Attributes - -These correspond to a `clap::PossibleValue`. - -**Raw attributes:** Any [`PossibleValue` method](https://docs.rs/clap/latest/clap/struct.PossibleValue.html) can also be used as an attribute, see [Terminology](#terminology) for syntax. -- e.g. `#[clap(alias("foo"))]` would translate to `pv.alias("foo")` - -**Magic attributes**: -- `name = `: `clap::PossibleValue::new` - - When not present: case-converted field name is used -- `help = `: `clap::PossibleValue::help` - - When not present: [Doc comment summary](#doc-comments) - -## Arg Types - -`clap` assumes some intent based on the type used: - -| Type | Effect | Implies | -|---------------------|--------------------------------------|------------------------------------------------------------------| -| `bool` | flag | `#[clap(parse(from_flag))]` | -| `Option` | optional argument | `.takes_value(true).required(false)` | -| `Option>` | optional value for optional argument | `.takes_value(true).required(false).min_values(0).max_values(1)` | -| `T` | required argument | `.takes_value(true).required(!has_default)` | -| `Vec` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` | -| `Option>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` | - -Notes: -- For custom type behavior, you can override the implied attributes/settings and/or set additional ones - - For example, see [custom-bool](./custom-bool.md) -- `Option>` will be `None` instead of `vec![]` if no arguments are provided. - - This gives the user some flexibility in designing their argument, like with `min_values(0)` - -You can then support your custom type with `#[clap(parse( [= ]))]`: - -| `` | Signature | Default `` | -|--------------------------|---------------------------------------|---------------------------------| -| `from_str` | `fn(&str) -> T` | `::std::convert::From::from` | -| `try_from_str` (default) | `fn(&str) -> Result` | `::std::str::FromStr::from_str` | -| `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` | -| `try_from_os_str` | `fn(&OsStr) -> Result` | (no default function) | -| `from_occurrences` | `fn(u64) -> T` | `value as T` | -| `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` | - -Notes: -- `from_os_str`: - - Implies `arg.takes_value(true).allow_invalid_utf8(true)` -- `try_from_os_str`: - - Implies `arg.takes_value(true).allow_invalid_utf8(true)` -- `from_occurrences`: - - Implies `arg.takes_value(false).multiple_occurrences(true)` - - Reads from `clap::ArgMatches::occurrences_of` rather than a `get_one` function - - Note: operations on values, like `default_value`, are unlikely to do what you want -- `from_flag` - - Implies `arg.takes_value(false)` - - Reads from `clap::ArgMatches::is_present` rather than a `get_one` function - - Note: operations on values, like `default_value`, are unlikely to do what you want - -**Warning:** -- To support non-UTF8 paths, you should use `#[clap(value_parser)]` otherwise - `clap` will parse it as a `String` which will fail on some paths. - -## Doc Comments - -In clap, help messages for the whole binary can be specified -via [`Command::about`] and [`Command::long_about`] while help messages -for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]". - -`long_*` variants are used when user calls the program with -`--help` and "short" variants are used with `-h` flag. - -```rust -# use clap::Parser; - -#[derive(Parser)] -#[clap(about = "I am a program and I work, just pass `-h`", long_about = None)] -struct Foo { - #[clap(short, help = "Pass `-h` and you'll see me!")] - bar: String, -} -``` - -For convenience, doc comments can be used instead of raw methods -(this example works exactly like the one above): - -```rust -# use clap::Parser; - -#[derive(Parser)] -/// I am a program and I work, just pass `-h` -struct Foo { - /// Pass `-h` and you'll see me! - bar: String, -} -``` - -**NOTE:** Attributes have priority over doc comments! - -**Top level doc comments always generate `Command::about/long_about` calls!** -If you really want to use the `Command::about/long_about` methods (you likely don't), -use the `about` / `long_about` attributes to override the calls generated from -the doc comment. To clear `long_about`, you can use -`#[clap(long_about = None)]`. - -**TIP:** Set `#![deny(missing_docs)]` to catch missing `--help` documentation at compile time. - -### Pre-processing - -```rust -# use clap::Parser; -#[derive(Parser)] -/// Hi there, I'm Robo! -/// -/// I like beeping, stumbling, eating your electricity, -/// and making records of you singing in a shower. -/// Pay up, or I'll upload it to youtube! -struct Robo { - /// Call my brother SkyNet. - /// - /// I am artificial superintelligence. I won't rest - /// until I'll have destroyed humanity. Enjoy your - /// pathetic existence, you mere mortals. - #[clap(long, action)] - kill_all_humans: bool, -} -``` - -A doc comment consists of three parts: -- Short summary -- A blank line (whitespace only) -- Detailed description, all the rest - -The summary corresponds with `Command::about` / `Arg::help`. When a blank line is -present, the whole doc comment will be passed to `Command::long_about` / -`Arg::long_help`. Or in other words, a doc may result in just a `Command::about` / -`Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` / -`Arg::long_help` - -In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including: - -- Strip leading and trailing whitespace from every line, if present. - -- Strip leading and trailing blank lines, if present. - -- Interpret each group of non-empty lines as a word-wrapped paragraph. - - We replace newlines within paragraphs with spaces to allow the output - to be re-wrapped to the terminal width. - -- Strip any excess blank lines so that there is exactly one per paragraph break. - -- If the first paragraph ends in exactly one period, - remove the trailing period (i.e. strip trailing periods but not trailing ellipses). - -Sometimes you don't want this preprocessing to apply, for example the comment contains -some ASCII art or markdown tables, you would need to preserve LFs along with -blank lines and the leading/trailing whitespace. When you pass use the -`verbatim_doc_comment` magic attribute, you preserve -them. - -**Note:** Keep in mind that `verbatim_doc_comment` will *still* -- Remove one leading space from each line, even if this attribute is present, - to allow for a space between `///` and the content. -- Remove leading and trailing blank lines - -## Tips - -- To get access to a `Command` call `CommandFactory::command` (implemented when deriving `Parser`) -- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](../tutorial_derive/05_01_assert.rs)) - -## Mixing Builder and Derive APIs - -The builder and derive APIs do not live in isolation. They can work together, which is especially helpful if some arguments can be specified at compile-time while others must be specified at runtime. - -### Using derived arguments in a builder application - -*[Jump to source](augment_args.rs)* - -When using the derive API, you can `#[clap(flatten)]` a struct deriving `Args` into a struct deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance created using the builder API with `Args` created using the derive API. - -It uses the `Args::augment_args` method to add the arguments to the `Command` instance. - -Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide structs that implement `Args` or `Parser`. Without the technique shown in this example, it would not be possible to use such crates with the builder API. `augment_args` to the rescue! - -### Using derived subcommands in a builder application - -*[Jump to source](augment_subcommands.rs)* - -When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also add the subcommands in that enum to a `Command` instance created with the builder API. - -It uses the `Subcommand::augment_subcommands` method to add the subcommands to the `Command` instance. - -### Adding hand-implemented subcommands to a derived application - -*[Jump to source](hand_subcommand.rs)* - -When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also implement the `Subcommand` trait manually on this enum (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance created behind the scenes for you by the derive API. - -Notice how in the previous example we used `augment_subcommands` on an enum that derived `Parser`, whereas now we implement `augment_subcommands` ourselves, but the derive API calls it automatically since we used the `#[clap(subcommand)]` attribute. - -### Flattening hand-implemented args into a derived application - -*[Jump to source](flatten_hand_args.rs)* - -When using the derive API, you can use `#[clap(flatten)]` inside the struct to add arguments as if they were added directly to the containing struct. The type of the field is usually an struct that derived `Args`. However, you can also implement the `Args` trait manually on this struct (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Args` trait will use the builder API to add the arguments to the `Command` instance created behind the scenes for you by the derive API. - -Notice how in the example 1 we used `augment_args` on the struct that derived `Parser`, whereas now we implement `augment_args` ourselves, but the derive API calls it automatically since we used the `#[clap(flatten)]` attribute. diff --git a/vendor/clap/examples/derive_ref/augment_args.rs b/vendor/clap/examples/derive_ref/augment_args.rs index 390c72f4a..310556914 100644 --- a/vendor/clap/examples/derive_ref/augment_args.rs +++ b/vendor/clap/examples/derive_ref/augment_args.rs @@ -1,6 +1,6 @@ -use clap::{arg, Args as _, Command, FromArgMatches as _, Parser}; +use clap::{arg, Args, Command, FromArgMatches as _}; -#[derive(Parser, Debug)] +#[derive(Args, Debug)] struct DerivedArgs { #[clap(short, long, action)] derived: bool, @@ -12,13 +12,10 @@ fn main() { let cli = DerivedArgs::augment_args(cli); let matches = cli.get_matches(); - println!( - "Value of built: {:?}", - *matches.get_one::("built").unwrap() - ); + println!("Value of built: {:?}", matches.get_flag("built")); println!( "Value of derived via ArgMatches: {:?}", - *matches.get_one::("derived").unwrap() + matches.get_flag("derived") ); // Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches. diff --git a/vendor/clap/examples/derive_ref/flatten_hand_args.rs b/vendor/clap/examples/derive_ref/flatten_hand_args.rs index 74d10edec..c10e0b29f 100644 --- a/vendor/clap/examples/derive_ref/flatten_hand_args.rs +++ b/vendor/clap/examples/derive_ref/flatten_hand_args.rs @@ -15,8 +15,8 @@ impl FromArgMatches for CliArgs { } fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result { Ok(Self { - foo: *matches.get_one::("foo").expect("defaulted by clap"), - bar: *matches.get_one::("bar").expect("defaulted by clap"), + foo: matches.get_flag("foo"), + bar: matches.get_flag("bar"), quuz: matches.remove_one::("quuz"), }) } @@ -25,8 +25,8 @@ impl FromArgMatches for CliArgs { self.update_from_arg_matches_mut(&mut matches) } fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> { - self.foo |= *matches.get_one::("foo").expect("defaulted by clap"); - self.bar |= *matches.get_one::("bar").expect("defaulted by clap"); + self.foo |= matches.get_flag("foo"); + self.bar |= matches.get_flag("bar"); if let Some(quuz) = matches.remove_one::("quuz") { self.quuz = Some(quuz); } diff --git a/vendor/clap/examples/escaped-positional-derive.md b/vendor/clap/examples/escaped-positional-derive.md index 3b5f8fe56..fa39a2c03 100644 --- a/vendor/clap/examples/escaped-positional-derive.md +++ b/vendor/clap/examples/escaped-positional-derive.md @@ -1,6 +1,4 @@ -*Jump to [source](escaped-positional-derive.rs)* - -**This requires enabling the `derive` feature flag.** +**This requires enabling the [`derive` feature flag][crate::_features].** You can use `--` to escape further arguments. diff --git a/vendor/clap/examples/escaped-positional-derive.rs b/vendor/clap/examples/escaped-positional-derive.rs index 54dbc853b..fd8fde4ed 100644 --- a/vendor/clap/examples/escaped-positional-derive.rs +++ b/vendor/clap/examples/escaped-positional-derive.rs @@ -1,8 +1,6 @@ -// Note: this requires the `derive` feature - use clap::Parser; -#[derive(Parser)] +#[derive(Parser)] // requires `derive` feature #[clap(author, version, about, long_about = None)] struct Cli { #[clap(short = 'f', action)] diff --git a/vendor/clap/examples/escaped-positional.md b/vendor/clap/examples/escaped-positional.md index 1f71a8736..987b26139 100644 --- a/vendor/clap/examples/escaped-positional.md +++ b/vendor/clap/examples/escaped-positional.md @@ -1,6 +1,4 @@ -*Jump to [source](escaped-positional.rs)* - -**This requires enabling the `cargo` feature flag.** +**This requires enabling the [`cargo` feature flag][crate::_features].** You can use `--` to escape further arguments. diff --git a/vendor/clap/examples/escaped-positional.rs b/vendor/clap/examples/escaped-positional.rs index a0fff790b..fdcb930fb 100644 --- a/vendor/clap/examples/escaped-positional.rs +++ b/vendor/clap/examples/escaped-positional.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, value_parser, ArgAction}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg(arg!(eff: -f).action(ArgAction::SetTrue)) .arg( arg!(pea: -p ) @@ -22,10 +20,7 @@ fn main() { // This is what will happen with `myprog -f -p=bob -- sloppy slop slop`... // -f used: true - println!( - "-f used: {:?}", - *matches.get_one::("eff").expect("defaulted by clap") - ); + println!("-f used: {:?}", matches.get_flag("eff")); // -p's value: Some("bob") println!("-p's value: {:?}", matches.get_one::("pea")); // 'slops' values: Some(["sloppy", "slop", "slop"]) diff --git a/vendor/clap/examples/git-derive.md b/vendor/clap/examples/git-derive.md index dc27776f5..aa1ca6d9d 100644 --- a/vendor/clap/examples/git-derive.md +++ b/vendor/clap/examples/git-derive.md @@ -1,6 +1,4 @@ -*Jump to [source](git-derive.rs)* - -**This requires enabling the `derive` feature flag.** +**This requires enabling the [`derive` feature flag][crate::_features].** Git is an example of several common subcommand patterns. diff --git a/vendor/clap/examples/git-derive.rs b/vendor/clap/examples/git-derive.rs index ecbda3fe9..ac500ddad 100644 --- a/vendor/clap/examples/git-derive.rs +++ b/vendor/clap/examples/git-derive.rs @@ -1,12 +1,10 @@ -// Note: this requires the `derive` feature - use std::ffi::OsString; use std::path::PathBuf; use clap::{Args, Parser, Subcommand}; /// A fictional versioning CLI -#[derive(Debug, Parser)] +#[derive(Debug, Parser)] // requires `derive` feature #[clap(name = "git")] #[clap(about = "A fictional versioning CLI", long_about = None)] struct Cli { diff --git a/vendor/clap/examples/git.md b/vendor/clap/examples/git.md index 2cdfe653b..9e413415a 100644 --- a/vendor/clap/examples/git.md +++ b/vendor/clap/examples/git.md @@ -1,5 +1,3 @@ -*Jump to [source](git.rs)* - Git is an example of several common subcommand patterns. Help: diff --git a/vendor/clap/examples/git.rs b/vendor/clap/examples/git.rs index 5536f1487..e56f427a6 100644 --- a/vendor/clap/examples/git.rs +++ b/vendor/clap/examples/git.rs @@ -1,5 +1,3 @@ -// Note: this requires the `cargo` feature - use std::ffi::OsString; use std::path::PathBuf; diff --git a/vendor/clap/examples/multicall-busybox.md b/vendor/clap/examples/multicall-busybox.md index a09418403..5ca2cad5b 100644 --- a/vendor/clap/examples/multicall-busybox.md +++ b/vendor/clap/examples/multicall-busybox.md @@ -1,8 +1,4 @@ -*Jump to [source](multicall-busybox.rs)* - -Example of a busybox-style multicall program - -See the documentation for `clap::Command::multicall` for rationale. +See the documentation for [`Command::multicall`][crate::App::multicall] for rationale. This example omits every command except true and false, which are the most trivial to implement, diff --git a/vendor/clap/examples/multicall-hostname.md b/vendor/clap/examples/multicall-hostname.md index 9e17ca16c..d22b85fba 100644 --- a/vendor/clap/examples/multicall-hostname.md +++ b/vendor/clap/examples/multicall-hostname.md @@ -1,8 +1,4 @@ -*Jump to [source](multicall-hostname.rs)* - -Example of a `hostname-style` multicall program - -See the documentation for `clap::Command::multicall` for rationale. +See the documentation for [`Command::multicall`][crate::App::multicall] for rationale. This example omits the implementation of displaying address config diff --git a/vendor/clap/examples/pacman.md b/vendor/clap/examples/pacman.md index 7f6c5a7d3..b8ddd09d9 100644 --- a/vendor/clap/examples/pacman.md +++ b/vendor/clap/examples/pacman.md @@ -1,5 +1,3 @@ -*Jump to [source](pacman.rs)* - [`pacman`](https://wiki.archlinux.org/index.php/pacman) defines subcommands via flags. Here, `-S` is a short flag subcommand: diff --git a/vendor/clap/examples/pacman.rs b/vendor/clap/examples/pacman.rs index 6a60a8bf5..aee7cd892 100644 --- a/vendor/clap/examples/pacman.rs +++ b/vendor/clap/examples/pacman.rs @@ -89,10 +89,7 @@ fn main() { .collect(); let values = packages.join(", "); - if *sync_matches - .get_one::("info") - .expect("defaulted by clap") - { + if sync_matches.get_flag("info") { println!("Retrieving info for {}...", values); } else { println!("Installing {}...", values); diff --git a/vendor/clap/examples/tutorial_builder/01_quick.md b/vendor/clap/examples/tutorial_builder/01_quick.md new file mode 100644 index 000000000..4a9e3fca1 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/01_quick.md @@ -0,0 +1,37 @@ +```console +$ 01_quick --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 01_quick[EXE] [OPTIONS] [name] [SUBCOMMAND] + +ARGS: + Optional name to operate on + +OPTIONS: + -c, --config Sets a custom config file + -d, --debug Turn debugging information on + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + test does testing things + +``` + +By default, the program does nothing: +```console +$ 01_quick +Debug mode is off + +``` + +But you can mix and match the various features +```console +$ 01_quick -dd test +Debug mode is on +Not printing testing lists... + +``` diff --git a/vendor/clap/examples/tutorial_builder/01_quick.rs b/vendor/clap/examples/tutorial_builder/01_quick.rs index 61cc3432d..393d6aeae 100644 --- a/vendor/clap/examples/tutorial_builder/01_quick.rs +++ b/vendor/clap/examples/tutorial_builder/01_quick.rs @@ -1,11 +1,9 @@ -// Note: this requires the `cargo` feature - use std::path::PathBuf; use clap::{arg, command, value_parser, ArgAction, Command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg(arg!([name] "Optional name to operate on")) .arg( arg!( diff --git a/vendor/clap/examples/tutorial_builder/02_app_settings.md b/vendor/clap/examples/tutorial_builder/02_app_settings.md new file mode 100644 index 000000000..247843bcf --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/02_app_settings.md @@ -0,0 +1,19 @@ +```console +$ 02_app_settings --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_app_settings[EXE] --two --one + +OPTIONS: + --two + --one + -h, --help Print help information + -V, --version Print version information + +$ 02_app_settings --one -1 --one -3 --two 10 +two: "10" +one: "-3" + +``` diff --git a/vendor/clap/examples/tutorial_builder/02_app_settings.rs b/vendor/clap/examples/tutorial_builder/02_app_settings.rs index 7bbedd3eb..5f374d7f0 100644 --- a/vendor/clap/examples/tutorial_builder/02_app_settings.rs +++ b/vendor/clap/examples/tutorial_builder/02_app_settings.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, AppSettings, ArgAction}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .global_setting(AppSettings::DeriveDisplayOrder) .allow_negative_numbers(true) .arg(arg!(--two ).action(ArgAction::Set)) diff --git a/vendor/clap/examples/tutorial_builder/02_apps.md b/vendor/clap/examples/tutorial_builder/02_apps.md new file mode 100644 index 000000000..8504b5f52 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/02_apps.md @@ -0,0 +1,19 @@ +```console +$ 02_apps --help +MyApp 1.0 +Kevin K. +Does awesome things + +USAGE: + 02_apps[EXE] --two --one + +OPTIONS: + -h, --help Print help information + --one + --two + -V, --version Print version information + +$ 02_apps --version +MyApp 1.0 + +``` diff --git a/vendor/clap/examples/tutorial_builder/02_crate.md b/vendor/clap/examples/tutorial_builder/02_crate.md new file mode 100644 index 000000000..f76e0d608 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/02_crate.md @@ -0,0 +1,18 @@ +```console +$ 02_crate --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_crate[EXE] --two --one + +OPTIONS: + -h, --help Print help information + --one + --two + -V, --version Print version information + +$ 02_crate --version +clap [..] + +``` diff --git a/vendor/clap/examples/tutorial_builder/02_crate.rs b/vendor/clap/examples/tutorial_builder/02_crate.rs index 16b7e7ee0..8a1722fd3 100644 --- a/vendor/clap/examples/tutorial_builder/02_crate.rs +++ b/vendor/clap/examples/tutorial_builder/02_crate.rs @@ -1,8 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command}; fn main() { + // requires `cargo` feature, reading name, version, author, and description from `Cargo.toml` let matches = command!() .arg(arg!(--two )) .arg(arg!(--one )) diff --git a/vendor/clap/examples/tutorial_builder/03_01_flag_bool.md b/vendor/clap/examples/tutorial_builder/03_01_flag_bool.md new file mode 100644 index 000000000..b0ee2a126 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_01_flag_bool.md @@ -0,0 +1,23 @@ +```console +$ 03_01_flag_bool --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_bool[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_bool +verbose: false + +$ 03_01_flag_bool --verbose +verbose: true + +$ 03_01_flag_bool --verbose --verbose +verbose: true + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_01_flag_bool.rs b/vendor/clap/examples/tutorial_builder/03_01_flag_bool.rs index 41ecbb1d7..03f2f1756 100644 --- a/vendor/clap/examples/tutorial_builder/03_01_flag_bool.rs +++ b/vendor/clap/examples/tutorial_builder/03_01_flag_bool.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{command, Arg, ArgAction}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg( Arg::new("verbose") .short('v') @@ -12,10 +10,5 @@ fn main() { ) .get_matches(); - println!( - "verbose: {:?}", - *matches - .get_one::("verbose") - .expect("defaulted by clap") - ); + println!("verbose: {:?}", matches.get_flag("verbose")); } diff --git a/vendor/clap/examples/tutorial_builder/03_01_flag_count.md b/vendor/clap/examples/tutorial_builder/03_01_flag_count.md new file mode 100644 index 000000000..ca4bcd6eb --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_01_flag_count.md @@ -0,0 +1,23 @@ +```console +$ 03_01_flag_count --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_count[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_count +verbose: 0 + +$ 03_01_flag_count --verbose +verbose: 1 + +$ 03_01_flag_count --verbose --verbose +verbose: 2 + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_01_flag_count.rs b/vendor/clap/examples/tutorial_builder/03_01_flag_count.rs index 764affbd8..7f23649d6 100644 --- a/vendor/clap/examples/tutorial_builder/03_01_flag_count.rs +++ b/vendor/clap/examples/tutorial_builder/03_01_flag_count.rs @@ -1,16 +1,9 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, ArgAction}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg(arg!(-v - -verbose).action(ArgAction::Count)) .get_matches(); - println!( - "verbose: {:?}", - matches - .get_one::("verbose") - .expect("Count always defaulted") - ); + println!("verbose: {:?}", matches.get_count("verbose")); } diff --git a/vendor/clap/examples/tutorial_builder/03_02_option.md b/vendor/clap/examples/tutorial_builder/03_02_option.md new file mode 100644 index 000000000..6198bcc73 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_02_option.md @@ -0,0 +1,32 @@ +```console +$ 03_02_option --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_02_option[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -n, --name + -V, --version Print version information + +$ 03_02_option +name: None + +$ 03_02_option --name bob +name: Some("bob") + +$ 03_02_option --name=bob +name: Some("bob") + +$ 03_02_option -n bob +name: Some("bob") + +$ 03_02_option -n=bob +name: Some("bob") + +$ 03_02_option -nbob +name: Some("bob") + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_02_option.rs b/vendor/clap/examples/tutorial_builder/03_02_option.rs index 80e2b9159..188244566 100644 --- a/vendor/clap/examples/tutorial_builder/03_02_option.rs +++ b/vendor/clap/examples/tutorial_builder/03_02_option.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg(arg!(-n --name ).required(false)) .get_matches(); diff --git a/vendor/clap/examples/tutorial_builder/03_03_positional.md b/vendor/clap/examples/tutorial_builder/03_03_positional.md new file mode 100644 index 000000000..a3d7b8cf3 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_03_positional.md @@ -0,0 +1,22 @@ +```console +$ 03_03_positional --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_03_positional[EXE] [NAME] + +ARGS: + + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_03_positional +NAME: None + +$ 03_03_positional bob +NAME: Some("bob") + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_03_positional.rs b/vendor/clap/examples/tutorial_builder/03_03_positional.rs index c6579409a..0c3a5f037 100644 --- a/vendor/clap/examples/tutorial_builder/03_03_positional.rs +++ b/vendor/clap/examples/tutorial_builder/03_03_positional.rs @@ -1,9 +1,9 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command}; fn main() { - let matches = command!().arg(arg!([NAME])).get_matches(); + let matches = command!() // requires `cargo` feature + .arg(arg!([NAME])) + .get_matches(); println!("NAME: {:?}", matches.get_one::("NAME")); } diff --git a/vendor/clap/examples/tutorial_builder/03_04_subcommands.md b/vendor/clap/examples/tutorial_builder/03_04_subcommands.md new file mode 100644 index 000000000..8f9efa911 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_04_subcommands.md @@ -0,0 +1,64 @@ +```console +$ 03_04_subcommands help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +$ 03_04_subcommands help add +03_04_subcommands[EXE]-add [..] +Adds files to myapp + +USAGE: + 03_04_subcommands[EXE] add [NAME] + +ARGS: + + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_04_subcommands add bob +'myapp add' was used, name is: Some("bob") + +``` + +Because we set [`Command::arg_required_else_help`][crate::Command::arg_required_else_help]: +```console +$ 03_04_subcommands +? failed +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +``` + +Because we set [`Command::propagate_version`][crate::Command::propagate_version]: +```console +$ 03_04_subcommands --version +clap [..] + +$ 03_04_subcommands add --version +03_04_subcommands[EXE]-add [..] + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_04_subcommands.rs b/vendor/clap/examples/tutorial_builder/03_04_subcommands.rs index 1dd1cbf09..fbe23809e 100644 --- a/vendor/clap/examples/tutorial_builder/03_04_subcommands.rs +++ b/vendor/clap/examples/tutorial_builder/03_04_subcommands.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, Command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .propagate_version(true) .subcommand_required(true) .arg_required_else_help(true) diff --git a/vendor/clap/examples/tutorial_builder/03_05_default_values.md b/vendor/clap/examples/tutorial_builder/03_05_default_values.md new file mode 100644 index 000000000..7b6c0307d --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/03_05_default_values.md @@ -0,0 +1,22 @@ +```console +$ 03_05_default_values --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_05_default_values[EXE] [NAME] + +ARGS: + [default: alice] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_05_default_values +NAME: "alice" + +$ 03_05_default_values bob +NAME: "bob" + +``` diff --git a/vendor/clap/examples/tutorial_builder/03_05_default_values.rs b/vendor/clap/examples/tutorial_builder/03_05_default_values.rs index c68e87973..cb3e3831f 100644 --- a/vendor/clap/examples/tutorial_builder/03_05_default_values.rs +++ b/vendor/clap/examples/tutorial_builder/03_05_default_values.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg(arg!([NAME]).default_value("alice")) .get_matches(); diff --git a/vendor/clap/examples/tutorial_builder/04_01_enum.md b/vendor/clap/examples/tutorial_builder/04_01_enum.md new file mode 100644 index 000000000..282b1e613 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_01_enum.md @@ -0,0 +1,29 @@ +```console +$ 04_01_enum --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_01_enum[EXE] + +ARGS: + What mode to run the program in [possible values: fast, slow] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_01_enum fast +Hare + +$ 04_01_enum slow +Tortoise + +$ 04_01_enum medium +? failed +error: "medium" isn't a valid value for '' + [possible values: fast, slow] + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_01_enum.rs b/vendor/clap/examples/tutorial_builder/04_01_enum.rs index ad2177c23..e8cf70f5c 100644 --- a/vendor/clap/examples/tutorial_builder/04_01_enum.rs +++ b/vendor/clap/examples/tutorial_builder/04_01_enum.rs @@ -1,15 +1,49 @@ -// Note: this requires the `cargo` feature +use clap::{arg, builder::PossibleValue, command, value_parser, ValueEnum}; -use clap::{arg, command, value_parser, ValueEnum}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] enum Mode { Fast, Slow, } +// Can also be derived] with feature flag `derive` +impl ValueEnum for Mode { + fn value_variants<'a>() -> &'a [Self] { + &[Mode::Fast, Mode::Slow] + } + + fn to_possible_value<'a>(&self) -> Option> { + Some(match self { + Mode::Fast => PossibleValue::new("fast"), + Mode::Slow => PossibleValue::new("slow"), + }) + } +} + +impl std::fmt::Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_possible_value() + .expect("no values are skipped") + .get_name() + .fmt(f) + } +} + +impl std::str::FromStr for Mode { + type Err = String; + + fn from_str(s: &str) -> Result { + for variant in Self::value_variants() { + if variant.to_possible_value().unwrap().matches(s, false) { + return Ok(*variant); + } + } + Err(format!("Invalid variant: {}", s)) + } +} + fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg( arg!() .help("What mode to run the program in") diff --git a/vendor/clap/examples/tutorial_builder/04_01_possible.md b/vendor/clap/examples/tutorial_builder/04_01_possible.md new file mode 100644 index 000000000..2909bfb17 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_01_possible.md @@ -0,0 +1,29 @@ +```console +$ 04_01_possible --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_01_possible[EXE] + +ARGS: + What mode to run the program in [possible values: fast, slow] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_01_possible fast +Hare + +$ 04_01_possible slow +Tortoise + +$ 04_01_possible medium +? failed +error: "medium" isn't a valid value for '' + [possible values: fast, slow] + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_01_possible.rs b/vendor/clap/examples/tutorial_builder/04_01_possible.rs index f7b0cfb34..3da7aca74 100644 --- a/vendor/clap/examples/tutorial_builder/04_01_possible.rs +++ b/vendor/clap/examples/tutorial_builder/04_01_possible.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg( arg!() .help("What mode to run the program in") diff --git a/vendor/clap/examples/tutorial_builder/04_02_parse.md b/vendor/clap/examples/tutorial_builder/04_02_parse.md new file mode 100644 index 000000000..605bf4b59 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_02_parse.md @@ -0,0 +1,31 @@ +```console +$ 04_02_parse --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_parse[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_parse 22 +PORT = 22 + +$ 04_02_parse foobar +? failed +error: Invalid value "foobar" for '': invalid digit found in string + +For more information try --help + +$ 04_02_parse_derive 0 +? failed +error: Invalid value "0" for '': 0 is not in 1..=65535 + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_02_parse.rs b/vendor/clap/examples/tutorial_builder/04_02_parse.rs index c2f3cc533..13f41a18e 100644 --- a/vendor/clap/examples/tutorial_builder/04_02_parse.rs +++ b/vendor/clap/examples/tutorial_builder/04_02_parse.rs @@ -1,9 +1,7 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, value_parser}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg( arg!() .help("Network port to use") diff --git a/vendor/clap/examples/tutorial_builder/04_02_validate.md b/vendor/clap/examples/tutorial_builder/04_02_validate.md new file mode 100644 index 000000000..a317a8eb7 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_02_validate.md @@ -0,0 +1,31 @@ +```console +$ 04_02_validate --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_validate[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_validate 22 +PORT = 22 + +$ 04_02_validate foobar +? failed +error: Invalid value "foobar" for '': `foobar` isn't a port number + +For more information try --help + +$ 04_02_validate 0 +? failed +error: Invalid value "0" for '': Port not in range 1-65535 + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_02_validate.rs b/vendor/clap/examples/tutorial_builder/04_02_validate.rs index e60018a46..ea2f32e67 100644 --- a/vendor/clap/examples/tutorial_builder/04_02_validate.rs +++ b/vendor/clap/examples/tutorial_builder/04_02_validate.rs @@ -1,11 +1,9 @@ -// Note: this requires the `cargo` feature - use std::ops::RangeInclusive; use clap::{arg, command}; fn main() { - let matches = command!() + let matches = command!() // requires `cargo` feature .arg( arg!() .help("Network port to use") diff --git a/vendor/clap/examples/tutorial_builder/04_03_relations.md b/vendor/clap/examples/tutorial_builder/04_03_relations.md new file mode 100644 index 000000000..3ea336363 --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_03_relations.md @@ -0,0 +1,58 @@ +```console +$ 04_03_relations --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_03_relations[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +ARGS: + some regular input + +OPTIONS: + -c + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver set version manually + --spec-in some special input argument + -V, --version Print version information + +$ 04_03_relations +? failed +error: The following required arguments were not provided: + <--set-ver |--major|--minor|--patch> + +USAGE: + 04_03_relations[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +For more information try --help + +$ 04_03_relations --major +Version: 2.2.3 + +$ 04_03_relations --major --minor +? failed +error: The argument '--major' cannot be used with '--minor' + +USAGE: + 04_03_relations[EXE] <--set-ver |--major|--minor|--patch> + +For more information try --help + +$ 04_03_relations --major -c config.toml +? failed +error: The following required arguments were not provided: + > + +USAGE: + 04_03_relations[EXE] -c <--set-ver |--major|--minor|--patch> > + +For more information try --help + +$ 04_03_relations --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_03_relations.rs b/vendor/clap/examples/tutorial_builder/04_03_relations.rs index 605e5b48e..8e26d3ea9 100644 --- a/vendor/clap/examples/tutorial_builder/04_03_relations.rs +++ b/vendor/clap/examples/tutorial_builder/04_03_relations.rs @@ -1,12 +1,10 @@ -// Note: this requires the `cargo` feature - use std::path::PathBuf; use clap::{arg, command, value_parser, ArgAction, ArgGroup}; fn main() { // Create application like normal - let matches = command!() + let matches = command!() // requires `cargo` feature // Add the version arguments .arg(arg!(--"set-ver" "set version manually").required(false)) .arg(arg!(--major "auto inc major").action(ArgAction::SetTrue)) @@ -52,9 +50,9 @@ fn main() { } else { // Increment the one requested (in a real program, we'd reset the lower numbers) let (maj, min, pat) = ( - *matches.get_one::("major").expect("defaulted by clap"), - *matches.get_one::("minor").expect("defaulted by clap"), - *matches.get_one::("patch").expect("defaulted by clap"), + matches.get_flag("major"), + matches.get_flag("minor"), + matches.get_flag("patch"), ); match (maj, min, pat) { (true, _, _) => major += 1, diff --git a/vendor/clap/examples/tutorial_builder/04_04_custom.md b/vendor/clap/examples/tutorial_builder/04_04_custom.md new file mode 100644 index 000000000..26a3df1ab --- /dev/null +++ b/vendor/clap/examples/tutorial_builder/04_04_custom.md @@ -0,0 +1,57 @@ +```console +$ 04_04_custom --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] + +ARGS: + some regular input + +OPTIONS: + -c + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver set version manually + --spec-in some special input argument + -V, --version Print version information + +$ 04_04_custom +? failed +error: Can only modify one version field + +USAGE: + 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom --major +Version: 2.2.3 + +$ 04_04_custom --major --minor +? failed +error: Can only modify one version field + +USAGE: + 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom --major -c config.toml +? failed +Version: 2.2.3 +error: INPUT_FILE or --spec-in is required when using --config + +USAGE: + 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` diff --git a/vendor/clap/examples/tutorial_builder/04_04_custom.rs b/vendor/clap/examples/tutorial_builder/04_04_custom.rs index 3dc080505..fb40b2fc4 100644 --- a/vendor/clap/examples/tutorial_builder/04_04_custom.rs +++ b/vendor/clap/examples/tutorial_builder/04_04_custom.rs @@ -1,12 +1,10 @@ -// Note: this requires the `cargo` feature - use std::path::PathBuf; use clap::{arg, command, value_parser, ArgAction, ErrorKind}; fn main() { // Create application like normal - let mut cmd = command!() + let mut cmd = command!() // requires `cargo` feature // Add the version arguments .arg(arg!(--"set-ver" "set version manually").required(false)) .arg(arg!(--major "auto inc major").action(ArgAction::SetTrue)) @@ -36,10 +34,7 @@ fn main() { // See if --set-ver was used to set the version manually let version = if let Some(ver) = matches.get_one::("set-ver") { - if *matches.get_one::("major").expect("defaulted by clap") - || *matches.get_one::("minor").expect("defaulted by clap") - || *matches.get_one::("patch").expect("defaulted by clap") - { + if matches.get_flag("major") || matches.get_flag("minor") || matches.get_flag("patch") { cmd.error( ErrorKind::ArgumentConflict, "Can't do relative and absolute version change", @@ -50,9 +45,9 @@ fn main() { } else { // Increment the one requested (in a real program, we'd reset the lower numbers) let (maj, min, pat) = ( - *matches.get_one::("major").expect("defaulted by clap"), - *matches.get_one::("minor").expect("defaulted by clap"), - *matches.get_one::("patch").expect("defaulted by clap"), + matches.get_flag("major"), + matches.get_flag("minor"), + matches.get_flag("patch"), ); match (maj, min, pat) { (true, false, false) => major += 1, diff --git a/vendor/clap/examples/tutorial_builder/05_01_assert.rs b/vendor/clap/examples/tutorial_builder/05_01_assert.rs index d6f19ffe5..4b9254230 100644 --- a/vendor/clap/examples/tutorial_builder/05_01_assert.rs +++ b/vendor/clap/examples/tutorial_builder/05_01_assert.rs @@ -1,5 +1,3 @@ -// Note: this requires the `cargo` feature - use clap::{arg, command, value_parser}; fn main() { @@ -13,14 +11,15 @@ fn main() { } fn cmd() -> clap::Command<'static> { - command!().arg( - arg!() - .help("Network port to use") - .value_parser(value_parser!(usize)), - ) + command!() // requires `cargo` feature + .arg( + arg!() + .help("Network port to use") + .value_parser(value_parser!(usize)), + ) } #[test] -fn verify_app() { +fn verify_cmd() { cmd().debug_assert(); } diff --git a/vendor/clap/examples/tutorial_builder/README.md b/vendor/clap/examples/tutorial_builder/README.md deleted file mode 100644 index 945b01e72..000000000 --- a/vendor/clap/examples/tutorial_builder/README.md +++ /dev/null @@ -1,658 +0,0 @@ -# Tutorial - -*Jump to [derive tutorial](../tutorial_derive/README.md)* - -1. [Quick Start](#quick-start) -2. [Configuring the Parser](#configuring-the-parser) -3. [Adding Arguments](#adding-arguments) - 1. [Positionals](#positionals) - 2. [Options](#options) - 3. [Flags](#flags) - 4. [Subcommands](#subcommands) - 5. [Defaults](#defaults) -4. Validation - 1. [Enumerated values](#enumerated-values) - 2. [Validated values](#validated-values) - 3. [Argument Relations](#argument-relations) - 4. [Custom Validation](#custom-validation) -5. [Tips](#tips) -6. [Contributing](#contributing) - -## Quick Start - -You can create an application with several arguments using usage strings. - -[Example:](01_quick.rs) -```console -$ 01_quick --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 01_quick[EXE] [OPTIONS] [name] [SUBCOMMAND] - -ARGS: - Optional name to operate on - -OPTIONS: - -c, --config Sets a custom config file - -d, --debug Turn debugging information on - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - help Print this message or the help of the given subcommand(s) - test does testing things - -``` - -By default, the program does nothing: -```console -$ 01_quick -Debug mode is off - -``` - -But you can mix and match the various features -```console -$ 01_quick -dd test -Debug mode is on -Not printing testing lists... - -``` - -## Configuring the Parser - -You use the `Command` the start building a parser. - -[Example:](02_apps.rs) -```console -$ 02_apps --help -MyApp 1.0 -Kevin K. -Does awesome things - -USAGE: - 02_apps[EXE] --two --one - -OPTIONS: - -h, --help Print help information - --one - --two - -V, --version Print version information - -$ 02_apps --version -MyApp 1.0 - -``` - -You can use `command!()` to fill these fields in from your `Cargo.toml` -file. **This requires the `cargo` feature flag.** - -[Example:](02_crate.rs) -```console -$ 02_crate --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 02_crate[EXE] --two --one - -OPTIONS: - -h, --help Print help information - --one - --two - -V, --version Print version information - -$ 02_crate --version -clap [..] - -``` - -You can use `Command` methods to change the application level behavior of clap. - -[Example:](02_app_settings.rs) -```console -$ 02_app_settings --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 02_app_settings[EXE] --two --one - -OPTIONS: - --two - --one - -h, --help Print help information - -V, --version Print version information - -$ 02_app_settings --one -1 --one -3 --two 10 -two: "10" -one: "-3" - -``` - -## Adding Arguments - -### Positionals - -You can have users specify values by their position on the command-line: - -[Example:](03_03_positional.rs) -```console -$ 03_03_positional --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_03_positional[EXE] [NAME] - -ARGS: - - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_03_positional -NAME: None - -$ 03_03_positional bob -NAME: Some("bob") - -``` - -### Options - -You can name your arguments with a flag: -- Order doesn't matter -- They can be optional -- Intent is clearer - -[Example:](03_02_option.rs) -```console -$ 03_02_option --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_02_option[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -n, --name - -V, --version Print version information - -$ 03_02_option -name: None - -$ 03_02_option --name bob -name: Some("bob") - -$ 03_02_option --name=bob -name: Some("bob") - -$ 03_02_option -n bob -name: Some("bob") - -$ 03_02_option -n=bob -name: Some("bob") - -$ 03_02_option -nbob -name: Some("bob") - -``` - -### Flags - -Flags can also be switches that can be on/off: - -[Example:](03_01_flag_bool.rs) -```console -$ 03_01_flag_bool --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_01_flag_bool[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -v, --verbose - -V, --version Print version information - -$ 03_01_flag_bool -verbose: false - -$ 03_01_flag_bool --verbose -verbose: true - -$ 03_01_flag_bool --verbose --verbose -verbose: true - -``` - -Or counted. - -[Example:](03_01_flag_count.rs) -```console -$ 03_01_flag_count --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_01_flag_count[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -v, --verbose - -V, --version Print version information - -$ 03_01_flag_count -verbose: 0 - -$ 03_01_flag_count --verbose -verbose: 1 - -$ 03_01_flag_count --verbose --verbose -verbose: 2 - -``` - -### Subcommands - -Subcommands are defined as `Command`s that get added via `Command::subcommand`. Each -instance of a Subcommand can have its own version, author(s), Args, and even its own -subcommands. - -[Example:](03_04_subcommands.rs) -```console -$ 03_04_subcommands help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_04_subcommands[EXE] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - add Adds files to myapp - help Print this message or the help of the given subcommand(s) - -$ 03_04_subcommands help add -03_04_subcommands[EXE]-add [..] -Adds files to myapp - -USAGE: - 03_04_subcommands[EXE] add [NAME] - -ARGS: - - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_04_subcommands add bob -'myapp add' was used, name is: Some("bob") - -``` - -Because we set `Command::arg_required_else_help`: -```console -$ 03_04_subcommands -? failed -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_04_subcommands[EXE] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - add Adds files to myapp - help Print this message or the help of the given subcommand(s) - -``` - -Because we set `Command::propagate_version`: -```console -$ 03_04_subcommands --version -clap [..] - -$ 03_04_subcommands add --version -03_04_subcommands[EXE]-add [..] - -``` - -### Defaults - -We've previously showed that arguments can be `required` or optional. When -optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can -set `Arg::default_value`. - -[Example:](03_05_default_values.rs) -```console -$ 03_05_default_values --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_05_default_values[EXE] [NAME] - -ARGS: - [default: alice] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_05_default_values -NAME: "alice" - -$ 03_05_default_values bob -NAME: "bob" - -``` - -## Validation - -### Enumerated values - -If you have arguments of specific values you want to test for, you can use the -`PossibleValuesParser` or `Arg::value_parser(["val1", ...])` for short. - -This allows you specify the valid values for that argument. If the user does not use one of -those specific values, they will receive a graceful exit with error message informing them -of the mistake, and what the possible valid values are - -[Example:](04_01_possible.rs) -```console -$ 04_01_possible --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_01_possible[EXE] - -ARGS: - What mode to run the program in [possible values: fast, slow] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_01_possible fast -Hare - -$ 04_01_possible slow -Tortoise - -$ 04_01_possible medium -? failed -error: "medium" isn't a valid value for '' - [possible values: fast, slow] - -For more information try --help - -``` - -When enabling the `derive` feature, you can use `ValueEnum` to take care of the boiler plate for you, giving the same results. - -[Example:](04_01_enum.rs) -```console -$ 04_01_enum --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_01_enum[EXE] - -ARGS: - What mode to run the program in [possible values: fast, slow] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_01_enum fast -Hare - -$ 04_01_enum slow -Tortoise - -$ 04_01_enum medium -? failed -error: "medium" isn't a valid value for '' - [possible values: fast, slow] - -For more information try --help - -``` - -### Validated values - -More generally, you can validate and parse into any data type. - -[Example:](04_02_parse.rs) -```console -$ 04_02_parse --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_02_parse[EXE] - -ARGS: - Network port to use - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_02_parse 22 -PORT = 22 - -$ 04_02_parse foobar -? failed -error: Invalid value "foobar" for '': invalid digit found in string - -For more information try --help - -$ 04_02_parse_derive 0 -? failed -error: Invalid value "0" for '': 0 is not in 1..=65535 - -For more information try --help - -``` - -A custom parser can be used to improve the error messages or provide additional validation: - -[Example:](04_02_validate.rs) -```console -$ 04_02_validate --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_02_validate[EXE] - -ARGS: - Network port to use - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_02_validate 22 -PORT = 22 - -$ 04_02_validate foobar -? failed -error: Invalid value "foobar" for '': `foobar` isn't a port number - -For more information try --help - -$ 04_02_validate 0 -? failed -error: Invalid value "0" for '': Port not in range 1-65535 - -For more information try --help - -``` - -### Argument Relations - -You can declare dependencies or conflicts between `Arg`s or even `ArgGroup`s. - -`ArgGroup`s make it easier to declare relations instead of having to list each -individually, or when you want a rule to apply "any but not all" arguments. - -Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be -present out of a given set. Imagine that you had multiple arguments, and you want one of them to -be required, but making all of them required isn't feasible because perhaps they conflict with -each other. - -[Example:](04_03_relations.rs) -```console -$ 04_03_relations --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_03_relations[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] - -ARGS: - some regular input - -OPTIONS: - -c - -h, --help Print help information - --major auto inc major - --minor auto inc minor - --patch auto inc patch - --set-ver set version manually - --spec-in some special input argument - -V, --version Print version information - -$ 04_03_relations -? failed -error: The following required arguments were not provided: - <--set-ver |--major|--minor|--patch> - -USAGE: - 04_03_relations[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] - -For more information try --help - -$ 04_03_relations --major -Version: 2.2.3 - -$ 04_03_relations --major --minor -? failed -error: The argument '--major' cannot be used with '--minor' - -USAGE: - 04_03_relations[EXE] <--set-ver |--major|--minor|--patch> - -For more information try --help - -$ 04_03_relations --major -c config.toml -? failed -error: The following required arguments were not provided: - > - -USAGE: - 04_03_relations[EXE] -c <--set-ver |--major|--minor|--patch> > - -For more information try --help - -$ 04_03_relations --major -c config.toml --spec-in input.txt -Version: 2.2.3 -Doing work using input input.txt and config config.toml - -``` - -### Custom Validation - -As a last resort, you can create custom errors with the basics of clap's formatting. - -[Example:](04_04_custom.rs) -```console -$ 04_04_custom --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] - -ARGS: - some regular input - -OPTIONS: - -c - -h, --help Print help information - --major auto inc major - --minor auto inc minor - --patch auto inc patch - --set-ver set version manually - --spec-in some special input argument - -V, --version Print version information - -$ 04_04_custom -? failed -error: Can only modify one version field - -USAGE: - 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom --major -Version: 2.2.3 - -$ 04_04_custom --major --minor -? failed -error: Can only modify one version field - -USAGE: - 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom --major -c config.toml -? failed -Version: 2.2.3 -error: INPUT_FILE or --spec-in is required when using --config - -USAGE: - 04_04_custom[EXE] [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom --major -c config.toml --spec-in input.txt -Version: 2.2.3 -Doing work using input input.txt and config config.toml - -``` - -## Tips - -- For more complex demonstration of features, see our [examples](../README.md). -- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs)) - -## Contributing - -New example code: -- Please update the corresponding section in the [derive tutorial](../tutorial_derive/README.md) -- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`. -- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here). - -See also the general [CONTRIBUTING](../../CONTRIBUTING.md). diff --git a/vendor/clap/examples/tutorial_derive/01_quick.md b/vendor/clap/examples/tutorial_derive/01_quick.md new file mode 100644 index 000000000..6f70d2cce --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/01_quick.md @@ -0,0 +1,37 @@ +```console +$ 01_quick_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 01_quick_derive[EXE] [OPTIONS] [NAME] [SUBCOMMAND] + +ARGS: + Optional name to operate on + +OPTIONS: + -c, --config Sets a custom config file + -d, --debug Turn debugging information on + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + test does testing things + +``` + +By default, the program does nothing: +```console +$ 01_quick_derive +Debug mode is off + +``` + +But you can mix and match the various features +```console +$ 01_quick_derive -dd test +Debug mode is on +Not printing testing lists... + +``` diff --git a/vendor/clap/examples/tutorial_derive/02_app_settings.md b/vendor/clap/examples/tutorial_derive/02_app_settings.md new file mode 100644 index 000000000..ee16c66df --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/02_app_settings.md @@ -0,0 +1,19 @@ +```console +$ 02_app_settings_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_app_settings_derive[EXE] --two --one + +OPTIONS: + --two + --one + -h, --help Print help information + -V, --version Print version information + +$ 02_app_settings_derive --one -1 --one -3 --two 10 +two: "10" +one: "-3" + +``` diff --git a/vendor/clap/examples/tutorial_derive/02_apps.md b/vendor/clap/examples/tutorial_derive/02_apps.md new file mode 100644 index 000000000..0141581c4 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/02_apps.md @@ -0,0 +1,19 @@ +```console +$ 02_apps_derive --help +MyApp 1.0 +Kevin K. +Does awesome things + +USAGE: + 02_apps_derive[EXE] --two --one + +OPTIONS: + -h, --help Print help information + --one + --two + -V, --version Print version information + +$ 02_apps_derive --version +MyApp 1.0 + +``` diff --git a/vendor/clap/examples/tutorial_derive/02_crate.md b/vendor/clap/examples/tutorial_derive/02_crate.md new file mode 100644 index 000000000..92c820758 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/02_crate.md @@ -0,0 +1,18 @@ +```console +$ 02_crate_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_crate_derive[EXE] --two --one + +OPTIONS: + -h, --help Print help information + --one + --two + -V, --version Print version information + +$ 02_crate_derive --version +clap [..] + +``` diff --git a/vendor/clap/examples/tutorial_derive/02_crate.rs b/vendor/clap/examples/tutorial_derive/02_crate.rs index df16468d0..5576f998c 100644 --- a/vendor/clap/examples/tutorial_derive/02_crate.rs +++ b/vendor/clap/examples/tutorial_derive/02_crate.rs @@ -1,7 +1,7 @@ use clap::Parser; #[derive(Parser)] -#[clap(author, version, about, long_about = None)] +#[clap(author, version, about, long_about = None)] // Read from `Cargo.toml` struct Cli { #[clap(long, value_parser)] two: String, diff --git a/vendor/clap/examples/tutorial_derive/03_01_flag_bool.md b/vendor/clap/examples/tutorial_derive/03_01_flag_bool.md new file mode 100644 index 000000000..0baaa10ca --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_01_flag_bool.md @@ -0,0 +1,23 @@ +```console +$ 03_01_flag_bool_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_bool_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_bool_derive +verbose: false + +$ 03_01_flag_bool_derive --verbose +verbose: true + +$ 03_01_flag_bool_derive --verbose --verbose +verbose: true + +``` diff --git a/vendor/clap/examples/tutorial_derive/03_01_flag_count.md b/vendor/clap/examples/tutorial_derive/03_01_flag_count.md new file mode 100644 index 000000000..3d5a53084 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_01_flag_count.md @@ -0,0 +1,23 @@ +```console +$ 03_01_flag_count_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_count_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_count_derive +verbose: 0 + +$ 03_01_flag_count_derive --verbose +verbose: 1 + +$ 03_01_flag_count_derive --verbose --verbose +verbose: 2 + +``` diff --git a/vendor/clap/examples/tutorial_derive/03_02_option.md b/vendor/clap/examples/tutorial_derive/03_02_option.md new file mode 100644 index 000000000..84ff7fa74 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_02_option.md @@ -0,0 +1,32 @@ +```console +$ 03_02_option_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_02_option_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -n, --name + -V, --version Print version information + +$ 03_02_option_derive +name: None + +$ 03_02_option_derive --name bob +name: Some("bob") + +$ 03_02_option_derive --name=bob +name: Some("bob") + +$ 03_02_option_derive -n bob +name: Some("bob") + +$ 03_02_option_derive -n=bob +name: Some("bob") + +$ 03_02_option_derive -nbob +name: Some("bob") + +``` diff --git a/vendor/clap/examples/tutorial_derive/03_03_positional.md b/vendor/clap/examples/tutorial_derive/03_03_positional.md new file mode 100644 index 000000000..7281fe3ff --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_03_positional.md @@ -0,0 +1,22 @@ +```console +$ 03_03_positional_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_03_positional_derive[EXE] [NAME] + +ARGS: + + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_03_positional_derive +name: None + +$ 03_03_positional_derive bob +name: Some("bob") + +``` diff --git a/vendor/clap/examples/tutorial_derive/03_04_subcommands.md b/vendor/clap/examples/tutorial_derive/03_04_subcommands.md new file mode 100644 index 000000000..02f96e3d3 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_04_subcommands.md @@ -0,0 +1,64 @@ +```console +$ 03_04_subcommands_derive help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands_derive[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +$ 03_04_subcommands_derive help add +03_04_subcommands_derive[EXE]-add [..] +Adds files to myapp + +USAGE: + 03_04_subcommands_derive[EXE] add [NAME] + +ARGS: + + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_04_subcommands_derive add bob +'myapp add' was used, name is: Some("bob") + +``` + +Because we used `command: Commands` instead of `command: Option`: +```console +$ 03_04_subcommands_derive +? failed +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands_derive[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +``` + +Because we added `#[clap(propagate_version = true)]`: +```console +$ 03_04_subcommands_derive --version +clap [..] + +$ 03_04_subcommands_derive add --version +03_04_subcommands_derive[EXE]-add [..] + +``` diff --git a/vendor/clap/examples/tutorial_derive/03_05_default_values.md b/vendor/clap/examples/tutorial_derive/03_05_default_values.md new file mode 100644 index 000000000..f7315e736 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/03_05_default_values.md @@ -0,0 +1,22 @@ +```console +$ 03_05_default_values_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_05_default_values_derive[EXE] [NAME] + +ARGS: + [default: alice] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_05_default_values_derive +name: "alice" + +$ 03_05_default_values_derive bob +name: "bob" + +``` diff --git a/vendor/clap/examples/tutorial_derive/04_01_enum.md b/vendor/clap/examples/tutorial_derive/04_01_enum.md new file mode 100644 index 000000000..2523af924 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/04_01_enum.md @@ -0,0 +1,29 @@ +```console +$ 04_01_enum_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_01_enum_derive[EXE] + +ARGS: + What mode to run the program in [possible values: fast, slow] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_01_enum_derive fast +Hare + +$ 04_01_enum_derive slow +Tortoise + +$ 04_01_enum_derive medium +? failed +error: "medium" isn't a valid value for '' + [possible values: fast, slow] + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_derive/04_01_enum.rs b/vendor/clap/examples/tutorial_derive/04_01_enum.rs index 84b4cace4..1ac984288 100644 --- a/vendor/clap/examples/tutorial_derive/04_01_enum.rs +++ b/vendor/clap/examples/tutorial_derive/04_01_enum.rs @@ -1,4 +1,4 @@ -use clap::{ArgEnum, Parser}; +use clap::{Parser, ValueEnum}; #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -8,7 +8,7 @@ struct Cli { mode: Mode, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] enum Mode { Fast, Slow, diff --git a/vendor/clap/examples/tutorial_derive/04_02_parse.md b/vendor/clap/examples/tutorial_derive/04_02_parse.md new file mode 100644 index 000000000..6079ef193 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/04_02_parse.md @@ -0,0 +1,31 @@ +```console +$ 04_02_parse_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_parse_derive[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_parse_derive 22 +PORT = 22 + +$ 04_02_parse_derive foobar +? failed +error: Invalid value "foobar" for '': invalid digit found in string + +For more information try --help + +$ 04_02_parse_derive 0 +? failed +error: Invalid value "0" for '': 0 is not in 1..=65535 + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_derive/04_02_validate.md b/vendor/clap/examples/tutorial_derive/04_02_validate.md new file mode 100644 index 000000000..cc43440ef --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/04_02_validate.md @@ -0,0 +1,31 @@ +```console +$ 04_02_validate_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_validate_derive[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_validate_derive 22 +PORT = 22 + +$ 04_02_validate_derive foobar +? failed +error: Invalid value "foobar" for '': `foobar` isn't a port number + +For more information try --help + +$ 04_02_validate_derive 0 +? failed +error: Invalid value "0" for '': Port not in range 1-65535 + +For more information try --help + +``` diff --git a/vendor/clap/examples/tutorial_derive/04_03_relations.md b/vendor/clap/examples/tutorial_derive/04_03_relations.md new file mode 100644 index 000000000..4f5703d82 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/04_03_relations.md @@ -0,0 +1,58 @@ +```console +$ 04_03_relations_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_03_relations_derive[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +ARGS: + some regular input + +OPTIONS: + -c + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver set version manually + --spec-in some special input argument + -V, --version Print version information + +$ 04_03_relations_derive +? failed +error: The following required arguments were not provided: + <--set-ver |--major|--minor|--patch> + +USAGE: + 04_03_relations_derive[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +For more information try --help + +$ 04_03_relations_derive --major +Version: 2.2.3 + +$ 04_03_relations_derive --major --minor +? failed +error: The argument '--major' cannot be used with '--minor' + +USAGE: + 04_03_relations_derive[EXE] <--set-ver |--major|--minor|--patch> + +For more information try --help + +$ 04_03_relations_derive --major -c config.toml +? failed +error: The following required arguments were not provided: + > + +USAGE: + 04_03_relations_derive[EXE] -c <--set-ver |--major|--minor|--patch> > + +For more information try --help + +$ 04_03_relations_derive --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` diff --git a/vendor/clap/examples/tutorial_derive/04_03_relations.rs b/vendor/clap/examples/tutorial_derive/04_03_relations.rs index f8523902d..37efe95e3 100644 --- a/vendor/clap/examples/tutorial_derive/04_03_relations.rs +++ b/vendor/clap/examples/tutorial_derive/04_03_relations.rs @@ -44,7 +44,7 @@ fn main() { let mut minor = 2; let mut patch = 3; - // See if --set-ver was used to set the version manually + // See if --set_ver was used to set the version manually let version = if let Some(ver) = cli.set_ver.as_deref() { ver.to_string() } else { diff --git a/vendor/clap/examples/tutorial_derive/04_04_custom.md b/vendor/clap/examples/tutorial_derive/04_04_custom.md new file mode 100644 index 000000000..0f19bfe31 --- /dev/null +++ b/vendor/clap/examples/tutorial_derive/04_04_custom.md @@ -0,0 +1,57 @@ +```console +$ 04_04_custom_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_04_custom_derive[EXE] [OPTIONS] [INPUT_FILE] + +ARGS: + some regular input + +OPTIONS: + -c + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver set version manually + --spec-in some special input argument + -V, --version Print version information + +$ 04_04_custom_derive +? failed +error: Can only modify one version field + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major +Version: 2.2.3 + +$ 04_04_custom_derive --major --minor +? failed +error: Can only modify one version field + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major -c config.toml +? failed +Version: 2.2.3 +error: INPUT_FILE or --spec-in is required when using --config + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` diff --git a/vendor/clap/examples/tutorial_derive/05_01_assert.rs b/vendor/clap/examples/tutorial_derive/05_01_assert.rs index f5fa3f6c5..66dca727f 100644 --- a/vendor/clap/examples/tutorial_derive/05_01_assert.rs +++ b/vendor/clap/examples/tutorial_derive/05_01_assert.rs @@ -15,7 +15,7 @@ fn main() { } #[test] -fn verify_app() { +fn verify_cli() { use clap::CommandFactory; Cli::command().debug_assert() } diff --git a/vendor/clap/examples/tutorial_derive/README.md b/vendor/clap/examples/tutorial_derive/README.md deleted file mode 100644 index 6127b6cd3..000000000 --- a/vendor/clap/examples/tutorial_derive/README.md +++ /dev/null @@ -1,639 +0,0 @@ -# Tutorial - -*Jump to [builder tutorial](../tutorial_builder/README.md)* - -1. [Quick Start](#quick-start) -2. [Configuring the Parser](#configuring-the-parser) -3. [Adding Arguments](#adding-arguments) - 1. [Positionals](#positionals) - 2. [Options](#options) - 3. [Flags](#flags) - 4. [Subcommands](#subcommands) - 5. [Defaults](#defaults) -4. Validation - 1. [Enumerated values](#enumerated-values) - 2. [Validated values](#validated-values) - 3. [Argument Relations](#argument-relations) - 4. [Custom Validation](#custom-validation) -5. [Tips](#tips) -6. [Contributing](#contributing) - -## Quick Start - -You can create an application declaratively with a `struct` and some -attributes. **This requires enabling the `derive` feature flag.** - -[Example:](01_quick.rs) -```console -$ 01_quick_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 01_quick_derive[EXE] [OPTIONS] [NAME] [SUBCOMMAND] - -ARGS: - Optional name to operate on - -OPTIONS: - -c, --config Sets a custom config file - -d, --debug Turn debugging information on - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - help Print this message or the help of the given subcommand(s) - test does testing things - -``` - -By default, the program does nothing: -```console -$ 01_quick_derive -Debug mode is off - -``` - -But you can mix and match the various features -```console -$ 01_quick_derive -dd test -Debug mode is on -Not printing testing lists... - -``` - -In addition to this tutorial, see the [derive reference](../derive_ref/README.md). - -## Configuring the Parser - -You use derive `Parser` the start building a parser. - -[Example:](02_apps.rs) -```console -$ 02_apps_derive --help -MyApp 1.0 -Kevin K. -Does awesome things - -USAGE: - 02_apps_derive[EXE] --two --one - -OPTIONS: - -h, --help Print help information - --one - --two - -V, --version Print version information - -$ 02_apps_derive --version -MyApp 1.0 - -``` - -You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file. - -[Example:](02_crate.rs) -```console -$ 02_crate_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 02_crate_derive[EXE] --two --one - -OPTIONS: - -h, --help Print help information - --one - --two - -V, --version Print version information - -$ 02_crate_derive --version -clap [..] - -``` - -You can use attributes to change the application level behavior of clap. Any `Command` builder function can be used as an attribute. - -[Example:](02_app_settings.rs) -```console -$ 02_app_settings_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 02_app_settings_derive[EXE] --two --one - -OPTIONS: - --two - --one - -h, --help Print help information - -V, --version Print version information - -$ 02_app_settings_derive --one -1 --one -3 --two 10 -two: "10" -one: "-3" - -``` - -## Adding Arguments - -### Positionals - -You can have users specify values by their position on the command-line: - -[Example:](03_03_positional.rs) -```console -$ 03_03_positional_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_03_positional_derive[EXE] [NAME] - -ARGS: - - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_03_positional_derive -name: None - -$ 03_03_positional_derive bob -name: Some("bob") - -``` - -### Options - -You can name your arguments with a flag: -- Order doesn't matter -- They can be optional -- Intent is clearer - -The `#[clap(short = 'c')]` and `#[clap(long = "name")]` attributes that define -the flags are `Arg` methods that are derived from the field name when no value -is specified (`#[clap(short)]` and `#[clap(long)]`). - -[Example:](03_02_option.rs) -```console -$ 03_02_option_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_02_option_derive[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -n, --name - -V, --version Print version information - -$ 03_02_option_derive -name: None - -$ 03_02_option_derive --name bob -name: Some("bob") - -$ 03_02_option_derive --name=bob -name: Some("bob") - -$ 03_02_option_derive -n bob -name: Some("bob") - -$ 03_02_option_derive -n=bob -name: Some("bob") - -$ 03_02_option_derive -nbob -name: Some("bob") - -``` - -### Flags - -Flags can also be switches that can be on/off. This is enabled via the -`#[clap(parse(from_flag)]` attribute though this is implied when the field is a -`bool`. - -[Example:](03_01_flag_bool.rs) -```console -$ 03_01_flag_bool_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_01_flag_bool_derive[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -v, --verbose - -V, --version Print version information - -$ 03_01_flag_bool_derive -verbose: false - -$ 03_01_flag_bool_derive --verbose -verbose: true - -$ 03_01_flag_bool_derive --verbose --verbose -verbose: true - -``` - -Or counted with `#[clap(action = clap::ArgAction::Count)]`: - -[Example:](03_01_flag_count.rs) -```console -$ 03_01_flag_count_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_01_flag_count_derive[EXE] [OPTIONS] - -OPTIONS: - -h, --help Print help information - -v, --verbose - -V, --version Print version information - -$ 03_01_flag_count_derive -verbose: 0 - -$ 03_01_flag_count_derive --verbose -verbose: 1 - -$ 03_01_flag_count_derive --verbose --verbose -verbose: 2 - -``` - -### Subcommands - -Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each -instance of a Subcommand can have its own version, author(s), Args, and even its own -subcommands. - -[Example:](03_04_subcommands.rs) -```console -$ 03_04_subcommands_derive help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_04_subcommands_derive[EXE] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - add Adds files to myapp - help Print this message or the help of the given subcommand(s) - -$ 03_04_subcommands_derive help add -03_04_subcommands_derive[EXE]-add [..] -Adds files to myapp - -USAGE: - 03_04_subcommands_derive[EXE] add [NAME] - -ARGS: - - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_04_subcommands_derive add bob -'myapp add' was used, name is: Some("bob") - -``` - -Above, we used a struct-variant to define the `add` subcommand. Alternatively, -you can -[use a struct for your subcommand's arguments](03_04_subcommands_alt.rs). - -Because we used `command: Commands` instead of `command: Option`: -```console -$ 03_04_subcommands_derive -? failed -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_04_subcommands_derive[EXE] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -SUBCOMMANDS: - add Adds files to myapp - help Print this message or the help of the given subcommand(s) - -``` - -Because we added `#[clap(propagate_version = true)]`: -```console -$ 03_04_subcommands_derive --version -clap [..] - -$ 03_04_subcommands_derive add --version -03_04_subcommands_derive[EXE]-add [..] - -``` - -### Defaults - -We've previously showed that arguments can be `required` or optional. When -optional, you work with an `Option` and can `unwrap_or`. Alternatively, you can -set `#[clap(default_value_t)]`. - -[Example:](03_05_default_values.rs) -```console -$ 03_05_default_values_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 03_05_default_values_derive[EXE] [NAME] - -ARGS: - [default: alice] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 03_05_default_values_derive -name: "alice" - -$ 03_05_default_values_derive bob -name: "bob" - -``` - -## Validation - -### Enumerated values - -If you have arguments of specific values you want to test for, you can derive -`ValueEnum`. - -This allows you specify the valid values for that argument. If the user does not use one of -those specific values, they will receive a graceful exit with error message informing them -of the mistake, and what the possible valid values are - -[Example:](04_01_enum.rs) -```console -$ 04_01_enum_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_01_enum_derive[EXE] - -ARGS: - What mode to run the program in [possible values: fast, slow] - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_01_enum_derive fast -Hare - -$ 04_01_enum_derive slow -Tortoise - -$ 04_01_enum_derive medium -? failed -error: "medium" isn't a valid value for '' - [possible values: fast, slow] - -For more information try --help - -``` - -### Validated values - -More generally, you can validate and parse into any data type. - -[Example:](04_02_parse.rs) -```console -$ 04_02_parse_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_02_parse_derive[EXE] - -ARGS: - Network port to use - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_02_parse_derive 22 -PORT = 22 - -$ 04_02_parse_derive foobar -? failed -error: Invalid value "foobar" for '': invalid digit found in string - -For more information try --help - -$ 04_02_parse_derive 0 -? failed -error: Invalid value "0" for '': 0 is not in 1..=65535 - -For more information try --help - -``` - -A custom parser can be used to improve the error messages or provide additional validation: - -[Example:](04_02_validate.rs) -```console -$ 04_02_validate_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_02_validate_derive[EXE] - -ARGS: - Network port to use - -OPTIONS: - -h, --help Print help information - -V, --version Print version information - -$ 04_02_validate_derive 22 -PORT = 22 - -$ 04_02_validate_derive foobar -? failed -error: Invalid value "foobar" for '': `foobar` isn't a port number - -For more information try --help - -$ 04_02_validate_derive 0 -? failed -error: Invalid value "0" for '': Port not in range 1-65535 - -For more information try --help - -``` - -### Argument Relations - -You can declare dependencies or conflicts between `Arg`s or even `ArgGroup`s. - -`ArgGroup`s make it easier to declare relations instead of having to list each -individually, or when you want a rule to apply "any but not all" arguments. - -Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be -present out of a given set. Imagine that you had multiple arguments, and you want one of them to -be required, but making all of them required isn't feasible because perhaps they conflict with -each other. - -[Example:](04_03_relations.rs) -```console -$ 04_03_relations_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_03_relations_derive[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] - -ARGS: - some regular input - -OPTIONS: - -c - -h, --help Print help information - --major auto inc major - --minor auto inc minor - --patch auto inc patch - --set-ver set version manually - --spec-in some special input argument - -V, --version Print version information - -$ 04_03_relations_derive -? failed -error: The following required arguments were not provided: - <--set-ver |--major|--minor|--patch> - -USAGE: - 04_03_relations_derive[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] - -For more information try --help - -$ 04_03_relations_derive --major -Version: 2.2.3 - -$ 04_03_relations_derive --major --minor -? failed -error: The argument '--major' cannot be used with '--minor' - -USAGE: - 04_03_relations_derive[EXE] <--set-ver |--major|--minor|--patch> - -For more information try --help - -$ 04_03_relations_derive --major -c config.toml -? failed -error: The following required arguments were not provided: - > - -USAGE: - 04_03_relations_derive[EXE] -c <--set-ver |--major|--minor|--patch> > - -For more information try --help - -$ 04_03_relations_derive --major -c config.toml --spec-in input.txt -Version: 2.2.3 -Doing work using input input.txt and config config.toml - -``` - -### Custom Validation - -As a last resort, you can create custom errors with the basics of clap's formatting. - -[Example:](04_04_custom.rs) -```console -$ 04_04_custom_derive --help -clap [..] -A simple to use, efficient, and full-featured Command Line Argument Parser - -USAGE: - 04_04_custom_derive[EXE] [OPTIONS] [INPUT_FILE] - -ARGS: - some regular input - -OPTIONS: - -c - -h, --help Print help information - --major auto inc major - --minor auto inc minor - --patch auto inc patch - --set-ver set version manually - --spec-in some special input argument - -V, --version Print version information - -$ 04_04_custom_derive -? failed -error: Can only modify one version field - -USAGE: - clap [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom_derive --major -Version: 2.2.3 - -$ 04_04_custom_derive --major --minor -? failed -error: Can only modify one version field - -USAGE: - clap [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom_derive --major -c config.toml -? failed -Version: 2.2.3 -error: INPUT_FILE or --spec-in is required when using --config - -USAGE: - clap [OPTIONS] [INPUT_FILE] - -For more information try --help - -$ 04_04_custom_derive --major -c config.toml --spec-in input.txt -Version: 2.2.3 -Doing work using input input.txt and config config.toml - -``` - -## Tips - -- For more complex demonstration of features, see our [examples](../README.md). -- See the [derive reference](../derive_ref/README.md) to understand how to use - anything in the [builder API](https://docs.rs/clap/) in the derive API. -- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs)) - -## Contributing - -New example code: -- Please update the corresponding section in the [builder tutorial](../tutorial_builder/README.md) -- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`. -- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here). - -See also the general [CONTRIBUTING](../../CONTRIBUTING.md). diff --git a/vendor/clap/examples/typed-derive.md b/vendor/clap/examples/typed-derive.md index 7c61f70d9..9c7615c63 100644 --- a/vendor/clap/examples/typed-derive.md +++ b/vendor/clap/examples/typed-derive.md @@ -1,6 +1,4 @@ -*Jump to [source](typed-derive.rs)* - -**This requires enabling the `derive` feature flag.** +**This requires enabling the [`derive` feature flag][crate::_features].** Help: ```console diff --git a/vendor/clap/examples/typed-derive.rs b/vendor/clap/examples/typed-derive.rs index 85c750f9c..31084029d 100644 --- a/vendor/clap/examples/typed-derive.rs +++ b/vendor/clap/examples/typed-derive.rs @@ -1,9 +1,7 @@ -// Note: this requires the `derive` feature - use clap::Parser; use std::error::Error; -#[derive(Parser, Debug)] +#[derive(Parser, Debug)] // requires `derive` feature struct Args { /// Implicitly using `std::str::FromStr` #[clap(short = 'O', value_parser)] diff --git a/vendor/clap/src/_cookbook/cargo_example.rs b/vendor/clap/src/_cookbook/cargo_example.rs new file mode 100644 index 000000000..ec5d582db --- /dev/null +++ b/vendor/clap/src/_cookbook/cargo_example.rs @@ -0,0 +1,7 @@ +//! # Example: cargo subcommand (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/cargo-example.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/cargo-example.md")] diff --git a/vendor/clap/src/_cookbook/cargo_example_derive b/vendor/clap/src/_cookbook/cargo_example_derive new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/clap/src/_cookbook/cargo_example_derive.rs b/vendor/clap/src/_cookbook/cargo_example_derive.rs new file mode 100644 index 000000000..d49f956f9 --- /dev/null +++ b/vendor/clap/src/_cookbook/cargo_example_derive.rs @@ -0,0 +1,7 @@ +//! # Example: cargo subcommand (Derive API) +//! +//! ```rust +#![doc = include_str!("../../examples/cargo-example-derive.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/cargo-example-derive.md")] diff --git a/vendor/clap/src/_cookbook/escaped_positional.rs b/vendor/clap/src/_cookbook/escaped_positional.rs new file mode 100644 index 000000000..99a3f83f3 --- /dev/null +++ b/vendor/clap/src/_cookbook/escaped_positional.rs @@ -0,0 +1,7 @@ +//! # Example (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/escaped-positional.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/escaped-positional.md")] diff --git a/vendor/clap/src/_cookbook/escaped_positional_derive.rs b/vendor/clap/src/_cookbook/escaped_positional_derive.rs new file mode 100644 index 000000000..e6f99ad17 --- /dev/null +++ b/vendor/clap/src/_cookbook/escaped_positional_derive.rs @@ -0,0 +1,7 @@ +//! # Example (Derive API) +//! +//! ```rust +#![doc = include_str!("../../examples/escaped-positional-derive.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/escaped-positional-derive.md")] diff --git a/vendor/clap/src/_cookbook/git.rs b/vendor/clap/src/_cookbook/git.rs new file mode 100644 index 000000000..03a926ca8 --- /dev/null +++ b/vendor/clap/src/_cookbook/git.rs @@ -0,0 +1,7 @@ +//! # Example: git-like CLI (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/git.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/git.md")] diff --git a/vendor/clap/src/_cookbook/git_derive.rs b/vendor/clap/src/_cookbook/git_derive.rs new file mode 100644 index 000000000..d3119736d --- /dev/null +++ b/vendor/clap/src/_cookbook/git_derive.rs @@ -0,0 +1,7 @@ +//! # Example: git-like CLI (Derive API) +//! +//! ```rust +#![doc = include_str!("../../examples/git-derive.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/git-derive.md")] diff --git a/vendor/clap/src/_cookbook/mod.rs b/vendor/clap/src/_cookbook/mod.rs new file mode 100644 index 000000000..1a78ed11b --- /dev/null +++ b/vendor/clap/src/_cookbook/mod.rs @@ -0,0 +1,55 @@ +// Contributing +// +// New examples: +// - Building: They must be added to `Cargo.toml` with the appropriate `required-features`. +// - Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax +// - Link the `.md` file from here + +//! # Documentation: Cookbook +//! +//! Typed arguments: [derive][typed_derive] +//! - Topics: +//! - Custom `parse()` +//! +//! Custom cargo command: [builder][cargo_example], [derive][cargo_example_derive] +//! - Topics: +//! - Subcommands +//! - Cargo plugins +//! +//! git-like interface: [builder][git], [derive][git_derive] +//! - Topics: +//! - Subcommands +//! - External subcommands +//! - Optional subcommands +//! - Default subcommands +//! +//! pacman-like interface: [builder][pacman] +//! - Topics: +//! - Flag subcommands +//! - Conflicting arguments +//! +//! Escaped positionals with `--`: [builder][escaped_positional], [derive][escaped_positional_derive] +//! +//! Multi-call +//! - busybox: [builder][multicall_busybox] +//! - Topics: +//! - Subcommands +//! - hostname: [builder][multicall_hostname] +//! - Topics: +//! - Subcommands +//! +//! repl: [builder][repl] +//! - Topics: +//! - Read-Eval-Print Loops / Custom command lines + +pub mod cargo_example; +pub mod cargo_example_derive; +pub mod escaped_positional; +pub mod escaped_positional_derive; +pub mod git; +pub mod git_derive; +pub mod multicall_busybox; +pub mod multicall_hostname; +pub mod pacman; +pub mod repl; +pub mod typed_derive; diff --git a/vendor/clap/src/_cookbook/multicall_busybox.rs b/vendor/clap/src/_cookbook/multicall_busybox.rs new file mode 100644 index 000000000..e3384d682 --- /dev/null +++ b/vendor/clap/src/_cookbook/multicall_busybox.rs @@ -0,0 +1,7 @@ +//! # Example: busybox-like CLI (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/multicall-busybox.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/multicall-busybox.md")] diff --git a/vendor/clap/src/_cookbook/multicall_hostname.rs b/vendor/clap/src/_cookbook/multicall_hostname.rs new file mode 100644 index 000000000..9777654dc --- /dev/null +++ b/vendor/clap/src/_cookbook/multicall_hostname.rs @@ -0,0 +1,7 @@ +//! # Example: hostname-like CLI (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/multicall-hostname.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/multicall-hostname.md")] diff --git a/vendor/clap/src/_cookbook/pacman.rs b/vendor/clap/src/_cookbook/pacman.rs new file mode 100644 index 000000000..880c58158 --- /dev/null +++ b/vendor/clap/src/_cookbook/pacman.rs @@ -0,0 +1,7 @@ +//! # Example: pacman-like CLI (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/pacman.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/pacman.md")] diff --git a/vendor/clap/src/_cookbook/repl.rs b/vendor/clap/src/_cookbook/repl.rs new file mode 100644 index 000000000..549ec8259 --- /dev/null +++ b/vendor/clap/src/_cookbook/repl.rs @@ -0,0 +1,5 @@ +//! # Example: Command REPL (Builder API) +//! +//! ```rust +#![doc = include_str!("../../examples/repl.rs")] +//! ``` diff --git a/vendor/clap/src/_cookbook/typed_derive.rs b/vendor/clap/src/_cookbook/typed_derive.rs new file mode 100644 index 000000000..a5fd15ff8 --- /dev/null +++ b/vendor/clap/src/_cookbook/typed_derive.rs @@ -0,0 +1,7 @@ +//! # Example: Custom Types (Derive API) +//! +//! ```rust +#![doc = include_str!("../../examples/typed-derive.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/typed-derive.md")] diff --git a/vendor/clap/src/_derive/_tutorial.rs b/vendor/clap/src/_derive/_tutorial.rs new file mode 100644 index 000000000..abd57cef8 --- /dev/null +++ b/vendor/clap/src/_derive/_tutorial.rs @@ -0,0 +1,205 @@ +// Contributing +// +// New example code: +// - Please update the corresponding section in the derive tutorial +// - Building: They must be added to `Cargo.toml` with the appropriate `required-features`. +// - Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax +// +// See also the general CONTRIBUTING + +//! # Documentation: Derive Tutorial +//! +//! 1. [Quick Start](#quick-start) +//! 2. [Configuring the Parser](#configuring-the-parser) +//! 3. [Adding Arguments](#adding-arguments) +//! 1. [Positionals](#positionals) +//! 2. [Options](#options) +//! 3. [Flags](#flags) +//! 4. [Subcommands](#subcommands) +//! 5. [Defaults](#defaults) +//! 4. Validation +//! 1. [Enumerated values](#enumerated-values) +//! 2. [Validated values](#validated-values) +//! 3. [Argument Relations](#argument-relations) +//! 4. [Custom Validation](#custom-validation) +//! 5. [Testing](#testing) +//! +//! See also +//! - [FAQ: When should I use the builder vs derive APIs?][crate::_faq#when-should-i-use-the-builder-vs-derive-apis] +//! - The [cookbook][crate::_cookbook] for more application-focused examples +//! +//! ## Quick Start +//! +//! You can create an application declaratively with a `struct` and some +//! attributes. **This requires enabling the [`derive` feature flag][crate::_features].** +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/01_quick.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/tutorial_derive/01_quick.md")] +//! +//! ## Configuring the Parser +//! +//! You use derive [`Parser`][crate::Parser] to start building a parser. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/02_apps.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/tutorial_derive/02_apps.md")] +//! +//! You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/02_crate.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/02_crate.md")] +//! +//! You can use attributes to change the application level behavior of clap. Any [`Command`][crate::Command]] builder function can be used as an attribute. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.md")] +//! +//! ## Adding Arguments +//! +//! ### Positionals +//! +//! You can have users specify values by their position on the command-line: +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.md")] +//! +//! ### Options +//! +//! You can name your arguments with a flag: +//! - Order doesn't matter +//! - They can be optional +//! - Intent is clearer +//! +//! The `#[clap(short = 'n')]` and `#[clap(long = "name")]` attributes that define +//! the flags are [`Arg`][crate::Args] methods that are derived from the field name when no value +//! is specified (`#[clap(short)]` and `#[clap(long)]`). +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_02_option.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/03_02_option.md")] +//! +//! ### Flags +//! +//! Flags can also be switches that can be on/off. This is enabled via the +//! `#[clap(action = ArgAction::SetTrue)]` attribute though this is implied when the field is a +//! `bool`. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.md")] +//! +//! Or counted with `#[clap(action = clap::ArgAction::Count)]`: +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.md")] +//! +//! ### Subcommands +//! +//! Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each +//! instance of a [Subcommand][crate::Subcommand] can have its own version, author(s), Args, and even its own +//! subcommands. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.rs")] +//! ``` +//! We used a struct-variant to define the `add` subcommand. +//! Alternatively, you can use a struct for your subcommand's arguments: +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands_alt.rs")] +//! ``` +//! +#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.md")] +//! +//! ### Defaults +//! +//! We've previously showed that arguments can be [`required`][crate::Arg::required] or optional. +//! When optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can +//! set `#[clap(default_value_t)]`. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.md")] +//! +//! ## Validation +//! +//! ### Enumerated values +//! +//! If you have arguments of specific values you want to test for, you can derive +//! [`ValueEnum`][crate::ValueEnum]. +//! +//! This allows you specify the valid values for that argument. If the user does not use one of +//! those specific values, they will receive a graceful exit with error message informing them +//! of the mistake, and what the possible valid values are +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.md")] +//! +//! ### Validated values +//! +//! More generally, you can validate and parse into any data type. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.md")] +//! +//! A custom parser can be used to improve the error messages or provide additional validation: +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.md")] +//! +//! ### Argument Relations +//! +//! You can declare dependencies or conflicts between [`Arg`][crate::Arg]s or even +//! [`ArgGroup`][crate::ArgGroup]s. +//! +//! [`ArgGroup`][crate::ArgGroup]s make it easier to declare relations instead of having to list +//! each individually, or when you want a rule to apply "any but not all" arguments. +//! +//! Perhaps the most common use of [`ArgGroup`][crate::ArgGroup]s is to require one and *only* one +//! argument to be present out of a given set. Imagine that you had multiple arguments, and you +//! want one of them to be required, but making all of them required isn't feasible because perhaps +//! they conflict with each other. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.md")] +//! +//! ### Custom Validation +//! +//! As a last resort, you can create custom errors with the basics of clap's formatting. +//! +//! ```rust +#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.rs")] +//! ``` +#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.md")] +//! +//! ## Testing +//! +//! clap reports most development errors as `debug_assert!`s. Rather than checking every +//! subcommand, you should have a test that calls +//! [`Command::debug_assert`][crate::App::debug_assert]: +//! ```rust,no_run +#![doc = include_str!("../../examples/tutorial_derive/05_01_assert.rs")] +//! ``` diff --git a/vendor/clap/src/_derive/mod.rs b/vendor/clap/src/_derive/mod.rs new file mode 100644 index 000000000..fc9f35db5 --- /dev/null +++ b/vendor/clap/src/_derive/mod.rs @@ -0,0 +1,510 @@ +//! # Documentation: Derive Reference +//! +//! 1. [Overview](#overview) +//! 2. [Attributes](#attributes) +//! 1. [Terminology](#terminology) +//! 2. [Command Attributes](#command-attributes) +//! 3. [Arg Attributes](#arg-attributes) +//! 4. [ValueEnum Attributes](#valueenum-attributes) +//! 5. [Possible Value Attributes](#possible-value-attributes) +//! 3. [Arg Types](#arg-types) +//! 4. [Doc Comments](#doc-comments) +//! 5. [Mixing Builder and Derive APIs](#mixing-builder-and-derive-apis) +//! 6. [Tips](#tips) +//! +//! ## Overview +//! +//! To derive `clap` types, you need to enable the [`derive` feature flag][crate::_features]. +//! +//! Example: +//! ```rust +#![doc = include_str!("../../examples/demo.rs")] +//! ``` +//! +//! Let's start by breaking down the anatomy of the derive attributes: +//! ```rust +//! use clap::{Parser, Args, Subcommand, ValueEnum}; +//! +//! /// Doc comment +//! #[derive(Parser)] +//! #[clap(APP ATTRIBUTE)] +//! struct Cli { +//! /// Doc comment +//! #[clap(ARG ATTRIBUTE)] +//! field: UserType, +//! +//! #[clap(value_enum, ARG ATTRIBUTE...)] +//! field: EnumValues, +//! +//! #[clap(flatten)] +//! delegate: Struct, +//! +//! #[clap(subcommand)] +//! command: Command, +//! } +//! +//! /// Doc comment +//! #[derive(Args)] +//! #[clap(PARENT APP ATTRIBUTE)] +//! struct Struct { +//! /// Doc comment +//! #[clap(ARG ATTRIBUTE)] +//! field: UserType, +//! } +//! +//! /// Doc comment +//! #[derive(Subcommand)] +//! #[clap(PARENT APP ATTRIBUTE)] +//! enum Command { +//! /// Doc comment +//! #[clap(APP ATTRIBUTE)] +//! Variant1(Struct), +//! +//! /// Doc comment +//! #[clap(APP ATTRIBUTE)] +//! Variant2 { +//! /// Doc comment +//! #[clap(ARG ATTRIBUTE)] +//! field: UserType, +//! } +//! } +//! +//! /// Doc comment +//! #[derive(ValueEnum)] +//! #[clap(VALUE ENUM ATTRIBUTE)] +//! enum EnumValues { +//! /// Doc comment +//! #[clap(POSSIBLE VALUE ATTRIBUTE)] +//! Variant1, +//! } +//! +//! fn main() { +//! let cli = Cli::parse(); +//! } +//! ``` +//! +//! Traits: +//! - [`Parser`][crate::Parser] parses arguments into a `struct` (arguments) or `enum` (subcommands). +//! - [`Args`][crate::Args] allows defining a set of re-usable arguments that get merged into their parent container. +//! - [`Subcommand`][crate::Subcommand] defines available subcommands. +//! - Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant. +//! - [`ValueEnum`][crate::ValueEnum] allows parsing a value directly into an `enum`, erroring on unsupported values. +//! - The derive doesn't work on enums that contain non-unit variants, unless they are skipped +//! +//! *See also the [derive tutorial][crate::_derive::_tutorial] and [cookbook][crate::_cookbook]* +//! +//! ## Attributes +//! +//! ### Terminology +//! +//! **Raw attributes** are forwarded directly to the underlying [`clap` builder][crate::builder]. Any +//! [`Command`][crate::Command], [`Arg`][crate::Arg], or [`PossibleValue`][crate::PossibleValue] method can be used as an attribute. +//! +//! Raw attributes come in two different syntaxes: +//! ```rust,ignore +//! #[clap( +//! global = true, // name = arg form, neat for one-arg methods +//! required_if_eq("out", "file") // name(arg1, arg2, ...) form. +//! )] +//! ``` +//! +//! - `method = arg` can only be used for methods which take only one argument. +//! - `method(arg1, arg2)` can be used with any method. +//! +//! As long as `method_name` is not one of the magical methods it will be +//! translated into a mere method call. +//! +//! **Magic attributes** have post-processing done to them, whether that is +//! - Providing of defaults +//! - Special behavior is triggered off of it +//! +//! Magic attributes are more constrained in the syntax they support, usually just +//! ` = ` though some use `()` instead. See the specific +//! magic attributes documentation for details. This allows users to access the +//! raw behavior of an attribute via `()` syntax. +//! +//! **NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc +//! Comments](#doc-comments). Explicit attributes take precedence over inferred +//! attributes. +//! +//! ### Command Attributes +//! +//! These correspond to a [`Command`][crate::Command] which is used for both top-level parsers and +//! when defining subcommands. +//! +//! **Raw attributes:** Any [`Command` method][crate::Command] can also be used as an attribute, +//! see [Terminology](#terminology) for syntax. +//! - e.g. `#[clap(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)` +//! +//! **Magic attributes:** +//! - `name = `: [`Command::name`][crate::App::name] +//! - When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (if on [`Parser`][crate::Parser] container), variant name (if on [`Subcommand`][crate::Subcommand] variant) +//! - `version [= ]`: [`Command::version`][crate::App::version] +//! - When not present: no version set +//! - Without ``: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field) +//! - `author [= ]`: [`Command::author`][crate::App::author] +//! - When not present: no author set +//! - Without ``: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field) +//! - `about [= ]`: [`Command::about`][crate::App::about] +//! - When not present: [Doc comment summary](#doc-comments) +//! - Without ``: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) ([`Parser`][crate::Parser] container) +//! - **TIP:** When a doc comment is also present, you most likely want to add +//! `#[clap(long_about = None)]` to clear the doc comment so only [`about`][crate::App::about] +//! gets shown with both `-h` and `--help`. +//! - `long_about = `: [`Command::long_about`][crate::App::long_about] +//! - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing +//! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`about`][crate::App::about] / [`long_about`][crate::App::long_about] +//! - `next_display_order`: [`Command::next_display_order`][crate::App::next_display_order] +//! - `next_help_heading`: [`Command::next_help_heading`][crate::App::next_help_heading] +//! - When `flatten`ing [`Args`][crate::Args], this is scoped to just the args in this struct and any struct `flatten`ed into it +//! - `rename_all = `: Override default field / variant name case conversion for [`Command::name`][crate::Command::name] / [`Arg::id`][crate::Arg::id] +//! - When not present: `"kebab-case"` +//! - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"` +//! - `rename_all_env = `: Override default field name case conversion for env variables for [`Arg::env`][crate::Arg::env] +//! - When not present: `"SCREAMING_SNAKE_CASE"` +//! - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"` +//! +//! And for [`Subcommand`][crate::Subcommand] variants: +//! - `skip`: Ignore this variant +//! - `flatten`: Delegates to the variant for more subcommands (must implement +//! [`Subcommand`][crate::Subcommand]) +//! - `subcommand`: Nest subcommands under the current set of subcommands (must implement +//! [`Subcommand`][crate::Subcommand]) +//! - `external_subcommand`: [`Command::allow_external_subcommand(true)`][crate::App::allow_external_subcommands] +//! - Variant must be either `Variant(Vec)` or `Variant(Vec)` +//! +//! ### Arg Attributes +//! +//! These correspond to a [`Arg`][crate::Arg]. +//! +//! **Raw attributes:** Any [`Arg` method][crate::Arg] can also be used as an attribute, see [Terminology](#terminology) for syntax. +//! - e.g. `#[clap(max_values(3))]` would translate to `arg.max_values(3)` +//! +//! **Magic attributes**: +//! - `id = `: [`Arg::id`][crate::Arg::id] +//! - When not present: case-converted field name is used +//! - `name = `: [`Arg::id`][crate::Arg::id] +//! - **Deprecated:** use `id` +//! - `value_parser [= ]`: [`Arg::value_parser`][crate::Arg::value_parser] +//! - When not present: will auto-select an implementation based on the field type using +//! [`value_parser!][crate::value_parser!] +//! - When present but defaulted: opt-in to clap v4 semantics +//! - Env parsing is now dependent on inferred parser +//! - `PathBuf` will implicitly skip UTF-8 validation (before it required specifying +//! `try_from_os_str`) +//! - When present, implies `#[clap(action)]` +//! - To register a custom type's [`ValueParser`][crate::builder::ValueParser], implement [`ValueParserFactory`][crate::builder::ValueParserFactory] +//! - `action [= ]`: [`Arg::action`][crate::Arg::action] +//! - When not present: will auto-select an action based on the field type +//! - When present but defaulted: opt-in to clap v4 semantics +//! - When present, implies `#[clap(value_parser)]` +//! - `args_override_self` is forced on for single flags +//! - `help = `: [`Arg::help`][crate::Arg::help] +//! - When not present: [Doc comment summary](#doc-comments) +//! - `long_help = `: [`Arg::long_help`][crate::Arg::long_help] +//! - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing +//! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`help`][crate::Arg::help] / [`long_help`][crate::Arg::long_help] +//! - `short [= ]`: [`Arg::short`][crate::Arg::short] +//! - When not present: no short set +//! - Without ``: defaults to first character in the case-converted field name +//! - `long [= ]`: [`Arg::long`][crate::Arg::long] +//! - When not present: no long set +//! - Without ``: defaults to the case-converted field name +//! - `env [= ]`: [`Arg::env`][crate::Arg::env] (needs [`env` feature][crate::_features] enabled) +//! - When not present: no env set +//! - Without ``: defaults to the case-converted field name +//! - `flatten`: Delegates to the field for more arguments (must implement [`Args`][crate::Args]) +//! - Only [`next_help_heading`][crate::Command::next_help_heading] can be used with `flatten`. See +//! [clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why +//! arg attributes are not generally supported. +//! - **Tip:** Though we do apply a flattened [`Args`][crate::Args]'s Parent Command Attributes, this +//! makes reuse harder. Generally prefer putting the cmd attributes on the +//! [`Parser`][crate::Parser] or on the flattened field. +//! - `subcommand`: Delegates definition of subcommands to the field (must implement +//! [`Subcommand`][crate::Subcommand]) +//! - When `Option`, the subcommand becomes optional +//! - `from_global`: Read a [`Arg::global`][crate::Arg::global] argument (raw attribute), regardless of what subcommand you are in +//! - `parse( [= ])`: [`Arg::validator`][crate::Arg::validator] and [`ArgMatches::values_of_t`][crate::ArgMatches::values_of_t] +//! - **Deprecated:** +//! - Use `value_parser(...)` for `from_str`, `try_from_str`, `from_os_str`, and `try_from_os_str` +//! - Use `action(ArgAction::Count` for `from_occurrences` +//! - Use `action(ArgAction::SetTrue` for `from_flag` +//! - Default: `try_from_str` +//! - Warning: for `Path` / `OsString`, be sure to use `try_from_os_str` +//! - See [Arg Types](#arg-types) for more details +//! - `value_enum`: Parse the value using the [`ValueEnum`][crate::ValueEnum] +//! - `skip [= ]`: Ignore this field, filling in with `` +//! - Without ``: fills the field with `Default::default()` +//! - `default_value = `: [`Arg::default_value`][crate::Arg::default_value] and [`Arg::required(false)`][crate::Arg::required] +//! - `default_value_t [= ]`: [`Arg::default_value`][crate::Arg::default_value] and [`Arg::required(false)`][crate::Arg::required] +//! - Requires `std::fmt::Display` or `#[clap(value_enum)]` +//! - Without ``, relies on `Default::default()` +//! - `default_values_t = `: [`Arg::default_values`][crate::Arg::default_values] and [`Arg::required(false)`][crate::Arg::required] +//! - Requires field arg to be of type `Vec` and `T` to implement `std::fmt::Display` or `#[clap(value_enum)]` +//! - `` must implement `IntoIterator` +//! - `default_value_os_t [= ]`: [`Arg::default_value_os`][crate::Arg::default_value_os] and [`Arg::required(false)`][crate::Arg::required] +//! - Requires `std::convert::Into` or `#[clap(value_enum)]` +//! - Without ``, relies on `Default::default()` +//! - `default_values_os_t = `: [`Arg::default_values_os`][crate::Arg::default_values_os] and [`Arg::required(false)`][crate::Arg::required] +//! - Requires field arg to be of type `Vec` and `T` to implement `std::convert::Into` or `#[clap(value_enum)]` +//! - `` must implement `IntoIterator` +//! +//! ### ValueEnum Attributes +//! +//! - `rename_all = `: Override default field / variant name case conversion for [`PossibleValue::new`][crate::PossibleValue] +//! - When not present: `"kebab-case"` +//! - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"` +//! +//! ### Possible Value Attributes +//! +//! These correspond to a [`PossibleValue`][crate::PossibleValue]. +//! +//! **Raw attributes:** Any [`PossibleValue` method][crate::PossibleValue] can also be used as an attribute, see [Terminology](#terminology) for syntax. +//! - e.g. `#[clap(alias("foo"))]` would translate to `pv.alias("foo")` +//! +//! **Magic attributes**: +//! - `name = `: [`PossibleValue::new`][crate::PossibleValue::new] +//! - When not present: case-converted field name is used +//! - `help = `: [`PossibleValue::help`][crate::PossibleValue::help] +//! - When not present: [Doc comment summary](#doc-comments) +//! +//! ## Arg Types +//! +//! `clap` assumes some intent based on the type used: +//! +//! | Type | Effect | Implies | +//! |---------------------|--------------------------------------|------------------------------------------------------------------| +//! | `bool` | flag | `#[clap(parse(from_flag))]` | +//! | `Option` | optional argument | `.takes_value(true).required(false)` | +//! | `Option>` | optional value for optional argument | `.takes_value(true).required(false).min_values(0).max_values(1)` | +//! | `T` | required argument | `.takes_value(true).required(!has_default)` | +//! | `Vec` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` | +//! | `Option>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` | +//! +//! Notes: +//! - For custom type behavior, you can override the implied attributes/settings and/or set additional ones +//! - For example, see [custom-bool](./custom-bool.md) +//! - `Option>` will be `None` instead of `vec![]` if no arguments are provided. +//! - This gives the user some flexibility in designing their argument, like with `min_values(0)` +//! +//! You can then support your custom type with `#[clap(parse( [= ]))]`: +//! +//! | `` | Signature | Default `` | +//! |--------------------------|---------------------------------------|---------------------------------| +//! | `from_str` | `fn(&str) -> T` | `::std::convert::From::from` | +//! | `try_from_str` (default) | `fn(&str) -> Result` | `::std::str::FromStr::from_str` | +//! | `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` | +//! | `try_from_os_str` | `fn(&OsStr) -> Result` | (no default function) | +//! | `from_occurrences` | `fn(u64) -> T` | `value as T` | +//! | `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` | +//! +//! Notes: +//! - `from_os_str`: +//! - Implies `arg.takes_value(true).allow_invalid_utf8(true)` +//! - `try_from_os_str`: +//! - Implies `arg.takes_value(true).allow_invalid_utf8(true)` +//! - `from_occurrences`: +//! - Implies `arg.takes_value(false).multiple_occurrences(true)` +//! - Reads from `clap::ArgMatches::occurrences_of` rather than a `get_one` function +//! - Note: operations on values, like `default_value`, are unlikely to do what you want +//! - `from_flag` +//! - Implies `arg.takes_value(false)` +//! - Reads from `clap::ArgMatches::is_present` rather than a `get_one` function +//! - Note: operations on values, like `default_value`, are unlikely to do what you want +//! +//! **Warning:** +//! - To support non-UTF8 paths, you should use `#[clap(value_parser)]` otherwise +//! `clap` will parse it as a `String` which will fail on some paths. +//! +//! ## Doc Comments +//! +//! In clap, help messages for the whole binary can be specified +//! via [`Command::about`][crate::App::about] and [`Command::long_about`][crate::App::long_about] while help messages +//! for individual arguments can be specified via [`Arg::help`][crate::Arg::help] and [`Arg::long_help`][crate::Arg::long_help]. +//! +//! `long_*` variants are used when user calls the program with +//! `--help` and "short" variants are used with `-h` flag. +//! +//! ```rust +//! # use clap::Parser; +//! +//! #[derive(Parser)] +//! #[clap(about = "I am a program and I work, just pass `-h`", long_about = None)] +//! struct Foo { +//! #[clap(short, help = "Pass `-h` and you'll see me!")] +//! bar: String, +//! } +//! ``` +//! +//! For convenience, doc comments can be used instead of raw methods +//! (this example works exactly like the one above): +//! +//! ```rust +//! # use clap::Parser; +//! +//! #[derive(Parser)] +//! /// I am a program and I work, just pass `-h` +//! struct Foo { +//! /// Pass `-h` and you'll see me! +//! bar: String, +//! } +//! ``` +//! +//! **NOTE:** Attributes have priority over doc comments! +//! +//! **Top level doc comments always generate `Command::about/long_about` calls!** +//! If you really want to use the `Command::about/long_about` methods (you likely don't), +//! use the `about` / `long_about` attributes to override the calls generated from +//! the doc comment. To clear `long_about`, you can use +//! `#[clap(long_about = None)]`. +//! +//! **TIP:** Set `#![deny(missing_docs)]` to catch missing `--help` documentation at compile time. +//! +//! ### Pre-processing +//! +//! ```rust +//! # use clap::Parser; +//! #[derive(Parser)] +//! /// Hi there, I'm Robo! +//! /// +//! /// I like beeping, stumbling, eating your electricity, +//! /// and making records of you singing in a shower. +//! /// Pay up, or I'll upload it to youtube! +//! struct Robo { +//! /// Call my brother SkyNet. +//! /// +//! /// I am artificial superintelligence. I won't rest +//! /// until I'll have destroyed humanity. Enjoy your +//! /// pathetic existence, you mere mortals. +//! #[clap(long, action)] +//! kill_all_humans: bool, +//! } +//! ``` +//! +//! A doc comment consists of three parts: +//! - Short summary +//! - A blank line (whitespace only) +//! - Detailed description, all the rest +//! +//! The summary corresponds with `Command::about` / `Arg::help`. When a blank line is +//! present, the whole doc comment will be passed to `Command::long_about` / +//! `Arg::long_help`. Or in other words, a doc may result in just a `Command::about` / +//! `Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` / +//! `Arg::long_help` +//! +//! In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including: +//! +//! - Strip leading and trailing whitespace from every line, if present. +//! +//! - Strip leading and trailing blank lines, if present. +//! +//! - Interpret each group of non-empty lines as a word-wrapped paragraph. +//! +//! We replace newlines within paragraphs with spaces to allow the output +//! to be re-wrapped to the terminal width. +//! +//! - Strip any excess blank lines so that there is exactly one per paragraph break. +//! +//! - If the first paragraph ends in exactly one period, +//! remove the trailing period (i.e. strip trailing periods but not trailing ellipses). +//! +//! Sometimes you don't want this preprocessing to apply, for example the comment contains +//! some ASCII art or markdown tables, you would need to preserve LFs along with +//! blank lines and the leading/trailing whitespace. When you pass use the +//! `verbatim_doc_comment` magic attribute, you preserve +//! them. +//! +//! **Note:** Keep in mind that `verbatim_doc_comment` will *still* +//! - Remove one leading space from each line, even if this attribute is present, +//! to allow for a space between `///` and the content. +//! - Remove leading and trailing blank lines +//! +//! ## Mixing Builder and Derive APIs +//! +//! The builder and derive APIs do not live in isolation. They can work together, which is +//! especially helpful if some arguments can be specified at compile-time while others must be +//! specified at runtime. +//! +//! ### Using derived arguments in a builder application +//! +//! When using the derive API, you can `#[clap(flatten)]` a struct deriving `Args` into a struct +//! deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance +//! created using the builder API with `Args` created using the derive API. +//! +//! It uses the [`Args::augment_args`][crate::Args::augment_args] method to add the arguments to +//! the `Command` instance. +//! +//! Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide +//! structs that implement `Args`. Without the technique shown in this example, it would not be +//! possible to use such crates with the builder API. +//! +//! For example: +//! ```rust +#![doc = include_str!("../../examples/derive_ref/augment_args.rs")] +//! ``` +//! +//! ### Using derived subcommands in a builder application +//! +//! When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add +//! subcommands. The type of the field is usually an enum that derived `Parser`. However, you can +//! also add the subcommands in that enum to a `Command` instance created with the builder API. +//! +//! It uses the [`Subcommand::augment_subcommands`][crate::Subcommand::augment_subcommands] method +//! to add the subcommands to the `Command` instance. +//! +//! For example: +//! ```rust +#![doc = include_str!("../../examples/derive_ref/augment_subcommands.rs")] +//! ``` +//! +//! ### Adding hand-implemented subcommands to a derived application +//! +//! When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add +//! subcommands. The type of the field is usually an enum that derived `Parser`. However, you can +//! also implement the `Subcommand` trait manually on this enum (or any other type) and it can +//! still be used inside the struct created with the derive API. The implementation of the +//! `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance +//! created behind the scenes for you by the derive API. +//! +//! Notice how in the previous example we used +//! [`augment_subcommands`][crate::Subcommand::augment_subcommands] on an enum that derived +//! `Parser`, whereas now we implement +//! [`augment_subcommands`][crate::Subcommand::augment_subcommands] ourselves, but the derive API +//! calls it automatically since we used the `#[clap(subcommand)]` attribute. +//! +//! For example: +//! ```rust +#![doc = include_str!("../../examples/derive_ref/hand_subcommand.rs")] +//! ``` +//! +//! ### Flattening hand-implemented args into a derived application +//! +//! When using the derive API, you can use `#[clap(flatten)]` inside the struct to add arguments as +//! if they were added directly to the containing struct. The type of the field is usually an +//! struct that derived `Args`. However, you can also implement the `Args` trait manually on this +//! struct (or any other type) and it can still be used inside the struct created with the derive +//! API. The implementation of the `Args` trait will use the builder API to add the arguments to +//! the `Command` instance created behind the scenes for you by the derive API. +//! +//! Notice how in the previous example we used [`augment_args`][crate::Args::augment_args] on the +//! struct that derived `Parser`, whereas now we implement +//! [`augment_args`][crate::Args::augment_args] ourselves, but the derive API calls it +//! automatically since we used the `#[clap(flatten)]` attribute. +//! +//! For example: +//! ```rust +#![doc = include_str!("../../examples/derive_ref/flatten_hand_args.rs")] +//! ``` +//! +//! ## Tips +//! +//! - To get access to a [`Command`][crate::Command] call +//! [`CommandFactory::command`][crate::CommandFactory::command] (implemented when deriving +//! [`Parser`][crate::Parser]) +//! - Proactively check for bad [`Command`][crate::Command] configurations by calling +//! [`Command::debug_assert`][crate::App::debug_assert] in a test +//! ([example](../tutorial_derive/05_01_assert.rs)) + +pub mod _tutorial; +#[doc(inline)] +pub use crate::_cookbook; diff --git a/vendor/clap/src/_faq.rs b/vendor/clap/src/_faq.rs new file mode 100644 index 000000000..661a7e73d --- /dev/null +++ b/vendor/clap/src/_faq.rs @@ -0,0 +1,95 @@ +//! # Documentation: FAQ +//! +//! 1. [Comparisons](#comparisons) +//! 1. [How does `clap` compare to structopt?](#how-does-clap-compare-to-structopt) +//! 2. [What are some reasons to use `clap`? (The Pitch)](#what-are-some-reasons-to-use-clap-the-pitch) +//! 3. [What are some reasons *not* to use `clap`? (The Anti Pitch)](#what-are-some-reasons-not-to-use-clap-the-anti-pitch) +//! 4. [Reasons to use `clap`](#reasons-to-use-clap) +//! 2. [How many approaches are there to create a parser?](#how-many-approaches-are-there-to-create-a-parser) +//! 3. [When should I use the builder vs derive APIs?](#when-should-i-use-the-builder-vs-derive-apis) +//! 4. [Why is there a default subcommand of help?](#why-is-there-a-default-subcommand-of-help) +//! +//! ### Comparisons +//! +//! First, let me say that these comparisons are highly subjective, and not meant +//! in a critical or harsh manner. All the argument parsing libraries out there (to +//! include `clap`) have their own strengths and weaknesses. Sometimes it just +//! comes down to personal taste when all other factors are equal. When in doubt, +//! try them all and pick one that you enjoy :) There's plenty of room in the Rust +//! community for multiple implementations! +//! +//! For less detailed but more broad comparisons, see +//! [argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs). +//! +//! #### How does `clap` compare to [structopt](https://github.com/TeXitoi/structopt)? +//! +//! Simple! `clap` *is* `structopt`. `structopt` started as a derive API built on +//! top of clap v2. With clap v3, we've forked structopt and integrated it +//! directly into clap. structopt is in +//! [maintenance mode](https://github.com/TeXitoi/structopt/issues/516#issuecomment-989566094) +//! with the release of `clap_derive`. +//! +//! The benefits of integrating `structopt` and `clap` are: +//! - Easier cross-linking in documentation +//! - [Documentation parity](../examples) +//! - Tighter design feedback loop, ensuring all new features are designed with +//! derives in mind and easier to change `clap` in response to `structopt` bugs. +//! - Clearer endorsement of `structopt` +//! +//! See also +//! - [`clap` v3 CHANGELOG](../CHANGELOG.md#300---2021-12-31) +//! - [`structopt` migration guide](../CHANGELOG.md#migrate-structopt) +//! +//! #### What are some reasons to use `clap`? (The Pitch) +//! +//! `clap` is as fast, and as lightweight as possible while still giving all the features you'd expect from a modern argument parser. In fact, for the amount and type of features `clap` offers it remains about as fast as `getopts`. If you use `clap` when just need some simple arguments parsed, you'll find it's a walk in the park. `clap` also makes it possible to represent extremely complex, and advanced requirements, without too much thought. `clap` aims to be intuitive, easy to use, and fully capable for wide variety use cases and needs. +//! +//! #### What are some reasons *not* to use `clap`? (The Anti Pitch) +//! +//! Depending on the style in which you choose to define the valid arguments, `clap` can be very verbose. `clap` also offers so many finetuning knobs and dials, that learning everything can seem overwhelming. I strive to keep the simple cases simple, but when turning all those custom dials it can get complex. `clap` is also opinionated about parsing. Even though so much can be tweaked and tuned with `clap` (and I'm adding more all the time), there are still certain features which `clap` implements in specific ways which may be contrary to some users use-cases. +//! +//! #### Reasons to use `clap` +//! +//! * You want all the nice CLI features your users may expect, yet you don't want to implement them all yourself. You'd like to focus your application, not argument parsing. +//! * In addition to the point above; you don't want to sacrifice performance to get all those nice features +//! * You have complex requirements/conflicts between your various valid args. +//! * You want to use subcommands (although other libraries also support subcommands, they are not nearly as feature rich as those provided by `clap`) +//! * You want some sort of custom validation built into the argument parsing process, instead of as part of your application (which allows for earlier failures, better error messages, more cohesive experience, etc.) +//! +//! ### How many approaches are there to create a parser? +//! +//! The following APIs are supported: +//! - [Derive][crate::_derive::_tutorial] +//! - [Builder][crate::_tutorial] +//! +//! Previously, we supported: +//! - [YAML](https://github.com/clap-rs/clap/issues/3087) +//! - [docopt](http://docopt.org/)-inspired [usage parser](https://github.com/clap-rs/clap/issues/3086) +//! - [`clap_app!`](https://github.com/clap-rs/clap/issues/2835) +//! +//! There are also experiments with other APIs: +//! - [fncmd](https://github.com/yuhr/fncmd): function attribute +//! - [clap-serde](https://github.com/aobatact/clap-serde): create an `Command` from a deserializer +//! +//! ### When should I use the builder vs derive APIs? +//! +//! Our default answer is to use the [Derive API][crate::_derive::_tutorial]: +//! - Easier to read, write, and modify +//! - Easier to keep the argument declaration and reading of argument in sync +//! - Easier to reuse, e.g. [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag) +//! +//! The [Builder API][crate::_tutorial] is a lower-level API that someone might want to use for +//! - Faster compile times if you aren't already using other procedural macros +//! - More flexibility, e.g. you can look up an [arguments values][crate::ArgMatches::get_many], +//! their [ordering with other arguments][crate::ArgMatches::indices_of], and [what set +//! them][crate::ArgMatches::value_source]. The Derive API can only report values and not +//! indices of or other data. +//! +//! You can [interop between Derive and Builder APIs][crate::_derive#mixing-builder-and-derive-apis]. +//! +//! ### Why is there a default subcommand of help? +//! +//! There is only a default subcommand of `help` when other subcommands have been defined manually. So it's opt-in(ish), being that you only get a `help` subcommand if you're actually using subcommands. +//! +//! Also, if the user defined a `help` subcommand themselves, the auto-generated one wouldn't be added (meaning it's only generated if the user hasn't defined one themselves). +//! diff --git a/vendor/clap/src/_features.rs b/vendor/clap/src/_features.rs new file mode 100644 index 000000000..923134c45 --- /dev/null +++ b/vendor/clap/src/_features.rs @@ -0,0 +1,27 @@ +//! ## Documentation: Feature Flags +//! +//! Available [compile-time feature flags](https://doc.rust-lang.org/cargo/reference/features.html#dependency-features) +//! +//! #### Default Features +//! +//! * **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner. +//! * **color**: Turns on colored error messages. +//! * **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. +//! +//! #### Optional features +//! +//! * **deprecated**: Guided experience to prepare for next breaking release (at different stages of development, this may become default) +//! * **derive**: Enables the custom derive (i.e. `#[derive(Parser)]`). Without this you must use one of the other methods of creating a `clap` CLI listed above. +//! * **cargo**: Turns on macros that read values from [`CARGO_*` environment variables](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates). +//! * **env**: Turns on the usage of environment variables during parsing. +//! * **regex**: Enables regex validators. +//! * **unicode**: Turns on support for unicode characters (including emoji) in arguments and help messages. +//! * **wrap_help**: Turns on the help text wrapping feature, based on the terminal size. +//! +//! #### Experimental features +//! +//! **Warning:** These may contain breaking changes between minor releases. +//! +//! * **unstable-replace**: Enable [`Command::replace`](https://github.com/clap-rs/clap/issues/2836) +//! * **unstable-grouped**: Enable [`ArgMatches::grouped_values_of`](https://github.com/clap-rs/clap/issues/2924) +//! * **unstable-v4**: Preview features which will be stable on the v4.0 release diff --git a/vendor/clap/src/_tutorial.rs b/vendor/clap/src/_tutorial.rs new file mode 100644 index 000000000..9dbfc6864 --- /dev/null +++ b/vendor/clap/src/_tutorial.rs @@ -0,0 +1,204 @@ +// Contributing +// +// New example code: +// - Please update the corresponding section in the derive tutorial +// - Building: They must be added to `Cargo.toml` with the appropriate `required-features`. +// - Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax +// +// See also the general CONTRIBUTING + +//! # Documentation: Builder Tutorial +//! +//! 1. [Quick Start](#quick-start) +//! 2. [Configuring the Parser](#configuring-the-parser) +//! 3. [Adding Arguments](#adding-arguments) +//! 1. [Positionals](#positionals) +//! 2. [Options](#options) +//! 3. [Flags](#flags) +//! 4. [Subcommands](#subcommands) +//! 5. [Defaults](#defaults) +//! 4. Validation +//! 1. [Enumerated values](#enumerated-values) +//! 2. [Validated values](#validated-values) +//! 3. [Argument Relations](#argument-relations) +//! 4. [Custom Validation](#custom-validation) +//! 5. [Testing](#testing) +//! +//! See also +//! - [FAQ: When should I use the builder vs derive APIs?][crate::_faq#when-should-i-use-the-builder-vs-derive-apis] +//! - The [cookbook][crate::_cookbook] for more application-focused examples +//! +//! ## Quick Start +//! +//! You can create an application with several arguments using usage strings. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/01_quick.rs")] +//! ``` +//! +#![doc = include_str!("../examples/tutorial_builder/01_quick.md")] +//! +//! ## Configuring the Parser +//! +//! You use [`Command`][crate::Command] to start building a parser. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/02_apps.rs")] +//! ``` +//! +#![doc = include_str!("../examples/tutorial_builder/02_apps.md")] +//! +//! You can use [`command!()`][crate::command!] to fill these fields in from your `Cargo.toml` +//! file. **This requires the [`cargo` feature flag][crate::_features].** +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/02_crate.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/02_crate.md")] +//! +//! You can use [`Command`][crate::Command] methods to change the application level behavior of +//! clap. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/02_app_settings.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/02_app_settings.md")] +//! +//! ## Adding Arguments +//! +//! ### Positionals +//! +//! You can have users specify values by their position on the command-line: +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_03_positional.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_03_positional.md")] +//! +//! ### Options +//! +//! You can name your arguments with a flag: +//! - Order doesn't matter +//! - They can be optional +//! - Intent is clearer +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_02_option.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_02_option.md")] +//! +//! ### Flags +//! +//! Flags can also be switches that can be on/off: +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_01_flag_bool.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_01_flag_bool.md")] +//! +//! Or counted. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_01_flag_count.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_01_flag_count.md")] +//! +//! ### Subcommands +//! +//! Subcommands are defined as [`Command`][crate::Command]s that get added via +//! [`Command::subcommand`][crate::Command::subcommand]. Each instance of a Subcommand can have its +//! own version, author(s), Args, and even its own subcommands. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_04_subcommands.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_04_subcommands.md")] +//! +//! ### Defaults +//! +//! We've previously showed that arguments can be [`required`][crate::Arg::required] or optional. +//! When optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can set +//! [`Arg::default_value`][crate::Arg::default_value]. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/03_05_default_values.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/03_05_default_values.md")] +//! +//! ## Validation +//! +//! ### Enumerated values +//! +//! If you have arguments of specific values you want to test for, you can use the +//! [`PossibleValuesParser`][crate::builder::PossibleValuesParser] or [`Arg::value_parser(["val1", +//! ...])`][crate::Arg::value_parser] for short. +//! +//! This allows you specify the valid values for that argument. If the user does not use one of +//! those specific values, they will receive a graceful exit with error message informing them +//! of the mistake, and what the possible valid values are +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_01_possible.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_01_possible.md")] +//! +//! When enabling the [`derive` feature][crate::_features], you can use +//! [`ValueEnum`][crate::ValueEnum] to take care of the boiler plate for you, giving the same +//! results. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_01_enum.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_01_enum.md")] +//! +//! ### Validated values +//! +//! More generally, you can validate and parse into any data type. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_02_parse.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_02_parse.md")] +//! +//! A custom parser can be used to improve the error messages or provide additional validation: +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_02_validate.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_02_validate.md")] +//! +//! ### Argument Relations +//! +//! You can declare dependencies or conflicts between [`Arg`][crate::Arg]s or even +//! [`ArgGroup`][crate::ArgGroup]s. +//! +//! [`ArgGroup`][crate::ArgGroup]s make it easier to declare relations instead of having to list +//! each individually, or when you want a rule to apply "any but not all" arguments. +//! +//! Perhaps the most common use of [`ArgGroup`][crate::ArgGroup]s is to require one and *only* one +//! argument to be present out of a given set. Imagine that you had multiple arguments, and you +//! want one of them to be required, but making all of them required isn't feasible because perhaps +//! they conflict with each other. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_03_relations.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_03_relations.md")] +//! +//! ### Custom Validation +//! +//! As a last resort, you can create custom errors with the basics of clap's formatting. +//! +//! ```rust +#![doc = include_str!("../examples/tutorial_builder/04_04_custom.rs")] +//! ``` +#![doc = include_str!("../examples/tutorial_builder/04_04_custom.md")] +//! +//! ## Testing +//! +//! clap reports most development errors as `debug_assert!`s. Rather than checking every +//! subcommand, you should have a test that calls +//! [`Command::debug_assert`][crate::App::debug_assert]: +//! ```rust,no_run +#![doc = include_str!("../examples/tutorial_builder/05_01_assert.rs")] +//! ``` diff --git a/vendor/clap/src/builder/action.rs b/vendor/clap/src/builder/action.rs index ab3314290..71a91a8b1 100644 --- a/vendor/clap/src/builder/action.rs +++ b/vendor/clap/src/builder/action.rs @@ -183,16 +183,16 @@ pub enum ArgAction { /// assert!(matches.contains_id("flag")); /// assert_eq!(matches.occurrences_of("flag"), 0); /// assert_eq!( - /// matches.get_one::("flag").copied(), - /// Some(2) + /// matches.get_count("flag"), + /// 2 /// ); /// /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap(); /// assert!(matches.contains_id("flag")); /// assert_eq!(matches.occurrences_of("flag"), 0); /// assert_eq!( - /// matches.get_one::("flag").copied(), - /// Some(0) + /// matches.get_count("flag"), + /// 0 /// ); /// ``` Count, diff --git a/vendor/clap/src/builder/app_settings.rs b/vendor/clap/src/builder/app_settings.rs index e2d9ba6b1..88bc243c4 100644 --- a/vendor/clap/src/builder/app_settings.rs +++ b/vendor/clap/src/builder/app_settings.rs @@ -400,23 +400,20 @@ pub enum AppSettings { )] NoAutoVersion, - /// Deprecated, replaced with [`AppSettings::AllowHyphenValues`] + /// Deprecated, replaced with [`Command::allow_hyphen_values`] #[cfg_attr( feature = "deprecated", - deprecated( - since = "3.0.0", - note = "Replaced with `AppSettings::AllowHyphenValues`" - ) + deprecated(since = "3.0.0", note = "Replaced with `Command::allow_hyphen_values`") )] #[doc(hidden)] AllowLeadingHyphen, - /// Deprecated, this is now the default, see [`AppSettings::AllowInvalidUtf8ForExternalSubcommands`] and [`ArgSettings::AllowInvalidUtf8`][crate::ArgSettings::AllowInvalidUtf8] for the opposite. + /// Deprecated, replaced with [`Command::allow_invalid_utf8_for_external_subcommands`] and [`Command::is_allow_invalid_utf8_for_external_subcommands_set`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "This is now the default see `AppSettings::AllowInvalidUtf8ForExternalSubcommands` and `ArgSettings::AllowInvalidUtf8` for the opposite." + note = "Replaced with `Command::allow_invalid_utf8_for_external_subcommands` and `Command::is_allow_invalid_utf8_for_external_subcommands_set`" ) )] #[doc(hidden)] @@ -462,42 +459,47 @@ pub enum AppSettings { #[doc(hidden)] ColorNever, - /// Deprecated, replaced with [`AppSettings::DisableHelpFlag`] + /// Deprecated, replaced with [`Command::disable_help_flag`] and [`Command::is_disable_help_flag_set`] #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `AppSettings::DisableHelpFlag`") + deprecated( + since = "3.0.0", + note = "Replaced with `Command::disable_help_flag` and `Command::is_disable_help_flag_set`" + ) )] #[doc(hidden)] DisableHelpFlags, - /// Deprecated, replaced with [`AppSettings::DisableVersionFlag`] + /// Deprecated, replaced with [`Command::disable_version_flag`] and + /// [`Command::is_disable_version_flag_set`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "Replaced with `AppSettings::DisableVersionFlag`" + note = "Replaced with `Command::disable_version_flag` and `Command::is_disable_version_flag_set`" ) )] #[doc(hidden)] DisableVersion, - /// Deprecated, replaced with [`AppSettings::PropagateVersion`] + /// Deprecated, replaced with [`Command::propagate_version`] and [`Command::is_propagate_version_set`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "Replaced with `AppSettings::PropagateVersion`" + note = "Replaced with `Command::propagate_version` and `Command::is_propagate_version_set`" ) )] #[doc(hidden)] GlobalVersion, - /// Deprecated, replaced with [`AppSettings::HidePossibleValues`] + /// Deprecated, replaced with [`Command::hide_possible_values`] and + /// [`Arg::is_hide_possible_values_set`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "Replaced with AppSettings::HidePossibleValues" + note = "Replaced with `Command::hide_possible_values` and `Arg::is_hide_possible_values_set`" ) )] #[doc(hidden)] diff --git a/vendor/clap/src/builder/arg.rs b/vendor/clap/src/builder/arg.rs index 63e88e80e..e9403d0b7 100644 --- a/vendor/clap/src/builder/arg.rs +++ b/vendor/clap/src/builder/arg.rs @@ -4316,6 +4316,16 @@ impl<'help> Arg<'help> { } } + /// Get *all* short aliases for this argument, if any, both visible and hidden. + #[inline] + pub fn get_all_short_aliases(&self) -> Option> { + if self.short_aliases.is_empty() { + None + } else { + Some(self.short_aliases.iter().map(|(s, _)| s).copied().collect()) + } + } + /// Get the short option name and its visible aliases, if any #[inline] pub fn get_short_and_visible_aliases(&self) -> Option> { @@ -4351,6 +4361,16 @@ impl<'help> Arg<'help> { } } + /// Get *all* aliases for this argument, if any, both visible and hidden. + #[inline] + pub fn get_all_aliases(&self) -> Option> { + if self.aliases.is_empty() { + None + } else { + Some(self.aliases.iter().map(|(s, _)| s).copied().collect()) + } + } + /// Get the long option name and its visible aliases, if any #[inline] pub fn get_long_and_visible_aliases(&self) -> Option> { diff --git a/vendor/clap/src/builder/arg_settings.rs b/vendor/clap/src/builder/arg_settings.rs index 3b7faf7bf..ecc064caa 100644 --- a/vendor/clap/src/builder/arg_settings.rs +++ b/vendor/clap/src/builder/arg_settings.rs @@ -50,14 +50,10 @@ pub enum ArgSettings { ) )] MultipleValues, - /// Deprecated, replaced with [`Arg::multiple_occurrences`] and - /// [`Arg::is_multiple_occurrences_set`] + /// Deprecated, replaced with [`Arg::action`] ([Issue #3772](https://github.com/clap-rs/clap/issues/3772)) #[cfg_attr( feature = "deprecated", - deprecated( - since = "3.1.0", - note = "Replaced with `Arg::multiple_occurrences` and `Arg::is_multiple_occurrences_set`" - ) + deprecated(since = "3.1.0", note = "Replaced with `Arg::action` (Issue #3772)") )] MultipleOccurrences, /// Deprecated, see [`ArgSettings::MultipleOccurrences`] (most likely what you want) and @@ -66,18 +62,17 @@ pub enum ArgSettings { feature = "deprecated", deprecated( since = "3.0.0", - note = "Split into `ArgSettings::MultipleOccurrences` (most likely what you want) and `ArgSettings::MultipleValues`" + note = "Split into `Arg::multiple_occurrences` (most likely what you want) and `Arg::multiple_values`" ) )] #[doc(hidden)] Multiple, - /// Deprecated, replaced with [`Arg::forbid_empty_values`] and - /// [`Arg::is_forbid_empty_values_set`] + /// Deprecated, replaced with [`Arg::value_parser(NonEmptyStringValueParser::new())`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.1.0", - note = "Replaced with `Arg::forbid_empty_values` and `Arg::is_forbid_empty_values_set`" + note = "Replaced with `Arg::value_parser(NonEmptyStringValueParser::new())`" ) )] ForbidEmptyValues, @@ -157,12 +152,13 @@ pub enum ArgSettings { ) )] AllowHyphenValues, - /// Deprecated, replaced with [`ArgSettings::AllowHyphenValues`] + /// Deprecated, replaced with [`Arg::allow_hyphen_values`] and + /// [`Arg::is_allow_hyphen_values_set`] #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "Replaced with `ArgSettings::AllowHyphenValues`" + note = "Replaced with `Arg::allow_hyphen_values` and `Arg::is_allow_hyphen_values_set`" ) )] #[doc(hidden)] @@ -203,10 +199,13 @@ pub enum ArgSettings { ) )] IgnoreCase, - /// Deprecated, replaced with [`ArgSettings::IgnoreCase`] + /// Deprecated, replaced with [`Arg::ignore_case`] and [`Arg::is_ignore_case_set`] #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `ArgSettings::IgnoreCase`") + deprecated( + since = "3.0.0", + note = "Replaced with `Arg::ignore_case` and `Arg::is_ignore_case_set`" + ) )] #[doc(hidden)] CaseInsensitive, diff --git a/vendor/clap/src/builder/command.rs b/vendor/clap/src/builder/command.rs index 1fcb64ecc..de59ad8cd 100644 --- a/vendor/clap/src/builder/command.rs +++ b/vendor/clap/src/builder/command.rs @@ -274,6 +274,50 @@ impl<'help> App<'help> { self } + /// Allows one to mutate a [`Command`] after it's been added as a subcommand. + /// + /// This can be useful for modifying auto-generated arguments of nested subcommands with + /// [`Command::mut_arg`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Command; + /// + /// let mut cmd = Command::new("foo") + /// .subcommand(Command::new("bar")) + /// .mut_subcommand("bar", |subcmd| subcmd.disable_help_flag(true)); + /// + /// let res = cmd.try_get_matches_from_mut(vec!["foo", "bar", "--help"]); + /// + /// // Since we disabled the help flag on the "bar" subcommand, this should err. + /// + /// assert!(res.is_err()); + /// + /// let res = cmd.try_get_matches_from_mut(vec!["foo", "bar"]); + /// assert!(res.is_ok()); + /// ``` + #[must_use] + pub fn mut_subcommand<'a, T, F>(mut self, subcmd_id: T, f: F) -> Self + where + F: FnOnce(App<'help>) -> App<'help>, + T: Into<&'a str>, + { + let subcmd_id: &str = subcmd_id.into(); + let id = Id::from(subcmd_id); + + let pos = self.subcommands.iter().position(|s| s.id == id); + + let subcmd = if let Some(idx) = pos { + self.subcommands.remove(idx) + } else { + App::new(subcmd_id) + }; + + self.subcommands.push(f(subcmd)); + self + } + /// Adds an [`ArgGroup`] to the application. /// /// [`ArgGroup`]s are a family of related arguments. @@ -700,7 +744,7 @@ impl<'help> App<'help> { /// [`io::stdout()`]: std::io::stdout() pub fn print_help(&mut self) -> io::Result<()> { self._build_self(); - let color = self.get_color(); + let color = self.color_help(); let mut c = Colorizer::new(Stream::Stdout, color); let usage = Usage::new(self); @@ -725,7 +769,7 @@ impl<'help> App<'help> { /// [`--help` (long)]: Arg::long_help() pub fn print_long_help(&mut self) -> io::Result<()> { self._build_self(); - let color = self.get_color(); + let color = self.color_help(); let mut c = Colorizer::new(Stream::Stdout, color); let usage = Usage::new(self); @@ -1604,6 +1648,14 @@ impl<'help> App<'help> { /// strings. After this setting is set, this will be *the only* usage string /// displayed to the user! /// + /// **NOTE:** Multiple usage lines may be present in the usage argument, but + /// some rules need to be followed to ensure the usage lines are formatted + /// correctly by the default help formatter: + /// + /// - Do not indent the first usage line. + /// - Indent all subsequent usage lines with four spaces. + /// - The last line must not end with a newline. + /// /// # Examples /// /// ```no_run @@ -1612,6 +1664,20 @@ impl<'help> App<'help> { /// .override_usage("myapp [-clDas] ") /// # ; /// ``` + /// + /// Or for multiple usage lines: + /// + /// ```no_run + /// # use clap::{Command, Arg}; + /// Command::new("myprog") + /// .override_usage( + /// "myapp -X [-a] [-b] \n \ + /// myapp -Y [-c] \n \ + /// myapp -Z [-d|-e]" + /// ) + /// # ; + /// ``` + /// /// [`ArgMatches::usage`]: ArgMatches::usage() #[must_use] pub fn override_usage>(mut self, usage: S) -> Self { @@ -3512,15 +3578,21 @@ impl<'help> App<'help> { if arg.is_global_set() { self.get_global_arg_conflicts_with(arg) } else { - arg.blacklist - .iter() - .map(|id| { - self.args.args().find(|arg| arg.id == *id).expect( - "Command::get_arg_conflicts_with: \ - The passed arg conflicts with an arg unknown to the cmd", - ) - }) - .collect() + let mut result = Vec::new(); + for id in arg.blacklist.iter() { + if let Some(arg) = self.find(id) { + result.push(arg); + } else if let Some(group) = self.find_group(id) { + result.extend( + self.unroll_args_in_group(&group.id) + .iter() + .map(|id| self.find(id).expect(INTERNAL_ERROR_MSG)), + ); + } else { + panic!("Command::get_arg_conflicts_with: The passed arg conflicts with an arg unknown to the cmd"); + } + } + result } } @@ -4264,7 +4336,8 @@ impl<'help> App<'help> { use std::fmt::Write; let mut mid_string = String::from(" "); - if !self.is_subcommand_negates_reqs_set() { + if !self.is_subcommand_negates_reqs_set() && !self.is_args_conflicts_with_subcommands_set() + { let reqs = Usage::new(self).get_required_usage_from(&[], None, true); // maybe Some(m) for s in &reqs { @@ -4347,7 +4420,9 @@ impl<'help> App<'help> { if !self.is_set(AppSettings::BinNameBuilt) { let mut mid_string = String::from(" "); - if !self.is_subcommand_negates_reqs_set() { + if !self.is_subcommand_negates_reqs_set() + && !self.is_args_conflicts_with_subcommands_set() + { let reqs = Usage::new(self).get_required_usage_from(&[], None, true); // maybe Some(m) for s in &reqs { @@ -5107,3 +5182,8 @@ where _ => None, } } + +#[test] +fn check_auto_traits() { + static_assertions::assert_impl_all!(Command: Send, Sync, Unpin); +} diff --git a/vendor/clap/src/builder/value_parser.rs b/vendor/clap/src/builder/value_parser.rs index 397537c9f..0492f2782 100644 --- a/vendor/clap/src/builder/value_parser.rs +++ b/vendor/clap/src/builder/value_parser.rs @@ -12,7 +12,7 @@ use crate::parser::AnyValueId; /// use within an application. /// /// See -/// - [`value_parser!`] for automatically selecting an implementation for a given type +/// - [`value_parser!`][crate::value_parser] for automatically selecting an implementation for a given type /// - [`ValueParser::new`] for additional [`TypedValueParser`] that can be used /// /// # Example diff --git a/vendor/clap/src/derive.rs b/vendor/clap/src/derive.rs index bfb7bdfa2..b6ac04df6 100644 --- a/vendor/clap/src/derive.rs +++ b/vendor/clap/src/derive.rs @@ -19,11 +19,9 @@ use std::ffi::OsString; /// /// See also [`Subcommand`] and [`Args`]. /// -/// See the -/// [derive reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) -/// for attributes and best practices. +/// See the [derive reference](crate::_derive) for attributes and best practices. /// -/// **NOTE:** Deriving requires the `derive` feature flag +/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] /// /// # Examples /// @@ -156,13 +154,13 @@ pub trait Parser: FromArgMatches + CommandFactory + Sized { .map_err(format_error::) } - /// Deprecated, `StructOpt::clap` replaced with [`IntoCommand::command`] (derive as part of + /// Deprecated, `StructOpt::clap` replaced with [`CommandFactory::command`] (derive as part of /// [`Parser`]) #[cfg_attr( feature = "deprecated", deprecated( since = "3.0.0", - note = "`StructOpt::clap` is replaced with `IntoCommand::command` (derived as part of `Parser`)" + note = "`StructOpt::clap` is replaced with `CommandFactory::command` (derived as part of `Parser`)" ) )] #[doc(hidden)] @@ -372,11 +370,9 @@ pub trait FromArgMatches: Sized { /// `Args`. /// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`. /// -/// See the -/// [derive reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) -/// for attributes and best practices. +/// See the [derive reference](crate::_derive) for attributes and best practices. /// -/// **NOTE:** Deriving requires the `derive` feature flag +/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] /// /// # Example /// @@ -416,11 +412,9 @@ pub trait Args: FromArgMatches + Sized { /// - `#[clap(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl /// `Subcommand`. /// -/// See the -/// [derive reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) -/// for attributes and best practices. +/// See the [derive reference](crate::_derive) for attributes and best practices. /// -/// **NOTE:** Deriving requires the `derive` feature flag +/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] /// /// # Example /// @@ -460,11 +454,9 @@ pub trait Subcommand: FromArgMatches + Sized { /// - Call [`Arg::possible_values`][crate::Arg::possible_values] /// - Allowing using the `#[clap(default_value_t)]` attribute without implementing `Display`. /// -/// See the -/// [derive reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) -/// for attributes and best practices. +/// See the [derive reference](crate::_derive) for attributes and best practices. /// -/// **NOTE:** Deriving requires the `derive` feature flag +/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features] /// /// # Example /// diff --git a/vendor/clap/src/error/kind.rs b/vendor/clap/src/error/kind.rs index 21256609a..4c3dc48b0 100644 --- a/vendor/clap/src/error/kind.rs +++ b/vendor/clap/src/error/kind.rs @@ -407,7 +407,7 @@ impl ErrorKind { Self::UnrecognizedSubcommand => Some("A subcommand wasn't recognized"), Self::EmptyValue => Some("An argument requires a value but none was supplied"), Self::NoEquals => Some("Equal is needed when assigning values to one of the arguments"), - Self::ValueValidation => Some("Invalid for for one of the arguments"), + Self::ValueValidation => Some("Invalid value for one of the arguments"), Self::TooManyValues => Some("An argument received an unexpected value"), Self::TooFewValues => Some("An argument requires more values"), Self::TooManyOccurrences => Some("An argument occurred too many times"), diff --git a/vendor/clap/src/error/mod.rs b/vendor/clap/src/error/mod.rs index df9a84c56..fbd2b30a8 100644 --- a/vendor/clap/src/error/mod.rs +++ b/vendor/clap/src/error/mod.rs @@ -1147,12 +1147,7 @@ impl Display for Backtrace { } } -#[cfg(test)] -mod tests { - /// Check `clap::Error` impls Send and Sync. - mod clap_error_impl_send_sync { - use crate::Error; - trait Foo: std::error::Error + Send + Sync + 'static {} - impl Foo for Error {} - } +#[test] +fn check_auto_traits() { + static_assertions::assert_impl_all!(Error: Send, Sync, Unpin); } diff --git a/vendor/clap/src/lib.rs b/vendor/clap/src/lib.rs index d9a97715f..5cefe6ec1 100644 --- a/vendor/clap/src/lib.rs +++ b/vendor/clap/src/lib.rs @@ -3,10 +3,79 @@ // (see LICENSE or ) All files in the project carrying such // notice may not be copied, modified, or distributed except according to those terms. +//! > **Command Line Argument Parser for Rust** +//! +//! Quick Links: +//! - Derive [tutorial][_derive::_tutorial] and [reference][_derive] +//! - Builder [tutorial][_tutorial] and [reference](index.html) +//! - [Cookbook][_cookbook] +//! - [FAQ][_faq] +//! - [Discussions](https://github.com/clap-rs/clap/discussions) +//! +//! ## Aspirations +//! +//! - Out of the box, users get a polished CLI experience +//! - Including common argument behavior, help generation, suggested fixes for users, colored output, [shell completions](https://github.com/clap-rs/clap/tree/master/clap_complete), etc +//! - Flexible enough to port your existing CLI interface +//! - However, we won't necessarily streamline support for each use case +//! - Reasonable parse performance +//! - Resilient maintainership, including +//! - Willing to break compatibility rather than batching up breaking changes in large releases +//! - Leverage feature flags to keep to one active branch +//! - Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor +//! - We follow semver and will wait about 6-9 months between major breaking changes +//! - We will support the last two minor Rust releases (MSRV, currently 1.56.1) +//! +//! While these aspirations can be at odds with fast build times and low binary +//! size, we will still strive to keep these reasonable for the flexibility you +//! get. Check out the +//! [argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for +//! CLI parsers optimized for other use cases. +//! +//! ## Example +//! +//! Run +//! ```console +//! $ cargo add clap --features derive +//! ``` +//! *(See also [feature flag reference][_features])* +//! +//! Then define your CLI in `main.rs`: +#![cfg_attr(not(feature = "derive"), doc = " ```ignore")] +#![cfg_attr(feature = "derive", doc = " ```no_run")] +#![doc = include_str!("../examples/demo.rs")] +//! ``` +//! +//! And try it out: +#![doc = include_str!("../examples/demo.md")] +//! +//! See also the derive [tutorial][_derive::_tutorial] and [reference][_derive] +//! +//! ### Related Projects +//! +//! Augment clap: +//! - [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux +//! - [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files) +//! - [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version` +//! - [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff) +//! - [clap_complete](https://crates.io/crates/clap_complete) for shell completion support +//! +//! CLI Helpers +//! - [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag) +//! - [clap-cargo](https://crates.io/crates/clap-cargo) +//! - [concolor-clap](https://crates.io/crates/concolor-clap) +//! +//! Testing +//! - [`trycmd`](https://crates.io/crates/trycmd): Bulk snapshot testing +//! - [`snapbox`](https://crates.io/crates/snapbox): Specialized snapshot testing +//! - [`assert_cmd`](https://crates.io/crates/assert_cmd) and [`assert_fs`](https://crates.io/crates/assert_fs): Customized testing +//! +//! Documentation: +//! - [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book +//! + #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")] -#![cfg_attr(feature = "derive", doc = include_str!("../README.md"))] -//! #![warn( missing_docs, missing_debug_implementations, @@ -82,9 +151,23 @@ pub use Parser as StructOpt; )] pub use ValueEnum as ArgEnum; -#[cfg(any(feature = "derive", feature = "cargo"))] +#[cfg(feature = "unstable-doc")] +pub mod _cookbook; +#[cfg(feature = "unstable-doc")] +pub mod _derive; +#[cfg(feature = "unstable-doc")] +pub mod _faq; +#[cfg(feature = "unstable-doc")] +pub mod _features; +#[cfg(feature = "unstable-doc")] +pub mod _tutorial; + #[doc(hidden)] -pub use once_cell; +pub mod __macro_refs { + #[cfg(any(feature = "derive", feature = "cargo"))] + #[doc(hidden)] + pub use once_cell; +} #[macro_use] #[allow(missing_docs)] diff --git a/vendor/clap/src/macros.rs b/vendor/clap/src/macros.rs index 0b671a37a..1f9167408 100644 --- a/vendor/clap/src/macros.rs +++ b/vendor/clap/src/macros.rs @@ -20,7 +20,7 @@ macro_rules! load_yaml { #[macro_export] #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::value_of_t`") + deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::get_one`") )] #[doc(hidden)] macro_rules! value_t { @@ -36,10 +36,7 @@ macro_rules! value_t { #[macro_export] #[cfg_attr( feature = "deprecated", - deprecated( - since = "3.0.0", - note = "Replaced with `ArgMatches::value_of_t_or_exit`" - ) + deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::get_one`") )] #[doc(hidden)] macro_rules! value_t_or_exit { @@ -55,7 +52,7 @@ macro_rules! value_t_or_exit { #[macro_export] #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::values_of_t`") + deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::get_many`") )] #[doc(hidden)] macro_rules! values_t { @@ -71,10 +68,7 @@ macro_rules! values_t { #[macro_export] #[cfg_attr( feature = "deprecated", - deprecated( - since = "3.0.0", - note = "Replaced with `ArgMatches::values_of_t_or_exit`" - ) + deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::get_many`") )] #[doc(hidden)] macro_rules! values_t_or_exit { @@ -88,7 +82,7 @@ macro_rules! values_t_or_exit { #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `ArgEnum`") + deprecated(since = "3.0.0", note = "Replaced with `ValueEnum`") )] #[doc(hidden)] #[macro_export] @@ -101,7 +95,7 @@ macro_rules! _clap_count_exprs { /// Deprecated, replaced with [`ArgEnum`][crate::ArgEnum] #[cfg_attr( feature = "deprecated", - deprecated(since = "3.0.0", note = "Replaced with `ArgEnum`") + deprecated(since = "3.0.0", note = "Replaced with `ValueEnum`") )] #[doc(hidden)] #[macro_export] @@ -256,8 +250,10 @@ macro_rules! crate_version { #[macro_export] macro_rules! crate_authors { ($sep:expr) => {{ - static CACHED: clap::once_cell::sync::Lazy = - clap::once_cell::sync::Lazy::new(|| env!("CARGO_PKG_AUTHORS").replace(':', $sep)); + static CACHED: clap::__macro_refs::once_cell::sync::Lazy = + clap::__macro_refs::once_cell::sync::Lazy::new(|| { + env!("CARGO_PKG_AUTHORS").replace(':', $sep) + }); let s: &'static str = &*CACHED; s diff --git a/vendor/clap/src/output/usage.rs b/vendor/clap/src/output/usage.rs index 7adaf58c6..6f7a2cad4 100644 --- a/vendor/clap/src/output/usage.rs +++ b/vendor/clap/src/output/usage.rs @@ -382,73 +382,64 @@ impl<'help, 'cmd> Usage<'help, 'cmd> { unrolled_reqs ); - let args_in_groups = self - .cmd - .get_groups() - .filter(|gn| required.contains(&gn.id)) - .flat_map(|g| self.cmd.unroll_args_in_group(&g.id)) - .collect::>(); - - for a in unrolled_reqs - .iter() - .chain(incls.iter()) - .filter(|name| !self.cmd.get_positionals().any(|p| &&p.id == name)) - .filter(|name| !self.cmd.get_groups().any(|g| &&g.id == name)) - .filter(|name| !args_in_groups.contains(name)) - .filter(|name| { - !(matcher.is_some() - && matcher - .as_ref() - .unwrap() - .check_explicit(name, ArgPredicate::IsPresent)) - }) - { - debug!("Usage::get_required_usage_from:iter:{:?}", a); - let arg = self.cmd.find(a).expect(INTERNAL_ERROR_MSG).to_string(); - ret_val.insert(arg); - } - let mut g_vec: Vec = vec![]; - for g in unrolled_reqs - .iter() - .filter(|n| self.cmd.get_groups().any(|g| g.id == **n)) - { - // don't print requirement for required groups that have an arg. - if let Some(m) = matcher { - let have_group_entry = self - .cmd - .unroll_args_in_group(g) - .iter() - .any(|arg| m.check_explicit(arg, ArgPredicate::IsPresent)); - if have_group_entry { - continue; + let mut required_groups_members = IndexSet::new(); + let mut required_opts = IndexSet::new(); + let mut required_groups = IndexSet::new(); + let mut required_positionals = Vec::new(); + for req in unrolled_reqs.iter().chain(incls.iter()) { + if let Some(arg) = self.cmd.find(req) { + let is_present = matcher + .map(|m| m.check_explicit(req, ArgPredicate::IsPresent)) + .unwrap_or(false); + debug!( + "Usage::get_required_usage_from:iter:{:?} arg is_present={}", + req, is_present + ); + if !is_present { + if arg.is_positional() { + if incl_last || !arg.is_last_set() { + required_positionals.push((arg.index.unwrap(), arg.to_string())); + } + } else { + required_opts.insert(arg.to_string()); + } + } + } else { + debug_assert!(self.cmd.find_group(req).is_some()); + let group_members = self.cmd.unroll_args_in_group(req); + let is_present = matcher + .map(|m| { + group_members + .iter() + .any(|arg| m.check_explicit(arg, ArgPredicate::IsPresent)) + }) + .unwrap_or(false); + debug!( + "Usage::get_required_usage_from:iter:{:?} group is_present={}", + req, is_present + ); + if !is_present { + let elem = self.cmd.format_group(req); + required_groups.insert(elem); + required_groups_members.extend( + group_members + .iter() + .flat_map(|id| self.cmd.find(id)) + .map(|arg| arg.to_string()), + ); } - } - - let elem = self.cmd.format_group(g); - if !g_vec.contains(&elem) { - g_vec.push(elem); } } - ret_val.extend(g_vec); - let mut pvec = unrolled_reqs - .iter() - .chain(incls.iter()) - .filter(|a| self.cmd.get_positionals().any(|p| &&p.id == a)) - .filter(|&pos| { - matcher.map_or(true, |m| !m.check_explicit(pos, ArgPredicate::IsPresent)) - }) - .filter_map(|pos| self.cmd.find(pos)) - .filter(|&pos| incl_last || !pos.is_last_set()) - .filter(|pos| !args_in_groups.contains(&pos.id)) - .map(|pos| (pos.index.unwrap(), pos)) - .collect::>(); - pvec.sort_by_key(|(ind, _)| *ind); // sort by index - - for (_, p) in pvec { - debug!("Usage::get_required_usage_from:push:{:?}", p.id); - if !args_in_groups.contains(&p.id) { - ret_val.insert(p.to_string()); + required_opts.retain(|arg| !required_groups_members.contains(arg)); + ret_val.extend(required_opts); + + ret_val.extend(required_groups); + + required_positionals.sort_by_key(|(ind, _)| *ind); // sort by index + for (_, p) in required_positionals { + if !required_groups_members.contains(&p) { + ret_val.insert(p); } } diff --git a/vendor/clap/src/parser/arg_matcher.rs b/vendor/clap/src/parser/arg_matcher.rs index 8d15c5799..22087e722 100644 --- a/vendor/clap/src/parser/arg_matcher.rs +++ b/vendor/clap/src/parser/arg_matcher.rs @@ -74,9 +74,7 @@ impl ArgMatcher { // a default value of `other` myprog would have an existing MatchedArg for // `--global-arg` where the value is `other` let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { - if parent_ma.check_explicit(ArgPredicate::IsPresent) - && !ma.check_explicit(ArgPredicate::IsPresent) - { + if parent_ma.source() > ma.source() { parent_ma } else { ma diff --git a/vendor/clap/src/parser/error.rs b/vendor/clap/src/parser/error.rs index bdafa9ae5..caeba4b8f 100644 --- a/vendor/clap/src/parser/error.rs +++ b/vendor/clap/src/parser/error.rs @@ -54,3 +54,14 @@ impl std::fmt::Display for MatchesError { } } } + +#[test] +fn check_auto_traits() { + static_assertions::assert_impl_all!( + MatchesError: Send, + Sync, + std::panic::RefUnwindSafe, + std::panic::UnwindSafe, + Unpin + ); +} diff --git a/vendor/clap/src/parser/matches/arg_matches.rs b/vendor/clap/src/parser/matches/arg_matches.rs index 17fa63ca6..2585c0219 100644 --- a/vendor/clap/src/parser/matches/arg_matches.rs +++ b/vendor/clap/src/parser/matches/arg_matches.rs @@ -119,6 +119,69 @@ impl ArgMatches { MatchesError::unwrap(&internal_id, self.try_get_one(id)) } + /// Gets the value of a specific [`ArgAction::Count`][crate::ArgAction::Count] flag + /// + /// # Panic + /// + /// If the argument's action is not [`ArgAction::Count`][crate::ArgAction::Count] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("flag") + /// .long("flag") + /// .action(clap::ArgAction::Count) + /// ); + /// + /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap(); + /// assert_eq!( + /// matches.get_count("flag"), + /// 2 + /// ); + /// ``` + #[track_caller] + pub fn get_count(&self, id: &str) -> u8 { + *self + .get_one::(id) + .expect("ArgAction::Count is defaulted") + } + + /// Gets the value of a specific [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] flag + /// + /// # Panic + /// + /// If the argument's action is not [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("flag") + /// .long("flag") + /// .action(clap::ArgAction::SetTrue) + /// ); + /// + /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap(); + /// assert!(matches.contains_id("flag")); + /// assert_eq!( + /// matches.get_flag("flag"), + /// true + /// ); + /// ``` + #[track_caller] + pub fn get_flag(&self, id: &str) -> bool { + *self + .get_one::(id) + .expect("ArgAction::SetTrue / ArgAction::SetFalse is defaulted") + } + /// Iterate over values of a specific option or positional argument. /// /// i.e. an argument that takes multiple values at runtime. @@ -604,13 +667,13 @@ impl ArgMatches { value.and_then(MatchedArg::source) } - /// Deprecated, replaced with [`ArgAction::Count`][crate::ArgAction] or - /// [`ArgMatches::get_many`]`.len()`. + /// Deprecated, replaced with [`ArgAction::Count`][crate::ArgAction], + /// [`ArgMatches::get_many`]`.len()`, or [`ArgMatches::value_source`]. #[cfg_attr( feature = "deprecated", deprecated( since = "3.2.0", - note = "Replaced with either `ArgAction::Count` or `ArgMatches::get_many(...).len()`" + note = "Replaced with either `ArgAction::Count`, `ArgMatches::get_many(...).len()`, or `ArgMatches::value_source`" ) )] #[cfg_attr(debug_assertions, track_caller)] @@ -1741,6 +1804,11 @@ fn unwrap_os_string_arg<'v>(id: &Id, value: &'v AnyValue) -> &'v OsStr { mod tests { use super::*; + #[test] + fn check_auto_traits() { + static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin); + } + #[test] fn test_default_values() { #![allow(deprecated)] diff --git a/vendor/clap/src/parser/parser.rs b/vendor/clap/src/parser/parser.rs index fc95dad22..ad2bc6e9c 100644 --- a/vendor/clap/src/parser/parser.rs +++ b/vendor/clap/src/parser/parser.rs @@ -98,77 +98,6 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { arg_os.to_value_os().as_raw_bytes() ); - // Correct pos_counter. - pos_counter = { - let is_second_to_last = pos_counter + 1 == positional_count; - - // The last positional argument, or second to last positional - // argument may be set to .multiple_values(true) or `.multiple_occurrences(true)` - let low_index_mults = is_second_to_last - && self - .cmd - .get_positionals() - .any(|a| a.is_multiple() && (positional_count != a.index.unwrap_or(0))) - && self - .cmd - .get_positionals() - .last() - .map_or(false, |p_name| !p_name.is_last_set()); - - let missing_pos = self.cmd.is_allow_missing_positional_set() - && is_second_to_last - && !trailing_values; - - debug!( - "Parser::get_matches_with: Positional counter...{}", - pos_counter - ); - debug!( - "Parser::get_matches_with: Low index multiples...{:?}", - low_index_mults - ); - - if low_index_mults || missing_pos { - let skip_current = if let Some(n) = raw_args.peek(&args_cursor) { - if let Some(arg) = self - .cmd - .get_positionals() - .find(|a| a.index == Some(pos_counter)) - { - // If next value looks like a new_arg or it's a - // subcommand, skip positional argument under current - // pos_counter(which means current value cannot be a - // positional argument with a value next to it), assume - // current value matches the next arg. - self.is_new_arg(&n, arg) - || self - .possible_subcommand(n.to_value(), valid_arg_found) - .is_some() - } else { - true - } - } else { - true - }; - - if skip_current { - debug!("Parser::get_matches_with: Bumping the positional counter..."); - pos_counter + 1 - } else { - pos_counter - } - } else if trailing_values - && (self.cmd.is_allow_missing_positional_set() || contains_last) - { - // Came to -- and one positional has .last(true) set, so we go immediately - // to the last (highest index) positional - debug!("Parser::get_matches_with: .last(true) and --, setting last pos"); - positional_count - } else { - pos_counter - } - }; - // Has the user already passed '--'? Meaning only positional args follow if !trailing_values { if self.cmd.is_subcommand_precedence_over_arg_set() @@ -376,6 +305,77 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { } } + // Correct pos_counter. + pos_counter = { + let is_second_to_last = pos_counter + 1 == positional_count; + + // The last positional argument, or second to last positional + // argument may be set to .multiple_values(true) or `.multiple_occurrences(true)` + let low_index_mults = is_second_to_last + && self + .cmd + .get_positionals() + .any(|a| a.is_multiple() && (positional_count != a.index.unwrap_or(0))) + && self + .cmd + .get_positionals() + .last() + .map_or(false, |p_name| !p_name.is_last_set()); + + let missing_pos = self.cmd.is_allow_missing_positional_set() + && is_second_to_last + && !trailing_values; + + debug!( + "Parser::get_matches_with: Positional counter...{}", + pos_counter + ); + debug!( + "Parser::get_matches_with: Low index multiples...{:?}", + low_index_mults + ); + + if low_index_mults || missing_pos { + let skip_current = if let Some(n) = raw_args.peek(&args_cursor) { + if let Some(arg) = self + .cmd + .get_positionals() + .find(|a| a.index == Some(pos_counter)) + { + // If next value looks like a new_arg or it's a + // subcommand, skip positional argument under current + // pos_counter(which means current value cannot be a + // positional argument with a value next to it), assume + // current value matches the next arg. + self.is_new_arg(&n, arg) + || self + .possible_subcommand(n.to_value(), valid_arg_found) + .is_some() + } else { + true + } + } else { + true + }; + + if skip_current { + debug!("Parser::get_matches_with: Bumping the positional counter..."); + pos_counter + 1 + } else { + pos_counter + } + } else if trailing_values + && (self.cmd.is_allow_missing_positional_set() || contains_last) + { + // Came to -- and one positional has .last(true) set, so we go immediately + // to the last (highest index) positional + debug!("Parser::get_matches_with: .last(true) and --, setting last pos"); + positional_count + } else { + pos_counter + } + }; + if let Some(arg) = self.cmd.get_keymap().get(&pos_counter) { if arg.is_last_set() && !trailing_values { let _ = self.resolve_pending(matcher); @@ -738,8 +738,10 @@ impl<'help, 'cmd> Parser<'help, 'cmd> { } }; if long_arg.is_empty() { - debug_assert!(long_value.is_none(), "{:?}", long_value); - return Ok(ParseResult::NoArg); + debug_assert!( + long_value.is_some(), + "`--` should be filtered out before this point" + ); } let arg = if let Some(arg) = self.cmd.get_keymap().get(long_arg) { diff --git a/vendor/clap_derive/.cargo-checksum.json b/vendor/clap_derive/.cargo-checksum.json index 8d3303f99..1dfa35a62 100644 --- a/vendor/clap_derive/.cargo-checksum.json +++ b/vendor/clap_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"29d214d0c807739f6d147a1a472dfab5d929b4dd31623f670df28a713be107e8","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"d99fca4ba5976a41b150cd7f5c17100e0d275b9bf48b51a0d964115dc81e20b9","src/attrs.rs":"dd4288ac38aeb184bbffade71af48706034f10d311068af2917c0f96d813698a","src/derives/args.rs":"27a13d33f24f7f7668c82fa653978e909514bd39e808c7996fddb0d3a3c0e570","src/derives/into_app.rs":"02c36d403ad35e3d49de6042cacecf2a724561b5e3948b5aec4b45646e031877","src/derives/mod.rs":"ff7947fddee4b3d8365e29459a02458382e13df022aee822e09bce1ac255d3bb","src/derives/parser.rs":"9ca609e6e5bfb303e22b4ecb8aca9035571179920b0df91031e9f987559252e0","src/derives/subcommand.rs":"0513c48013c2bd9f450ffc7bfcbf84b3a3290e37ff571dd070798356c2b291ac","src/derives/value_enum.rs":"27b87ccb6829925f6ffa631109217bffd81b74f61519841678bd6d8c5cfcbe40","src/dummies.rs":"02f111bbd84b8f0525faeb9189c59cb2fd2df05ae6c7b014735c82feac5ff23f","src/lib.rs":"e4be47e8db06a6555a2a4cd1802d17c16a3b51ae0ec291b3ec75ef2b6517eb0e","src/parse.rs":"f0d720da5477755bdce02fcd248a57efe74b2fbbc5e07c5dc17d9bf78b017958","src/utils/doc_comments.rs":"386859b274fd1e298aeaeafd2b20764db0957cbb4e6c9e8bab52a506a0b8ecda","src/utils/mod.rs":"ee28526587d2d80d5dba162f28191f44f6a0c296d0e52225eb74b90534d49b25","src/utils/spanned.rs":"e93600124c54985533f74fe23f096f4ada94b310eff97a16f0ce40fb0f690a3b","src/utils/ty.rs":"0a9b8c5dabfa28388b60423f4b6075a275b347258ac35301997cb0d7f763607f"},"package":"c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9"} \ No newline at end of file +{"files":{"Cargo.toml":"eaf10a4c685b527f604ea9f84fbe7095e15fe4424225c57481d0555a89dfb054","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"0d687e1f07b58fe68bda74668ff6326125e5e5efa184cce755cd84ac535b7058","README.md":"4ec07b9c59a2ddcedcdc9d21d51c147b18157794b03ff2ea5ae57f2b5236943d","src/attrs.rs":"1c95a75fd377d19587f429d3f51544ac0ca96f868cce4ffe12d1163f7465fa73","src/derives/args.rs":"27a13d33f24f7f7668c82fa653978e909514bd39e808c7996fddb0d3a3c0e570","src/derives/into_app.rs":"02c36d403ad35e3d49de6042cacecf2a724561b5e3948b5aec4b45646e031877","src/derives/mod.rs":"ff7947fddee4b3d8365e29459a02458382e13df022aee822e09bce1ac255d3bb","src/derives/parser.rs":"9ca609e6e5bfb303e22b4ecb8aca9035571179920b0df91031e9f987559252e0","src/derives/subcommand.rs":"0513c48013c2bd9f450ffc7bfcbf84b3a3290e37ff571dd070798356c2b291ac","src/derives/value_enum.rs":"4d0958d3a767c82f2366d8fda20367c5aa033af616d09ef581e8abdb2e029a70","src/dummies.rs":"02f111bbd84b8f0525faeb9189c59cb2fd2df05ae6c7b014735c82feac5ff23f","src/lib.rs":"e4be47e8db06a6555a2a4cd1802d17c16a3b51ae0ec291b3ec75ef2b6517eb0e","src/parse.rs":"ceaac282cabccfac5bcf56ce02095c9acbf00dbfdd3c3009fa58e87bdde46218","src/utils/doc_comments.rs":"386859b274fd1e298aeaeafd2b20764db0957cbb4e6c9e8bab52a506a0b8ecda","src/utils/mod.rs":"ee28526587d2d80d5dba162f28191f44f6a0c296d0e52225eb74b90534d49b25","src/utils/spanned.rs":"e93600124c54985533f74fe23f096f4ada94b310eff97a16f0ce40fb0f690a3b","src/utils/ty.rs":"0a9b8c5dabfa28388b60423f4b6075a275b347258ac35301997cb0d7f763607f"},"package":"ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"} \ No newline at end of file diff --git a/vendor/clap_derive/Cargo.toml b/vendor/clap_derive/Cargo.toml index 49e3fd963..f74476e68 100644 --- a/vendor/clap_derive/Cargo.toml +++ b/vendor/clap_derive/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56.0" +rust-version = "1.56.1" name = "clap_derive" -version = "3.2.5" +version = "3.2.18" include = [ "build.rs", "src/**/*", @@ -24,7 +24,6 @@ include = [ "examples/**/*", ] description = "Parse command line argument by defining a struct, derive crate." -documentation = "https://docs.rs/clap_derive" readme = "README.md" keywords = [ "clap", diff --git a/vendor/clap_derive/LICENSE-MIT b/vendor/clap_derive/LICENSE-MIT index 5acedf041..7b05b8453 100644 --- a/vendor/clap_derive/LICENSE-MIT +++ b/vendor/clap_derive/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2016 Kevin B. Knapp +Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/clap_derive/README.md b/vendor/clap_derive/README.md index 1acadb355..17f649eda 100644 --- a/vendor/clap_derive/README.md +++ b/vendor/clap_derive/README.md @@ -3,8 +3,8 @@ Macro implementation for clap's derives. [docs.rs](https://docs.rs/clap) -- [Derive Tutorial](https://github.com/clap-rs/clap/blob/v3.2.5/examples/tutorial_derive/README.md) -- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.2.5/examples/derive_ref/README.md) +- [Derive Tutorial](https://github.com/clap-rs/clap/blob/v3.2.18/examples/tutorial_derive/README.md) +- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.2.18/examples/derive_ref/README.md) ## License diff --git a/vendor/clap_derive/src/attrs.rs b/vendor/clap_derive/src/attrs.rs index 3c685fbe8..2c5b47d95 100644 --- a/vendor/clap_derive/src/attrs.rs +++ b/vendor/clap_derive/src/attrs.rs @@ -450,7 +450,7 @@ impl Attrs { } fn push_method(&mut self, name: Ident, arg: impl ToTokens) { - if name == "name" { + if name == "name" || name == "id" { self.name = Name::Assigned(quote!(#arg)); } else if name == "value_parser" { self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg)))); @@ -552,7 +552,7 @@ impl Attrs { }) } else { quote_spanned!(ident.span()=> { - static DEFAULT_VALUE: clap::once_cell::sync::Lazy = clap::once_cell::sync::Lazy::new(|| { + static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy = clap::__macro_refs::once_cell::sync::Lazy::new(|| { let val: #ty = #val; ::std::string::ToString::to_string(&val) }); @@ -564,6 +564,81 @@ impl Attrs { self.methods.push(Method::new(raw_ident, val)); } + DefaultValuesT(ident, expr) => { + let ty = if let Some(ty) = self.ty.as_ref() { + ty + } else { + abort!( + ident, + "#[clap(default_values_t)] (without an argument) can be used \ + only on field level"; + + note = "see \ + https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes") + }; + + let container_type = Ty::from_syn_ty(ty); + if *container_type != Ty::Vec { + abort!( + ident, + "#[clap(default_values_t)] can be used only on Vec types"; + + note = "see \ + https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes") + } + let inner_type = inner_type(ty); + + // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and + // `Vec<#inner_type>`. + let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) { + quote_spanned!(ident.span()=> { + { + fn iter_to_vals(iterable: impl IntoIterator) -> Vec<&'static str> + where + T: ::std::borrow::Borrow<#inner_type> + { + iterable + .into_iter() + .map(|val| { + clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name() + }) + .collect() + + } + + static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + iter_to_vals(#expr) + }); + &*DEFAULT_VALUES.as_slice() + } + }) + } else { + quote_spanned!(ident.span()=> { + { + fn iter_to_vals(iterable: impl IntoIterator) -> Vec + where + T: ::std::borrow::Borrow<#inner_type> + { + iterable.into_iter().map(|val| val.borrow().to_string()).collect() + + } + + static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + iter_to_vals(#expr) + }); + + static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect() + }); + &*DEFAULT_VALUES.as_slice() + } + }) + }; + + self.methods + .push(Method::new(Ident::new("default_values", ident.span()), val)); + } + DefaultValueOsT(ident, expr) => { let ty = if let Some(ty) = self.ty.as_ref() { ty @@ -592,7 +667,7 @@ impl Attrs { }) } else { quote_spanned!(ident.span()=> { - static DEFAULT_VALUE: clap::once_cell::sync::Lazy<::std::ffi::OsString> = clap::once_cell::sync::Lazy::new(|| { + static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { let val: #ty = #val; ::std::ffi::OsString::from(val) }); @@ -604,6 +679,84 @@ impl Attrs { self.methods.push(Method::new(raw_ident, val)); } + DefaultValuesOsT(ident, expr) => { + let ty = if let Some(ty) = self.ty.as_ref() { + ty + } else { + abort!( + ident, + "#[clap(default_values_os_t)] (without an argument) can be used \ + only on field level"; + + note = "see \ + https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes") + }; + + let container_type = Ty::from_syn_ty(ty); + if *container_type != Ty::Vec { + abort!( + ident, + "#[clap(default_values_os_t)] can be used only on Vec types"; + + note = "see \ + https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes") + } + let inner_type = inner_type(ty); + + // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and + // `Vec<#inner_type>`. + let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) { + quote_spanned!(ident.span()=> { + { + fn iter_to_vals(iterable: impl IntoIterator) -> Vec<&'static ::std::ffi::OsStr> + where + T: ::std::borrow::Borrow<#inner_type> + { + iterable + .into_iter() + .map(|val| { + clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name() + }) + .map(::std::ffi::OsStr::new) + .collect() + + } + + static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + iter_to_vals(#expr) + }); + &*DEFAULT_VALUES.as_slice() + } + }) + } else { + quote_spanned!(ident.span()=> { + { + fn iter_to_vals(iterable: impl IntoIterator) -> Vec<::std::ffi::OsString> + where + T: ::std::borrow::Borrow<#inner_type> + { + iterable.into_iter().map(|val| val.borrow().into()).collect() + + } + + static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + iter_to_vals(#expr) + }); + + static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy> = clap::__macro_refs::once_cell::sync::Lazy::new(|| { + DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect() + }); + &*DEFAULT_VALUES.as_slice() + } + }) + }; + + self.methods.push(Method::new( + Ident::new("default_values_os", ident.span()), + val, + )); + } + NextDisplayOrder(ident, expr) => { self.next_display_order = Some(Method::new(ident, quote!(#expr))); } diff --git a/vendor/clap_derive/src/derives/value_enum.rs b/vendor/clap_derive/src/derives/value_enum.rs index b18b665c4..06d514f0e 100644 --- a/vendor/clap_derive/src/derives/value_enum.rs +++ b/vendor/clap_derive/src/derives/value_enum.rs @@ -84,7 +84,7 @@ fn lits( None } else { if !matches!(variant.fields, Fields::Unit) { - abort!(variant.span(), "`#[derive(ValueEnum)]` only supports non-unit variants, unless they are skipped"); + abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped"); } let fields = attrs.field_methods(false); let name = attrs.cased_name(); diff --git a/vendor/clap_derive/src/parse.rs b/vendor/clap_derive/src/parse.rs index 253736cfd..7d7e19cdc 100644 --- a/vendor/clap_derive/src/parse.rs +++ b/vendor/clap_derive/src/parse.rs @@ -53,7 +53,9 @@ pub enum ClapAttr { // ident = arbitrary_expr NameExpr(Ident, Expr), DefaultValueT(Ident, Option), + DefaultValuesT(Ident, Expr), DefaultValueOsT(Ident, Option), + DefaultValuesOsT(Ident, Expr), NextDisplayOrder(Ident, Expr), NextHelpHeading(Ident, Expr), HelpHeading(Ident, Expr), @@ -122,7 +124,9 @@ impl Parse for ClapAttr { Ok(expr) => match &*name_str { "skip" => Ok(Skip(name, Some(expr))), "default_value_t" => Ok(DefaultValueT(name, Some(expr))), + "default_values_t" => Ok(DefaultValuesT(name, expr)), "default_value_os_t" => Ok(DefaultValueOsT(name, Some(expr))), + "default_values_os_t" => Ok(DefaultValuesOsT(name, expr)), "next_display_order" => Ok(NextDisplayOrder(name, expr)), "next_help_heading" => Ok(NextHelpHeading(name, expr)), "help_heading" => Ok(HelpHeading(name, expr)), diff --git a/vendor/compiler_builtins/.cargo-checksum.json b/vendor/compiler_builtins/.cargo-checksum.json index 9324f092f..3310b9b76 100644 --- a/vendor/compiler_builtins/.cargo-checksum.json +++ b/vendor/compiler_builtins/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"b369bba03aca1dd529671fb54000fd8dfc0d4d5b5cfe1afe71294155c974bc34","Cargo.toml":"1f727cb37da8b846367a12e034c01aca729f745a695383dd596b05b7f86ba970","README.md":"5eb36fbab30693dbbe9f0de54749c95bd06fd6e42013b5b9eff3c062b9fdd34f","build.rs":"991919d9ab1eca85e87a85acafcb86d4880f1afe9fe35d6bd87039dcb1fa9aa7","examples/intrinsics.rs":"a7aa69c17af3aa8f6edff32c214e80827d3cbe3aea386a2be42244444752d253","libm/src/math/acos.rs":"fb066ba84aba1372d706425ec14f35ff8d971756d15eeebd22ecf42a716493bb","libm/src/math/acosf.rs":"a112b82309bba1d35c4e3d6ad4d6c21ef305343d9ab601ddf4bc61d43bc9f1af","libm/src/math/acosh.rs":"56dac8538e4350cd7cf001327c89f087b68abb2e6aaad58edba8a094b09f6b0f","libm/src/math/acoshf.rs":"df5b0c4d8e37e64cf5ff2d8328b28bc35c78e84060ff769e64523ea9ff9065c1","libm/src/math/asin.rs":"095a1e98996daff45df0b154ca0ec35bbf31db964ee9fdda0207308cb20df441","libm/src/math/asinf.rs":"49cccb4db2881982643a4a7d5453f4f8daf527711bbb67313607a3c178856d61","libm/src/math/asinh.rs":"e8fc94031015fddf35e9c26b94da9f6431ee17c81cd7bd37da8ffc98f7e0b32c","libm/src/math/asinhf.rs":"8a0b8933a98a17617a66fef4c7b89eba645fdf05302000babf4a5a5f45328430","libm/src/math/atan.rs":"d4fe46e1c5739dd09997869dcfbc3c85f03c534af52e700d6c6bcf9c3fedda07","libm/src/math/atan2.rs":"2623bc8ca707d13a7092ce49adf68e9cbf4452ad1bf4a861dc40ca858606a747","libm/src/math/atan2f.rs":"dd01943e0e1f1955912e5c3ffc9467529cf64bd02ac0a6ad5ab31dbe6657f05d","libm/src/math/atanf.rs":"e41b41569474a59c970ede3538e00bda4072cf4d90040017101cc79d7dc28caa","libm/src/math/atanh.rs":"5934dbd6b7395ca4f103ace7598da723a9270e1cf6b47e7f786debe4bb3651ff","libm/src/math/atanhf.rs":"8ba4711dda19ef2dc33622be65c1483902868083543198c6bbd040d4026293de","libm/src/math/cbrt.rs":"f2c45612d2eecd93cfcdd9ebf824c754fc8f8dfd6d16862c0b9c4ccea78c2a0f","libm/src/math/cbrtf.rs":"ad0b483854aa9f17a44d36c049bf0e8ebab34c27e90b787c05f45cc230ec7d19","libm/src/math/ceil.rs":"57ba5b6e207a0ccbd34190d1aa544389ca12126be23821dfb5746497f620ce03","libm/src/math/ceilf.rs":"c922a0475a599b9ea5473e615f74700b99707cebd6927f24ea59cb2a3cb3bbc3","libm/src/math/copysign.rs":"d80c880efaf0cdf2ce0a4d4f5a68dd6c36c88d46fa997ec8ac8604bfdb26fa33","libm/src/math/copysignf.rs":"1547116071e68a42b1605eb2fc722db6466a34517dc96b92de1f29a274c3d8e3","libm/src/math/cos.rs":"74babdc13ede78e400c5ca1854c3e22d2e08cbdc5618aefa5bba6f9303ef65b6","libm/src/math/cosf.rs":"09c40f93c445b741e22477ceedf163ca33b6a47f973f7c9876cfba2692edb29c","libm/src/math/cosh.rs":"0d0a7cef18577f321996b8b87561963139f754ad7f2ea0a3b3883811f3f0693a","libm/src/math/coshf.rs":"be8ca8739e4cf1978425b349f941cb4838bba8c10cb559c7940b9fd4fdde21ad","libm/src/math/erf.rs":"9c55fc6756ba816996f0b585e07ccfa4cd87575ad525cd30c4a968b30acffda3","libm/src/math/erff.rs":"cb020e8bada9a54573a11fe3271750d73f14fed3092a881a9ceaf98fe32fd5a6","libm/src/math/exp.rs":"ca7405ad0d1993fffcf9aae96f9256307bed3c4916545aaebd1cf1d2df1807fa","libm/src/math/exp10.rs":"2deb037f88feac87a0e924b69dd496f0dd3b5d35f2a58e09d4c5166b207e517b","libm/src/math/exp10f.rs":"6979464dfe3f4f2da1f9afc909646499c4bfaef15e10a039384750e2f1586fea","libm/src/math/exp2.rs":"94a9304a2ce3bc81f6d2aefd3cde6faa30f13260d46cb13692863cdea1c9a3a1","libm/src/math/exp2f.rs":"785f2630accd35118ec07bf60273e219ed91a215b956b1552eeea5bc2a708cc8","libm/src/math/expf.rs":"ec14c18f891a9e37735ec39e6fc2e9bf674a2c2e083f22e2533b481177359c98","libm/src/math/expm1.rs":"124069f456c8ad331f265c7509d9e223b2a300e461bbfd3d6adfdcdd2ee5b8ac","libm/src/math/expm1f.rs":"18e2116d31ea8410051cc709b9d04b754b0e3ba6758ee1bf0b48749f4999b840","libm/src/math/expo2.rs":"4f4f9fecfccb43f30c2784aa7c0bb656754a52b8ab431f7d1b551c673ab133f1","libm/src/math/fabs.rs":"e6c7db39f98508098cdf64ac0c2f53866c466149a7490afb9fe22b44c4dd81b3","libm/src/math/fabsf.rs":"83a1f5f4d9ca899ba2b701d7332e18b40258b83e111db4c5d8fab2cc1be58aa3","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"8730d45aa4c591f91dccdcc1ce533fa23e9c6df0c38defb9c57f749cb25e1cd0","libm/src/math/floor.rs":"5050804cae173af6775c0678d6c1aafb5ca2b744bc8a2f50d9d03b95dcee1fb0","libm/src/math/floorf.rs":"c903e0c57bc60a888c513eb7a873a87a4759ba68fc791b6b931652f8ee74cc03","libm/src/math/fma.rs":"d88e01c2c2d11333dd49b61166caa036ff5f08f3a8c5973b9e3c9574bf2eb675","libm/src/math/fmaf.rs":"3e0f5727e56f31218f674b9b8975d7e67b3a24a097f06a2a3eca9723cd786213","libm/src/math/fmax.rs":"f6c8e96a8b1a170648d2fa3513e7b6b459085d708c839869f82e305fe58fac37","libm/src/math/fmaxf.rs":"dff0025433232e8a5ec7bd54d847ccf596d762ea4e35f5c54fbaac9404d732fd","libm/src/math/fmin.rs":"95b6cb66ca0e0e22276f0bf88dbe8fb69796a69a196a7491bd4802efbcf2e298","libm/src/math/fminf.rs":"304bc839b15ea3d84e68d2af9f40524ec120d30a36a667b22fcb98a6c258f4c7","libm/src/math/fmod.rs":"a1c0550fc7df8164733d914e222ff0966a2ab886d6e75a1098f24fe0283ae227","libm/src/math/fmodf.rs":"ee51ed092c0eeb8195f35735ff725cfd46612e0d689a7c483538bd92fbe61828","libm/src/math/frexp.rs":"28af70026922a8ab979744c7ad4d8faba6079c4743b7eeb6d14c983a982fbbcc","libm/src/math/frexpf.rs":"2e2593ae8002ba420809ebfaf737ef001cdc912354be3d978a8c0cb930350d4d","libm/src/math/hypot.rs":"841131c4a0cea75bc8a86e29f3f6d0815a61fc99731c9984651ce83d3050d218","libm/src/math/hypotf.rs":"5f317323edc2eb699580fe54b074b7e570a7734d51a0a149c0b49b54470a836c","libm/src/math/ilogb.rs":"813413bf6266d4fc40db9c5921af3cef4f892ba93e8f6d9efe62a449d1234532","libm/src/math/ilogbf.rs":"dec462780f46682e16cfaa733238bed3b692729e951f53a44726100b6c73a716","libm/src/math/j0.rs":"9572b6396c489927d332d0e717920e61ec0618e5e9c31f7eeeec70f5e4abab06","libm/src/math/j0f.rs":"802c8254bded9b3afb6eea8b9af240038a5a4a5d811396729f69ca509e3e7d87","libm/src/math/j1.rs":"97b1af1611fa3d110c2b349ee8e4176100132ea1391b619086b47ac063b81803","libm/src/math/j1f.rs":"9c9b128752e8ea2e7d81b637ba84907ab54a545e7602c49167b313743927930b","libm/src/math/jn.rs":"847d122334e5707ad9627146cddccc082a1f2f5bcd3e5ef54399013a7007ce88","libm/src/math/jnf.rs":"4045076f7d1a1b89882ed60d4dd60a4cbbc66b85cfb90491378c8015effcc476","libm/src/math/k_cos.rs":"f34a69e44d6b8901b03b578a75972f438ab20a7b98a0903fc1903d6fde3899be","libm/src/math/k_cosf.rs":"8f7117ff21cebf8e890a5bcfd7ea858a94172f4172b79a66d53824c2cb0888b1","libm/src/math/k_expo2.rs":"eb4ca9e6a525b7ea6da868c3cb136896682cc46f8396ba2a2ebc3ae9e9ba54b0","libm/src/math/k_expo2f.rs":"d51ad5df61cb5d1258bdb90c52bfed4572bb446a9337de9c04411ed9454ae0cb","libm/src/math/k_sin.rs":"14b2aba6ca07150c92768b5a72acaf5cde6a11d6619e14896512a7ba242e289a","libm/src/math/k_sinf.rs":"2775fcc710807164e6f37a4f8da3c8143cd5f16e19ce7c31c5591522151d7a96","libm/src/math/k_tan.rs":"a72beae4ccd9631eeeb61d6365bbeecae81c8411f3120a999c515cca0d5ea5c5","libm/src/math/k_tanf.rs":"6a794be56fa4b2f60452b9bab19af01c388f174560acbf829a351378ea39495d","libm/src/math/ldexp.rs":"b647f0096e80e4d926d8dd18d294c892ee2cb1778effe2c5e1b2664ae5cb1a4e","libm/src/math/ldexpf.rs":"98743fad2cd97a7be496f40ba3157ac1438fce0d0c25d5ab90c3b8c71c3fd0ed","libm/src/math/lgamma.rs":"498552658cc8106d7754f85ae8dbc3306ac2f0a9f7eb5a796be70c5beac92c41","libm/src/math/lgamma_r.rs":"77fb6442aeb5343926d8965e1549dde3e2cc4fd09555de6b56506001d956c344","libm/src/math/lgammaf.rs":"457105f53a4c8717e8f5a117d261dcf94e222e83981337fe23602abe883fe3f7","libm/src/math/lgammaf_r.rs":"44de75babbdd53c4a5879cd6f426e7311db82669def39df5f63914d67d6cc1b1","libm/src/math/log.rs":"b5e0c5f30d9e94351488732801be3107c12b854c3f95ad37e256dd88eeca408f","libm/src/math/log10.rs":"3425ff8be001fd1646ba15e254eb6ef4bdc6ccaf0cbee27ddf1fa84e04178b90","libm/src/math/log10f.rs":"fee4f71879bc4c99259e68c0c641364901629fb29a8ebddfcc0d090102cceddd","libm/src/math/log1p.rs":"9cf400852f165e6be19b97036ae9521fb9ca857d0a9a91c117d9123221622185","libm/src/math/log1pf.rs":"2716e6d2afa271996b7c8f47fd9e4952c88f4c1fd8c07c3e8ce8c62794bf71d8","libm/src/math/log2.rs":"dbbbfbaaa8aa6a4dbefea554ea3983090a9691228b011910c751f6adca912c40","libm/src/math/log2f.rs":"92a90350d8edce21c31c285c3e620fca7c62a2366008921715945c2c73b5b79f","libm/src/math/logf.rs":"845342cffc34d3db1f5ec12d8e5b773cd5a79056e28662fcb9bcd80207596f50","libm/src/math/mod.rs":"9de65aedb36910356bc47d25b1468b40ab63faf7e319e599e478a239681bdf9c","libm/src/math/modf.rs":"d012ed5a708ef52b6d1313c22a46cadaf5764dde1220816e3df2f03a0fcc60ae","libm/src/math/modff.rs":"f8f1e4c27a85d2cdb3c8e74439d59ef64aa543b948f22c23227d02d8388d61c2","libm/src/math/nextafter.rs":"3282e7eef214a32736fb6928d490198ad394b26b402b45495115b104839eebfe","libm/src/math/nextafterf.rs":"0937dc8a8155c19842c12181e741cec1f7df1f7a00cee81fcb2475e2842761b7","libm/src/math/pow.rs":"17c38297c5bf99accd915f292b777f8716ecf328916297c8bb9dfde6fd8ce522","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"3e53234977daf61c89c29c940791714aad2f676a6f38188c7d17543a2aa8806f","libm/src/math/rem_pio2_large.rs":"21762d08d72dc6f2e313123a7311683000974a09b8fcae50994d9c39239721b1","libm/src/math/rem_pio2f.rs":"07fb48f6d5cbadfd32ce4124b2b74af98b8391a2a6f36ce2a7d32e4500cb65ac","libm/src/math/remainder.rs":"63865f4370853c476b45bb27a5c54a4072146aa4a626835ae5263871a4e7e5dc","libm/src/math/remainderf.rs":"dd3fa432dbda8f2135428198be7bd69c57f8d13df3f365b12f52bf6a82352ac4","libm/src/math/remquo.rs":"3cc0bf55069f165c4843f2c358b3a27279c01e8cdd99f9057a3f7f31f45408f2","libm/src/math/remquof.rs":"cc749e18ecb7e766b8b8eeabdbf89ac99087d3d587e71e30f690676a3d2c1f9b","libm/src/math/round.rs":"f10797ef15dd34a74e912ba8621d60bc0200c87b94308c9de3cc88d7aec4feb4","libm/src/math/roundf.rs":"27e37cfcf82373709e7debf9c0c18f7ed00ae0f5d97a214c388041f7a6996d35","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"bb483a2138ca779e03a191222636f0c60fd75a77a2a12f263bda4b6aa9136317","libm/src/math/sincos.rs":"55b7446984db26bc118eb3d9b01f4fd2594de06558e0f9b6dc936a57888ca9be","libm/src/math/sincosf.rs":"f7b18383b242dad59e6033240d0e4a0fd08a2633e5048eff27532085f1c67f87","libm/src/math/sinf.rs":"dcddac1d56b084cbb8d0e019433c9c5fe2201d9b257a7dcf2f85c9a8f14b79cf","libm/src/math/sinh.rs":"d8ee4c7af883a526f36c1a6da13bb81fba9181b477e2f2538161a2bee97edc35","libm/src/math/sinhf.rs":"d06eb030ba9dbf7094df127262bfe99f149b4db49fa8ab8c15499660f1e46b26","libm/src/math/sqrt.rs":"824570a631c2542ccee68b65e3eb08fe79c037a29bbaaf54da5367e7b236124a","libm/src/math/sqrtf.rs":"4cf418d74f7751d522a642a9a8d6b86ee3472c6aaef44f0eb1bc26f4d8a90985","libm/src/math/tan.rs":"930ecedaadc60f704c2dfa4e15186f59713c1ba7d948529d215223b424827db5","libm/src/math/tanf.rs":"894156a3b107aee08461eb4e7e412fc049aa237d176ae705c6e3e2d7060d94e3","libm/src/math/tanh.rs":"f1f08eb98ed959a17370a7aaf0177be36e3764543424e78feb033ed3f5e8ec98","libm/src/math/tanhf.rs":"74027b0c672a4e64bdef6d7a3069b90caec50e1e7dbb2c12d2828f310502f41e","libm/src/math/tgamma.rs":"a6aabb8365410af6611f19f58694ccb74e82bb9ba9e1cdec7e1af787cfa44815","libm/src/math/tgammaf.rs":"c95bd69957387533853532164f7e2251d2b04f5e775406b9e647226ae2bdd5ad","libm/src/math/trunc.rs":"642264897cc1505e720c8cf313be81aa9fd53aae866644a2e988d01dbc77fd8a","libm/src/math/truncf.rs":"dee3607baf1af0f01deae46e429e097234c50b268eaefebbe716f19f38597900","src/arm.rs":"8ccf47608cc7862d8d834ca292d0d3d97faaab6cc6f20ba59ccf2987ff0f3f77","src/arm_linux.rs":"87136556091817b2bded52c3ece101123aae84ff13ccaf13a196826b2e3fc297","src/float/add.rs":"3ec32ceaf470a89777b54f9cde61832fdadeade0f4894f268a949e968520bc57","src/float/cmp.rs":"79b1fdc8d5f943c4ad5ea4ad32623b18f63e17ac3852fbc64a4942228007e1fc","src/float/conv.rs":"55138604371e00ef14167894159156b68f939039b0e5b2b1f3db61456e3d3870","src/float/div.rs":"bc808a5372d041b96aa603ac814165e1e7dbd690e4ab9b026d9465c1cbc2c583","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"48d76632575789a6ecf99213b1ed38c21c86ad5a5c3fa33ccb31f77829271b79","src/float/mul.rs":"0d0c1f0c28c149ecadeafd459d3c4c9327e4cfcae2cba479957bb8010ef51a01","src/float/pow.rs":"2ada190738731eb6f24104f8fb8c4d6f03cfb16451536dbee32f2b33db0c4b19","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/float/trunc.rs":"d21d2a2f9a1918b4bbb594691e397972a7c04b74b2acf04016c55693abf6d24b","src/int/addsub.rs":"7ec45ce1ba15b56a5b7129d3e5722c4db764c6545306d3fa9090983bcabd6f17","src/int/leading_zeros.rs":"ccf5e9d098c80034dcf6e38437c9a2eb670fa8043558bbfb574f2293164729a6","src/int/mod.rs":"bab1b77535ceebdebb89fd4e59e7105f8c45347bb638351a626615b24544a0b1","src/int/mul.rs":"bb48d8fd42d8f9f5fe9271d8d0f7a92dbae320bf4346e19d1071eb2093cb8ed9","src/int/sdiv.rs":"ace4cb0ec388a38834e01cab2c5bc87182d31588dfc0b1ae117c11ed0c4781cf","src/int/shift.rs":"3967c28a8d61279546e91958d64745fec63f15aee9175eb0602cc6353830da6c","src/int/specialized_div_rem/asymmetric.rs":"27f5bf70a35109f9d4e4e1ad1e8003aa17da5a1e436bf3e63a493d7528a3a566","src/int/specialized_div_rem/binary_long.rs":"9f1ced81a394f000a21a329683144d68ee431a954136a3634eb55b1ee2cf6d51","src/int/specialized_div_rem/delegate.rs":"9df141af98e391361e25d71ae38d5e845a91d896edd2c041132fd46af8268e85","src/int/specialized_div_rem/mod.rs":"c32a7c416f2c81d6368720053864c3e7082417bca983c329520a8e7dc8c34736","src/int/specialized_div_rem/norm_shift.rs":"3be7ee0dea545c1f702d9daf67dad2b624bf7b17b075c8b90d3d3f7b53df4c21","src/int/specialized_div_rem/trifecta.rs":"87eef69da255b809fd710b14f2eb3f9f59e3dac625f8564ebc8ba78f9763523b","src/int/udiv.rs":"3732b490a472505411577f008b92f489287745968ce6791665201201377d3475","src/lib.rs":"557cd24974b4be235d3cdc4846eeacd8e536330ff54d037b8d56b21d99f64b3c","src/macros.rs":"4e6c006a47d7437f91a92802ecdceea63c60f3924ec98a429a14506c41c5f5dc","src/math.rs":"48bb0d97a1b56d960c6b5130b9a62a1cb1e8e5d62a522163022b8ea24c6cfcca","src/mem/impls.rs":"4517ae10a8adc2b0527529a872d8a7f98627f166d9a18a7aed6fc774b18dd843","src/mem/mod.rs":"791fa5fab759060e966de994b637e88c3c329cf2c0343efccca1da9dc80fcb66","src/mem/x86_64.rs":"912d4e955440113b97bd7dc836697df01a692524edd48cafaf599783ae277b85","src/probestack.rs":"ef5c07e9b95de7b2b77a937789fcfefd9846274317489ad6d623e377c9888601","src/riscv.rs":"8aa8cde1106a179e9a37724193bc5cea5defe212eb38e3049c23b254578f78d4","src/x86.rs":"117b50d6725ee0af0a7b3d197ea580655561f66a870ebc450d96af22bf7f39f6","src/x86_64.rs":"4f16bc9fad7757d48a6da3a078c715dd3a22154aadb4f1998d4c1b5d91396f9e"},"package":"71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3"} \ No newline at end of file +{"files":{"Cargo.lock":"b0b1672fdd0af3eb8158670383772f3ce12d656d1481ec46657da2e9b26b19dd","Cargo.toml":"a49915bc5e86d21f27cfecb8465fe38a8e9cef628cca9619bfd2332cba170ac7","README.md":"5eb36fbab30693dbbe9f0de54749c95bd06fd6e42013b5b9eff3c062b9fdd34f","build.rs":"0c006642fbbe9fa5372a88cbbbb0bb4b391f635b2bde0c497de10740c1458c5e","examples/intrinsics.rs":"a7aa69c17af3aa8f6edff32c214e80827d3cbe3aea386a2be42244444752d253","libm/src/math/acos.rs":"fb066ba84aba1372d706425ec14f35ff8d971756d15eeebd22ecf42a716493bb","libm/src/math/acosf.rs":"a112b82309bba1d35c4e3d6ad4d6c21ef305343d9ab601ddf4bc61d43bc9f1af","libm/src/math/acosh.rs":"99de01ded7922bb93a882ad5ad8b472b5cae0059dea0bdca2077f65e94483150","libm/src/math/acoshf.rs":"10750c4d39ef6717b20a15ef1ce43e15eb851682d2f820f7e94501adec98b9a5","libm/src/math/asin.rs":"095a1e98996daff45df0b154ca0ec35bbf31db964ee9fdda0207308cb20df441","libm/src/math/asinf.rs":"49cccb4db2881982643a4a7d5453f4f8daf527711bbb67313607a3c178856d61","libm/src/math/asinh.rs":"4dd51affa71cce34a192ad66154e248f8d1c4b40fb497f29052333e425bb740f","libm/src/math/asinhf.rs":"914bfecf449f5e2bce786aa12c056d419073c6011d41c1bab7c39ba765fa4c53","libm/src/math/atan.rs":"d4fe46e1c5739dd09997869dcfbc3c85f03c534af52e700d6c6bcf9c3fedda07","libm/src/math/atan2.rs":"2623bc8ca707d13a7092ce49adf68e9cbf4452ad1bf4a861dc40ca858606a747","libm/src/math/atan2f.rs":"dd01943e0e1f1955912e5c3ffc9467529cf64bd02ac0a6ad5ab31dbe6657f05d","libm/src/math/atanf.rs":"e41b41569474a59c970ede3538e00bda4072cf4d90040017101cc79d7dc28caa","libm/src/math/atanh.rs":"57a8fb3f0f116fa4a966ac6bc2abd5f80236ead8e79013f468bd3786921f7110","libm/src/math/atanhf.rs":"6f2e57aaec1b5fc7609cb3938b3d155f51b4237dbda530739c34a0448cd9beb9","libm/src/math/cbrt.rs":"f2c45612d2eecd93cfcdd9ebf824c754fc8f8dfd6d16862c0b9c4ccea78c2a0f","libm/src/math/cbrtf.rs":"ad0b483854aa9f17a44d36c049bf0e8ebab34c27e90b787c05f45cc230ec7d19","libm/src/math/ceil.rs":"57ba5b6e207a0ccbd34190d1aa544389ca12126be23821dfb5746497f620ce03","libm/src/math/ceilf.rs":"c922a0475a599b9ea5473e615f74700b99707cebd6927f24ea59cb2a3cb3bbc3","libm/src/math/copysign.rs":"8b6440a251f0f1509d87f18122f74d0d5c03d0b60517e89e441434a3c5d84591","libm/src/math/copysignf.rs":"87d35436d224852ada93a2e93f6730cf1a727b808dd10e7d49ab4585866e336b","libm/src/math/cos.rs":"74babdc13ede78e400c5ca1854c3e22d2e08cbdc5618aefa5bba6f9303ef65b6","libm/src/math/cosf.rs":"09c40f93c445b741e22477ceedf163ca33b6a47f973f7c9876cfba2692edb29c","libm/src/math/cosh.rs":"0d0a7cef18577f321996b8b87561963139f754ad7f2ea0a3b3883811f3f0693a","libm/src/math/coshf.rs":"be8ca8739e4cf1978425b349f941cb4838bba8c10cb559c7940b9fd4fdde21ad","libm/src/math/erf.rs":"52cc9d9d54074a692001fb2d8215cd6903b645d4291ea20482455bc7f6947726","libm/src/math/erff.rs":"d37af67007fe4e9bce994c8c9805dd8af1b0ada68a10db8d8db13424dce65d09","libm/src/math/exp.rs":"ca7405ad0d1993fffcf9aae96f9256307bed3c4916545aaebd1cf1d2df1807fa","libm/src/math/exp10.rs":"2e136c6ecedd8e57a6c31796f57fae4546fcfd8bc6be66c836f553df9c74b907","libm/src/math/exp10f.rs":"9a3ce506ec587066a355ab74e0eb69a03a214ac405718087ae9772365050b20b","libm/src/math/exp2.rs":"94a9304a2ce3bc81f6d2aefd3cde6faa30f13260d46cb13692863cdea1c9a3a1","libm/src/math/exp2f.rs":"785f2630accd35118ec07bf60273e219ed91a215b956b1552eeea5bc2a708cc8","libm/src/math/expf.rs":"ec14c18f891a9e37735ec39e6fc2e9bf674a2c2e083f22e2533b481177359c98","libm/src/math/expm1.rs":"124069f456c8ad331f265c7509d9e223b2a300e461bbfd3d6adfdcdd2ee5b8ac","libm/src/math/expm1f.rs":"18e2116d31ea8410051cc709b9d04b754b0e3ba6758ee1bf0b48749f4999b840","libm/src/math/expo2.rs":"4f4f9fecfccb43f30c2784aa7c0bb656754a52b8ab431f7d1b551c673ab133f1","libm/src/math/fabs.rs":"e6c7db39f98508098cdf64ac0c2f53866c466149a7490afb9fe22b44c4dd81b3","libm/src/math/fabsf.rs":"83a1f5f4d9ca899ba2b701d7332e18b40258b83e111db4c5d8fab2cc1be58aa3","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"916ae11e4763588518d64dee82afb41be9d1ee38ecc0679c821d4e7e22cd3dc5","libm/src/math/floor.rs":"5050804cae173af6775c0678d6c1aafb5ca2b744bc8a2f50d9d03b95dcee1fb0","libm/src/math/floorf.rs":"c903e0c57bc60a888c513eb7a873a87a4759ba68fc791b6b931652f8ee74cc03","libm/src/math/fma.rs":"d88e01c2c2d11333dd49b61166caa036ff5f08f3a8c5973b9e3c9574bf2eb675","libm/src/math/fmaf.rs":"1db6ee0d47ddbdb441cfe167edf89b431239f5805708fd0376cf5c01349a4bd6","libm/src/math/fmax.rs":"f6c8e96a8b1a170648d2fa3513e7b6b459085d708c839869f82e305fe58fac37","libm/src/math/fmaxf.rs":"dff0025433232e8a5ec7bd54d847ccf596d762ea4e35f5c54fbaac9404d732fd","libm/src/math/fmin.rs":"95b6cb66ca0e0e22276f0bf88dbe8fb69796a69a196a7491bd4802efbcf2e298","libm/src/math/fminf.rs":"304bc839b15ea3d84e68d2af9f40524ec120d30a36a667b22fcb98a6c258f4c7","libm/src/math/fmod.rs":"a1c0550fc7df8164733d914e222ff0966a2ab886d6e75a1098f24fe0283ae227","libm/src/math/fmodf.rs":"ee51ed092c0eeb8195f35735ff725cfd46612e0d689a7c483538bd92fbe61828","libm/src/math/frexp.rs":"28af70026922a8ab979744c7ad4d8faba6079c4743b7eeb6d14c983a982fbbcc","libm/src/math/frexpf.rs":"2e2593ae8002ba420809ebfaf737ef001cdc912354be3d978a8c0cb930350d4d","libm/src/math/hypot.rs":"841131c4a0cea75bc8a86e29f3f6d0815a61fc99731c9984651ce83d3050d218","libm/src/math/hypotf.rs":"5f317323edc2eb699580fe54b074b7e570a7734d51a0a149c0b49b54470a836c","libm/src/math/ilogb.rs":"d178ad7ca3439f82d565962b143f20448e45b2e2c51357b127abaec683297e32","libm/src/math/ilogbf.rs":"00f2b1b0496e21c6a42d68aea74d7156fa2ff0a735741b9051f3ca1cf0f57586","libm/src/math/j0.rs":"9572b6396c489927d332d0e717920e61ec0618e5e9c31f7eeeec70f5e4abab06","libm/src/math/j0f.rs":"802c8254bded9b3afb6eea8b9af240038a5a4a5d811396729f69ca509e3e7d87","libm/src/math/j1.rs":"97b1af1611fa3d110c2b349ee8e4176100132ea1391b619086b47ac063b81803","libm/src/math/j1f.rs":"9c9b128752e8ea2e7d81b637ba84907ab54a545e7602c49167b313743927930b","libm/src/math/jn.rs":"847d122334e5707ad9627146cddccc082a1f2f5bcd3e5ef54399013a7007ce88","libm/src/math/jnf.rs":"4045076f7d1a1b89882ed60d4dd60a4cbbc66b85cfb90491378c8015effcc476","libm/src/math/k_cos.rs":"f34a69e44d6b8901b03b578a75972f438ab20a7b98a0903fc1903d6fde3899be","libm/src/math/k_cosf.rs":"8f7117ff21cebf8e890a5bcfd7ea858a94172f4172b79a66d53824c2cb0888b1","libm/src/math/k_expo2.rs":"eb4ca9e6a525b7ea6da868c3cb136896682cc46f8396ba2a2ebc3ae9e9ba54b0","libm/src/math/k_expo2f.rs":"d51ad5df61cb5d1258bdb90c52bfed4572bb446a9337de9c04411ed9454ae0cb","libm/src/math/k_sin.rs":"14b2aba6ca07150c92768b5a72acaf5cde6a11d6619e14896512a7ba242e289a","libm/src/math/k_sinf.rs":"2775fcc710807164e6f37a4f8da3c8143cd5f16e19ce7c31c5591522151d7a96","libm/src/math/k_tan.rs":"a72beae4ccd9631eeeb61d6365bbeecae81c8411f3120a999c515cca0d5ea5c5","libm/src/math/k_tanf.rs":"6a794be56fa4b2f60452b9bab19af01c388f174560acbf829a351378ea39495d","libm/src/math/ldexp.rs":"b647f0096e80e4d926d8dd18d294c892ee2cb1778effe2c5e1b2664ae5cb1a4e","libm/src/math/ldexpf.rs":"98743fad2cd97a7be496f40ba3157ac1438fce0d0c25d5ab90c3b8c71c3fd0ed","libm/src/math/lgamma.rs":"0edd18e4f96bfcbe8b1b5af3eeca5208cd6d2d479dfa5ad117c9dfeccecf614f","libm/src/math/lgamma_r.rs":"f44a37aeccd56559ef784ae8edf217d14ad5cc2d910f0a65e70ffc86d7dc23dd","libm/src/math/lgammaf.rs":"967845357758b868a571857ec001f9f9154001110b8e97c08b6d10586bed9c49","libm/src/math/lgammaf_r.rs":"7143016d60e11fa235d53968125e57231b1104ce52149b5e1eed39629e0d1ff0","libm/src/math/log.rs":"b5e0c5f30d9e94351488732801be3107c12b854c3f95ad37e256dd88eeca408f","libm/src/math/log10.rs":"3425ff8be001fd1646ba15e254eb6ef4bdc6ccaf0cbee27ddf1fa84e04178b90","libm/src/math/log10f.rs":"fee4f71879bc4c99259e68c0c641364901629fb29a8ebddfcc0d090102cceddd","libm/src/math/log1p.rs":"9cf400852f165e6be19b97036ae9521fb9ca857d0a9a91c117d9123221622185","libm/src/math/log1pf.rs":"2716e6d2afa271996b7c8f47fd9e4952c88f4c1fd8c07c3e8ce8c62794bf71d8","libm/src/math/log2.rs":"dbbbfbaaa8aa6a4dbefea554ea3983090a9691228b011910c751f6adca912c40","libm/src/math/log2f.rs":"92a90350d8edce21c31c285c3e620fca7c62a2366008921715945c2c73b5b79f","libm/src/math/logf.rs":"845342cffc34d3db1f5ec12d8e5b773cd5a79056e28662fcb9bcd80207596f50","libm/src/math/mod.rs":"9de65aedb36910356bc47d25b1468b40ab63faf7e319e599e478a239681bdf9c","libm/src/math/modf.rs":"d012ed5a708ef52b6d1313c22a46cadaf5764dde1220816e3df2f03a0fcc60ae","libm/src/math/modff.rs":"f8f1e4c27a85d2cdb3c8e74439d59ef64aa543b948f22c23227d02d8388d61c2","libm/src/math/nextafter.rs":"3282e7eef214a32736fb6928d490198ad394b26b402b45495115b104839eebfe","libm/src/math/nextafterf.rs":"0937dc8a8155c19842c12181e741cec1f7df1f7a00cee81fcb2475e2842761b7","libm/src/math/pow.rs":"17c38297c5bf99accd915f292b777f8716ecf328916297c8bb9dfde6fd8ce522","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"3e53234977daf61c89c29c940791714aad2f676a6f38188c7d17543a2aa8806f","libm/src/math/rem_pio2_large.rs":"482f31ff4e4eacf885f6130ae26a1d59f76b382059d6c742f30e5036811d3ca8","libm/src/math/rem_pio2f.rs":"07fb48f6d5cbadfd32ce4124b2b74af98b8391a2a6f36ce2a7d32e4500cb65ac","libm/src/math/remainder.rs":"63865f4370853c476b45bb27a5c54a4072146aa4a626835ae5263871a4e7e5dc","libm/src/math/remainderf.rs":"dd3fa432dbda8f2135428198be7bd69c57f8d13df3f365b12f52bf6a82352ac4","libm/src/math/remquo.rs":"3cc0bf55069f165c4843f2c358b3a27279c01e8cdd99f9057a3f7f31f45408f2","libm/src/math/remquof.rs":"cc749e18ecb7e766b8b8eeabdbf89ac99087d3d587e71e30f690676a3d2c1f9b","libm/src/math/round.rs":"f10797ef15dd34a74e912ba8621d60bc0200c87b94308c9de3cc88d7aec4feb4","libm/src/math/roundf.rs":"27e37cfcf82373709e7debf9c0c18f7ed00ae0f5d97a214c388041f7a6996d35","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"bb483a2138ca779e03a191222636f0c60fd75a77a2a12f263bda4b6aa9136317","libm/src/math/sincos.rs":"1cf62a16c215e367f51078a3ba23a3f257682032a8f3c657293029a886b18d82","libm/src/math/sincosf.rs":"b0f589e6ada8215944d7784f420c6721c90387d799e349ce7676674f3c475e75","libm/src/math/sinf.rs":"dcddac1d56b084cbb8d0e019433c9c5fe2201d9b257a7dcf2f85c9a8f14b79cf","libm/src/math/sinh.rs":"d8ee4c7af883a526f36c1a6da13bb81fba9181b477e2f2538161a2bee97edc35","libm/src/math/sinhf.rs":"d06eb030ba9dbf7094df127262bfe99f149b4db49fa8ab8c15499660f1e46b26","libm/src/math/sqrt.rs":"824570a631c2542ccee68b65e3eb08fe79c037a29bbaaf54da5367e7b236124a","libm/src/math/sqrtf.rs":"4cf418d74f7751d522a642a9a8d6b86ee3472c6aaef44f0eb1bc26f4d8a90985","libm/src/math/tan.rs":"930ecedaadc60f704c2dfa4e15186f59713c1ba7d948529d215223b424827db5","libm/src/math/tanf.rs":"894156a3b107aee08461eb4e7e412fc049aa237d176ae705c6e3e2d7060d94e3","libm/src/math/tanh.rs":"f1f08eb98ed959a17370a7aaf0177be36e3764543424e78feb033ed3f5e8ec98","libm/src/math/tanhf.rs":"74027b0c672a4e64bdef6d7a3069b90caec50e1e7dbb2c12d2828f310502f41e","libm/src/math/tgamma.rs":"c889cfa49bbeb4dbb0941fe9fac3b4da7d5879dcf04a3b9bb6e56de529baf374","libm/src/math/tgammaf.rs":"0737b34777095d0e4d07fe533e8f105082dd4e8ece411bba6ae5993b45b9388c","libm/src/math/trunc.rs":"642264897cc1505e720c8cf313be81aa9fd53aae866644a2e988d01dbc77fd8a","libm/src/math/truncf.rs":"dee3607baf1af0f01deae46e429e097234c50b268eaefebbe716f19f38597900","src/arm.rs":"acf149932aa46a2755cf8cd2eb7d6ae249e46b1e10ad45ce5f924561945d1273","src/arm_linux.rs":"35a4cb7b75015543feb15b0c692da0faf0e6037d3b97a4a18067ba416eae1a70","src/float/add.rs":"3ec32ceaf470a89777b54f9cde61832fdadeade0f4894f268a949e968520bc57","src/float/cmp.rs":"79b1fdc8d5f943c4ad5ea4ad32623b18f63e17ac3852fbc64a4942228007e1fc","src/float/conv.rs":"cb9a830e0d440ed825aa897f268e4ae067204da4ffc162ba963977a4b309007f","src/float/div.rs":"bc808a5372d041b96aa603ac814165e1e7dbd690e4ab9b026d9465c1cbc2c583","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"48d76632575789a6ecf99213b1ed38c21c86ad5a5c3fa33ccb31f77829271b79","src/float/mul.rs":"0d0c1f0c28c149ecadeafd459d3c4c9327e4cfcae2cba479957bb8010ef51a01","src/float/pow.rs":"2ada190738731eb6f24104f8fb8c4d6f03cfb16451536dbee32f2b33db0c4b19","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/float/trunc.rs":"d21d2a2f9a1918b4bbb594691e397972a7c04b74b2acf04016c55693abf6d24b","src/int/addsub.rs":"7ec45ce1ba15b56a5b7129d3e5722c4db764c6545306d3fa9090983bcabd6f17","src/int/leading_zeros.rs":"ccf5e9d098c80034dcf6e38437c9a2eb670fa8043558bbfb574f2293164729a6","src/int/mod.rs":"bab1b77535ceebdebb89fd4e59e7105f8c45347bb638351a626615b24544a0b1","src/int/mul.rs":"bb48d8fd42d8f9f5fe9271d8d0f7a92dbae320bf4346e19d1071eb2093cb8ed9","src/int/sdiv.rs":"ace4cb0ec388a38834e01cab2c5bc87182d31588dfc0b1ae117c11ed0c4781cf","src/int/shift.rs":"3967c28a8d61279546e91958d64745fec63f15aee9175eb0602cc6353830da6c","src/int/specialized_div_rem/asymmetric.rs":"27f5bf70a35109f9d4e4e1ad1e8003aa17da5a1e436bf3e63a493d7528a3a566","src/int/specialized_div_rem/binary_long.rs":"9f1ced81a394f000a21a329683144d68ee431a954136a3634eb55b1ee2cf6d51","src/int/specialized_div_rem/delegate.rs":"9df141af98e391361e25d71ae38d5e845a91d896edd2c041132fd46af8268e85","src/int/specialized_div_rem/mod.rs":"c32a7c416f2c81d6368720053864c3e7082417bca983c329520a8e7dc8c34736","src/int/specialized_div_rem/norm_shift.rs":"3be7ee0dea545c1f702d9daf67dad2b624bf7b17b075c8b90d3d3f7b53df4c21","src/int/specialized_div_rem/trifecta.rs":"87eef69da255b809fd710b14f2eb3f9f59e3dac625f8564ebc8ba78f9763523b","src/int/udiv.rs":"3732b490a472505411577f008b92f489287745968ce6791665201201377d3475","src/lib.rs":"d0e85291d12a57c61791257e3adefb8f2222e1ba6f9e5cd4cf7fba59d26477f4","src/macros.rs":"a3261b40b1db041fb779b32bfc2bf3cba7a7c85f10fd02997163b3396658a3d7","src/math.rs":"ac6063d7c8927e3b8fe6e41acf83261db2a57e02f7c5a30bc52dbb03c0df9c72","src/mem/impls.rs":"a8d1c28a77d9b334872abbebfcba3fd1802175bef53c0b545e85242860698780","src/mem/mod.rs":"5034543d963149c14a6823bee32a1fb9dfd950c32153d37f97e9df1dc6c23129","src/mem/x86_64.rs":"9f740891f666acf384159128eef233d9e15c6120da8016370c6f9f05cc29d653","src/probestack.rs":"ef5c07e9b95de7b2b77a937789fcfefd9846274317489ad6d623e377c9888601","src/riscv.rs":"8aa8cde1106a179e9a37724193bc5cea5defe212eb38e3049c23b254578f78d4","src/x86.rs":"117b50d6725ee0af0a7b3d197ea580655561f66a870ebc450d96af22bf7f39f6","src/x86_64.rs":"4f16bc9fad7757d48a6da3a078c715dd3a22154aadb4f1998d4c1b5d91396f9e"},"package":"4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca"} \ No newline at end of file diff --git a/vendor/compiler_builtins/Cargo.lock b/vendor/compiler_builtins/Cargo.lock index e184f7e20..e60762217 100644 --- a/vendor/compiler_builtins/Cargo.lock +++ b/vendor/compiler_builtins/Cargo.lock @@ -4,13 +4,13 @@ version = 3 [[package]] name = "cc" -version = "1.0.70" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "compiler_builtins" -version = "0.1.73" +version = "0.1.79" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/vendor/compiler_builtins/Cargo.toml b/vendor/compiler_builtins/Cargo.toml index 765e99f94..eedf9a7b2 100644 --- a/vendor/compiler_builtins/Cargo.toml +++ b/vendor/compiler_builtins/Cargo.toml @@ -11,7 +11,7 @@ [package] name = "compiler_builtins" -version = "0.1.73" +version = "0.1.79" authors = ["Jorge Aparicio "] links = "compiler-rt" include = [ @@ -33,6 +33,7 @@ documentation = "https://docs.rs/compiler_builtins" readme = "README.md" license = "MIT/Apache-2.0" repository = "https://github.com/rust-lang/compiler-builtins" +resolver = "1" [profile.dev] panic = "abort" diff --git a/vendor/compiler_builtins/build.rs b/vendor/compiler_builtins/build.rs index 11deffb9c..73952bb9f 100644 --- a/vendor/compiler_builtins/build.rs +++ b/vendor/compiler_builtins/build.rs @@ -29,6 +29,7 @@ fn main() { || (target.contains("sgx") && target.contains("fortanix")) || target.contains("-none") || target.contains("nvptx") + || target.contains("uefi") { println!("cargo:rustc-cfg=feature=\"mem\""); } @@ -58,9 +59,11 @@ fn main() { // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C - // compiler nor is cc-rs ready for compilation to riscv (at this - // time). This can probably be removed in the future - if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") { + // compiler. + if !target.contains("wasm") + && !target.contains("nvptx") + && (!target.starts_with("riscv") || target.contains("xous")) + { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } @@ -457,6 +460,7 @@ mod c { ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), ]); } diff --git a/vendor/compiler_builtins/libm/src/math/acosh.rs b/vendor/compiler_builtins/libm/src/math/acosh.rs index ac7a5f1c6..d1f5b9fa9 100644 --- a/vendor/compiler_builtins/libm/src/math/acosh.rs +++ b/vendor/compiler_builtins/libm/src/math/acosh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/vendor/compiler_builtins/libm/src/math/acoshf.rs b/vendor/compiler_builtins/libm/src/math/acoshf.rs index 0879e1edb..ad3455fdd 100644 --- a/vendor/compiler_builtins/libm/src/math/acoshf.rs +++ b/vendor/compiler_builtins/libm/src/math/acoshf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acoshf(x: f32) -> f32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/vendor/compiler_builtins/libm/src/math/asinh.rs b/vendor/compiler_builtins/libm/src/math/asinh.rs index 14295357a..0abd80c2f 100644 --- a/vendor/compiler_builtins/libm/src/math/asinh.rs +++ b/vendor/compiler_builtins/libm/src/math/asinh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinh(mut x: f64) -> f64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/vendor/compiler_builtins/libm/src/math/asinhf.rs b/vendor/compiler_builtins/libm/src/math/asinhf.rs index e22a29132..09c77823e 100644 --- a/vendor/compiler_builtins/libm/src/math/asinhf.rs +++ b/vendor/compiler_builtins/libm/src/math/asinhf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinhf(mut x: f32) -> f32 { let u = x.to_bits(); let i = u & 0x7fffffff; diff --git a/vendor/compiler_builtins/libm/src/math/atanh.rs b/vendor/compiler_builtins/libm/src/math/atanh.rs index 79a989c42..b984c4ac6 100644 --- a/vendor/compiler_builtins/libm/src/math/atanh.rs +++ b/vendor/compiler_builtins/libm/src/math/atanh.rs @@ -5,6 +5,7 @@ use super::log1p; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/vendor/compiler_builtins/libm/src/math/atanhf.rs b/vendor/compiler_builtins/libm/src/math/atanhf.rs index 7b2f34d97..a1aa314a5 100644 --- a/vendor/compiler_builtins/libm/src/math/atanhf.rs +++ b/vendor/compiler_builtins/libm/src/math/atanhf.rs @@ -5,6 +5,7 @@ use super::log1pf; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanhf(mut x: f32) -> f32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; diff --git a/vendor/compiler_builtins/libm/src/math/copysign.rs b/vendor/compiler_builtins/libm/src/math/copysign.rs index 1527fb6ea..1f4a35a33 100644 --- a/vendor/compiler_builtins/libm/src/math/copysign.rs +++ b/vendor/compiler_builtins/libm/src/math/copysign.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysign(x: f64, y: f64) -> f64 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/vendor/compiler_builtins/libm/src/math/copysignf.rs b/vendor/compiler_builtins/libm/src/math/copysignf.rs index 35148561a..6c346e3a5 100644 --- a/vendor/compiler_builtins/libm/src/math/copysignf.rs +++ b/vendor/compiler_builtins/libm/src/math/copysignf.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysignf(x: f32, y: f32) -> f32 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/vendor/compiler_builtins/libm/src/math/erf.rs b/vendor/compiler_builtins/libm/src/math/erf.rs index a2c617d34..5e21ba578 100644 --- a/vendor/compiler_builtins/libm/src/math/erf.rs +++ b/vendor/compiler_builtins/libm/src/math/erf.rs @@ -219,6 +219,7 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { /// Calculates an approximation to the “error functionâ€, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erf(x: f64) -> f64 { let r: f64; let s: f64; diff --git a/vendor/compiler_builtins/libm/src/math/erff.rs b/vendor/compiler_builtins/libm/src/math/erff.rs index 384052293..f74d4b632 100644 --- a/vendor/compiler_builtins/libm/src/math/erff.rs +++ b/vendor/compiler_builtins/libm/src/math/erff.rs @@ -130,6 +130,7 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { /// Calculates an approximation to the “error functionâ€, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erff(x: f32) -> f32 { let r: f32; let s: f32; diff --git a/vendor/compiler_builtins/libm/src/math/exp10.rs b/vendor/compiler_builtins/libm/src/math/exp10.rs index 9537f76f1..559930e10 100644 --- a/vendor/compiler_builtins/libm/src/math/exp10.rs +++ b/vendor/compiler_builtins/libm/src/math/exp10.rs @@ -6,16 +6,17 @@ const P10: &[f64] = &[ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ if (u >> 52 & 0x7ff) < 0x3ff + 4 { if y == 0.0 { - return P10[((n as isize) + 15) as usize]; + return i!(P10, ((n as isize) + 15) as usize); } y = exp2(LN10 * y); - return y * P10[((n as isize) + 15) as usize]; + return y * i!(P10, ((n as isize) + 15) as usize); } return pow(10.0, x); } diff --git a/vendor/compiler_builtins/libm/src/math/exp10f.rs b/vendor/compiler_builtins/libm/src/math/exp10f.rs index d45fff36e..1279bc6c5 100644 --- a/vendor/compiler_builtins/libm/src/math/exp10f.rs +++ b/vendor/compiler_builtins/libm/src/math/exp10f.rs @@ -6,16 +6,17 @@ const P10: &[f32] = &[ 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ if (u >> 23 & 0xff) < 0x7f + 3 { if y == 0.0 { - return P10[((n as isize) + 7) as usize]; + return i!(P10, ((n as isize) + 7) as usize); } y = exp2f(LN10_F32 * y); - return y * P10[((n as isize) + 7) as usize]; + return y * i!(P10, ((n as isize) + 7) as usize); } return exp2(LN10_F64 * (x as f64)) as f32; } diff --git a/vendor/compiler_builtins/libm/src/math/fenv.rs b/vendor/compiler_builtins/libm/src/math/fenv.rs index 652e60324..c91272e82 100644 --- a/vendor/compiler_builtins/libm/src/math/fenv.rs +++ b/vendor/compiler_builtins/libm/src/math/fenv.rs @@ -5,7 +5,6 @@ pub(crate) const FE_UNDERFLOW: i32 = 0; pub(crate) const FE_INEXACT: i32 = 0; pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_TOWARDZERO: i32 = 0; #[inline] pub(crate) fn feclearexcept(_mask: i32) -> i32 { @@ -26,8 +25,3 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 { pub(crate) fn fegetround() -> i32 { FE_TONEAREST } - -#[inline] -pub(crate) fn fesetround(_r: i32) -> i32 { - 0 -} diff --git a/vendor/compiler_builtins/libm/src/math/fmaf.rs b/vendor/compiler_builtins/libm/src/math/fmaf.rs index 03d371c55..2848f2aee 100644 --- a/vendor/compiler_builtins/libm/src/math/fmaf.rs +++ b/vendor/compiler_builtins/libm/src/math/fmaf.rs @@ -29,8 +29,7 @@ use core::f32; use core::ptr::read_volatile; use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST, - FE_TOWARDZERO, FE_UNDERFLOW, + feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, }; /* @@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * If result is inexact, and exactly halfway between two float values, * we need to adjust the low-order bit in the direction of the error. */ - fesetround(FE_TOWARDZERO); - // prevent `vxy + z` from being CSE'd with `xy + z` above - let vxy: f64 = unsafe { read_volatile(&xy) }; - let mut adjusted_result: f64 = vxy + z as f64; - fesetround(FE_TONEAREST); - if result == adjusted_result { - ui = adjusted_result.to_bits(); + let neg = ui >> 63 != 0; + let err = if neg == (z as f64 > xy) { + xy - result + z as f64 + } else { + z as f64 - result + xy + }; + if neg == (err < 0.0) { ui += 1; - adjusted_result = f64::from_bits(ui); + } else { + ui -= 1; + } + f64::from_bits(ui) as f32 +} + +#[cfg(test)] +mod tests { + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(super::fmaf(a, b, c), expected); } - z = adjusted_result as f32; - z } diff --git a/vendor/compiler_builtins/libm/src/math/ilogb.rs b/vendor/compiler_builtins/libm/src/math/ilogb.rs index 0a380b7ef..7d74dcfb6 100644 --- a/vendor/compiler_builtins/libm/src/math/ilogb.rs +++ b/vendor/compiler_builtins/libm/src/math/ilogb.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogb(x: f64) -> i32 { let mut i: u64 = x.to_bits(); let e = ((i >> 52) & 0x7ff) as i32; diff --git a/vendor/compiler_builtins/libm/src/math/ilogbf.rs b/vendor/compiler_builtins/libm/src/math/ilogbf.rs index b384fa4b2..0fa58748c 100644 --- a/vendor/compiler_builtins/libm/src/math/ilogbf.rs +++ b/vendor/compiler_builtins/libm/src/math/ilogbf.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogbf(x: f32) -> i32 { let mut i = x.to_bits(); let e = ((i >> 23) & 0xff) as i32; diff --git a/vendor/compiler_builtins/libm/src/math/lgamma.rs b/vendor/compiler_builtins/libm/src/math/lgamma.rs index 5bc87e85e..a08bc5b64 100644 --- a/vendor/compiler_builtins/libm/src/math/lgamma.rs +++ b/vendor/compiler_builtins/libm/src/math/lgamma.rs @@ -1,5 +1,6 @@ use super::lgamma_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } diff --git a/vendor/compiler_builtins/libm/src/math/lgamma_r.rs b/vendor/compiler_builtins/libm/src/math/lgamma_r.rs index 9533e882c..b26177e6e 100644 --- a/vendor/compiler_builtins/libm/src/math/lgamma_r.rs +++ b/vendor/compiler_builtins/libm/src/math/lgamma_r.rs @@ -152,7 +152,7 @@ fn sin_pi(mut x: f64) -> f64 { x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as i32; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -164,6 +164,7 @@ fn sin_pi(mut x: f64) -> f64 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma_r(mut x: f64) -> (f64, i32) { let u: u64 = x.to_bits(); let mut t: f64; diff --git a/vendor/compiler_builtins/libm/src/math/lgammaf.rs b/vendor/compiler_builtins/libm/src/math/lgammaf.rs index dfdc87f96..a9c2da75b 100644 --- a/vendor/compiler_builtins/libm/src/math/lgammaf.rs +++ b/vendor/compiler_builtins/libm/src/math/lgammaf.rs @@ -1,5 +1,6 @@ use super::lgammaf_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } diff --git a/vendor/compiler_builtins/libm/src/math/lgammaf_r.rs b/vendor/compiler_builtins/libm/src/math/lgammaf_r.rs index c5e559f46..723c90daf 100644 --- a/vendor/compiler_builtins/libm/src/math/lgammaf_r.rs +++ b/vendor/compiler_builtins/libm/src/math/lgammaf_r.rs @@ -88,7 +88,7 @@ fn sin_pi(mut x: f32) -> f32 { x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); y = (x as f64) - (n as f64) * 0.5; y *= 3.14159265358979323846; match n { @@ -99,6 +99,7 @@ fn sin_pi(mut x: f32) -> f32 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf_r(mut x: f32) -> (f32, i32) { let u = x.to_bits(); let mut t: f32; diff --git a/vendor/compiler_builtins/libm/src/math/rem_pio2_large.rs b/vendor/compiler_builtins/libm/src/math/rem_pio2_large.rs index 65473f0ab..db97a39d4 100644 --- a/vendor/compiler_builtins/libm/src/math/rem_pio2_large.rs +++ b/vendor/compiler_builtins/libm/src/math/rem_pio2_large.rs @@ -27,7 +27,7 @@ const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(target_pointer_width = "32")] +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] const IPIO2: [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, diff --git a/vendor/compiler_builtins/libm/src/math/sincos.rs b/vendor/compiler_builtins/libm/src/math/sincos.rs index 4ab588412..ff5d87a1c 100644 --- a/vendor/compiler_builtins/libm/src/math/sincos.rs +++ b/vendor/compiler_builtins/libm/src/math/sincos.rs @@ -12,6 +12,7 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; let c: f64; diff --git a/vendor/compiler_builtins/libm/src/math/sincosf.rs b/vendor/compiler_builtins/libm/src/math/sincosf.rs index 5304e8ca0..9a4c36104 100644 --- a/vendor/compiler_builtins/libm/src/math/sincosf.rs +++ b/vendor/compiler_builtins/libm/src/math/sincosf.rs @@ -23,6 +23,7 @@ const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; let c: f32; diff --git a/vendor/compiler_builtins/libm/src/math/tgamma.rs b/vendor/compiler_builtins/libm/src/math/tgamma.rs index f8ccf669a..e64eff61f 100644 --- a/vendor/compiler_builtins/libm/src/math/tgamma.rs +++ b/vendor/compiler_builtins/libm/src/math/tgamma.rs @@ -38,7 +38,7 @@ fn sinpi(mut x: f64) -> f64 { /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -118,18 +118,19 @@ fn s(x: f64) -> f64 { /* to avoid overflow handle large x differently */ if x < 8.0 { for i in (0..=N).rev() { - num = num * x + SNUM[i]; - den = den * x + SDEN[i]; + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); } } else { for i in 0..=N { - num = num / x + SNUM[i]; - den = den / x + SDEN[i]; + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); } } return num / den; } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); let absx: f64; @@ -157,7 +158,7 @@ pub fn tgamma(mut x: f64) -> f64 { return 0.0 / 0.0; } if x <= FACT.len() as f64 { - return FACT[(x as usize) - 1]; + return i!(FACT, (x as usize) - 1); } } diff --git a/vendor/compiler_builtins/libm/src/math/tgammaf.rs b/vendor/compiler_builtins/libm/src/math/tgammaf.rs index a8f161f0c..23e3814f9 100644 --- a/vendor/compiler_builtins/libm/src/math/tgammaf.rs +++ b/vendor/compiler_builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,6 @@ use super::tgamma; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 } diff --git a/vendor/compiler_builtins/src/arm.rs b/vendor/compiler_builtins/src/arm.rs index 9c1b6ad12..e517a9ef3 100644 --- a/vendor/compiler_builtins/src/arm.rs +++ b/vendor/compiler_builtins/src/arm.rs @@ -22,6 +22,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[naked] #[cfg(not(target_env = "msvc"))] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -36,6 +37,7 @@ intrinsics! { } #[naked] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -52,6 +54,7 @@ intrinsics! { } #[naked] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -65,6 +68,7 @@ intrinsics! { } #[naked] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", diff --git a/vendor/compiler_builtins/src/arm_linux.rs b/vendor/compiler_builtins/src/arm_linux.rs index 8fe09485b..8f22eb628 100644 --- a/vendor/compiler_builtins/src/arm_linux.rs +++ b/vendor/compiler_builtins/src/arm_linux.rs @@ -55,7 +55,7 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { } // Generic atomic read-modify-write operation -unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { +unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); @@ -65,7 +65,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { let newval = f(curval); let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { - return curval; + return g(curval, newval); } } } @@ -89,13 +89,21 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { } macro_rules! atomic_rmw { - ($name:ident, $ty:ty, $op:expr) => { + ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { intrinsics! { pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty } } }; + + (@old $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |old, _| old); + }; + + (@new $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |_, new| new); + }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { @@ -107,101 +115,129 @@ macro_rules! atomic_cmpxchg { }; } -atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); + +atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a +atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a +atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); -atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); -atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); +atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); + +atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); -atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); -atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); +atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); +atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); -atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); -atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); -atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); +atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); diff --git a/vendor/compiler_builtins/src/float/conv.rs b/vendor/compiler_builtins/src/float/conv.rs index 07b58f3d2..68ba63408 100644 --- a/vendor/compiler_builtins/src/float/conv.rs +++ b/vendor/compiler_builtins/src/float/conv.rs @@ -92,12 +92,12 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } @@ -129,13 +129,13 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { let sign_bit = ((i >> 127) as u32) << 31; f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { let sign_bit = ((i >> 127) as u64) << 63; f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) diff --git a/vendor/compiler_builtins/src/lib.rs b/vendor/compiler_builtins/src/lib.rs index 009923d27..e7bc61e4c 100644 --- a/vendor/compiler_builtins/src/lib.rs +++ b/vendor/compiler_builtins/src/lib.rs @@ -6,6 +6,7 @@ #![feature(compiler_builtins)] #![feature(core_ffi_c)] #![feature(core_intrinsics)] +#![feature(inline_const)] #![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] @@ -45,6 +46,7 @@ pub mod int; all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), + target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] pub mod math; diff --git a/vendor/compiler_builtins/src/macros.rs b/vendor/compiler_builtins/src/macros.rs index 518a18d4d..7d90b7aad 100644 --- a/vendor/compiler_builtins/src/macros.rs +++ b/vendor/compiler_builtins/src/macros.rs @@ -174,7 +174,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -182,7 +182,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_pointer_width = "64")))] + #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -209,13 +209,13 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) @@ -226,7 +226,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_arch = "x86_64")))] + #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -426,7 +426,7 @@ macro_rules! intrinsics { // Hack for LLVM expectations for ABI on windows. This is used by the // `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(windows, target_pointer_width = "64"))] +#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); diff --git a/vendor/compiler_builtins/src/math.rs b/vendor/compiler_builtins/src/math.rs index fa59753f8..fa9836186 100644 --- a/vendor/compiler_builtins/src/math.rs +++ b/vendor/compiler_builtins/src/math.rs @@ -20,6 +20,7 @@ macro_rules! no_mangle { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") @@ -62,6 +63,8 @@ no_mangle! { fn tanhf(n: f32) -> f32; fn ldexp(f: f64, n: i32) -> f64; fn ldexpf(f: f32, n: i32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; } #[cfg(any( @@ -70,6 +73,8 @@ no_mangle! { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", + all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -93,7 +98,17 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +#[cfg(any(target_os = "xous", target_os = "uefi"))] +no_mangle! { + fn sqrtf(x: f32) -> f32; + fn sqrt(x: f64) -> f64; +} + +#[cfg(any( + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "xous", + target_os = "uefi" +))] no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; diff --git a/vendor/compiler_builtins/src/mem/impls.rs b/vendor/compiler_builtins/src/mem/impls.rs index 815132425..72003a5c4 100644 --- a/vendor/compiler_builtins/src/mem/impls.rs +++ b/vendor/compiler_builtins/src/mem/impls.rs @@ -265,3 +265,17 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } set_bytes_bytes(s, c, n); } + +#[inline(always)] +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.add(i); + let b = *s2.add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} diff --git a/vendor/compiler_builtins/src/mem/mod.rs b/vendor/compiler_builtins/src/mem/mod.rs index a55113861..c5b0ddc16 100644 --- a/vendor/compiler_builtins/src/mem/mod.rs +++ b/vendor/compiler_builtins/src/mem/mod.rs @@ -51,16 +51,7 @@ intrinsics! { #[mem_builtin] #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.add(i); - let b = *s2.add(i); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 + impls::compare_bytes(s1, s2, n) } #[mem_builtin] diff --git a/vendor/compiler_builtins/src/mem/x86_64.rs b/vendor/compiler_builtins/src/mem/x86_64.rs index a7ab6f605..17b461f79 100644 --- a/vendor/compiler_builtins/src/mem/x86_64.rs +++ b/vendor/compiler_builtins/src/mem/x86_64.rs @@ -16,6 +16,10 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::arch::asm; +use core::intrinsics; +use core::mem; + #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { @@ -31,16 +35,26 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe movsq (%rsi), (%rdi)", - "mov {byte_count:e}, %ecx", - "repe movsb (%rsi), (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep movsq", inout("rcx") qword_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep movsb", + inout("ecx") byte_count => _, inout("rdi") dest => _, inout("rsi") src => _, options(att_syntax, nostack, preserves_flags) @@ -49,22 +63,28 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { #[inline(always)] pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // We can't separate this block due to std/cld + asm!( "std", - "repe movsq (%rsi), (%rdi)", - "movl {byte_count:e}, %ecx", - "addq $7, %rdi", - "addq $7, %rsi", - "repe movsb (%rsi), (%rdi)", + "rep movsb", + "sub $7, %rsi", + "sub $7, %rdi", + "mov {qword_count}, %rcx", + "rep movsq", + "test {pre_byte_count:e}, {pre_byte_count:e}", + "add $7, %rsi", + "add $7, %rdi", + "mov {pre_byte_count:e}, %ecx", + "rep movsb", "cld", - byte_count = in(reg) byte_count, - inout("rcx") qword_count => _, - inout("rdi") dest.add(count).wrapping_sub(8) => _, - inout("rsi") src.add(count).wrapping_sub(8) => _, - options(att_syntax, nostack) + pre_byte_count = in(reg) pre_byte_count, + qword_count = in(reg) qword_count, + inout("ecx") byte_count => _, + inout("rdi") dest.add(count - 1) => _, + inout("rsi") src.add(count - 1) => _, + // We modify flags, but we restore it afterwards + options(att_syntax, nostack, preserves_flags) ); } @@ -83,18 +103,82 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe stosq %rax, (%rdi)", - "mov {byte_count:e}, %ecx", - "repe stosb %al, (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let c = c as u64 * 0x0101_0101_0101_0101; + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep stosq", inout("rcx") qword_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); + asm!( + "rep stosb", + inout("ecx") byte_count => _, inout("rdi") dest => _, - in("rax") (c as u64) * 0x0101010101010101, + in("rax") c, options(att_syntax, nostack, preserves_flags) ); } + +#[inline(always)] +pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { + #[inline(always)] + unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 + where + T: Clone + Copy + Eq, + U: Clone + Copy + Eq, + F: FnOnce(*const U, *const U, usize) -> i32, + { + // Ensure T is not a ZST. + const { assert!(mem::size_of::() != 0) }; + + let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); + while a != end { + if a.read_unaligned() != b.read_unaligned() { + return f(a.cast(), b.cast(), mem::size_of::()); + } + a = a.add(1); + b = b.add(1); + } + f( + a.cast(), + b.cast(), + intrinsics::unchecked_rem(n, mem::size_of::()), + ) + } + let c1 = |mut a: *const u8, mut b: *const u8, n| { + for _ in 0..n { + if a.read() != b.read() { + return i32::from(a.read()) - i32::from(b.read()); + } + a = a.add(1); + b = b.add(1); + } + 0 + }; + let c2 = |a: *const u16, b, n| cmp(a, b, n, c1); + let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); + let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); + let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); + c16(a.cast(), b.cast(), n) +} + +/// Determine optimal parameters for a `rep` instruction. +fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((8 - (dest as usize & 0b111)) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} diff --git a/vendor/crossbeam-channel/.cargo-checksum.json b/vendor/crossbeam-channel/.cargo-checksum.json index dd210c73b..96db2f1ab 100644 --- a/vendor/crossbeam-channel/.cargo-checksum.json +++ b/vendor/crossbeam-channel/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"704f57293fd91b9801cb8befda7622900b6f02ffe76387ea03bd7e9a041ede50","Cargo.lock":"3b56bd551cb1b7d4e733413036c67b1407ac40e4899e8a368641884e0986ce60","Cargo.toml":"d5d17d3cace2539f582aa6aa6b41c1be09e621266fd0839cdb63920db04e229a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"415a71d4978cfd338a6ae1f1b41284652eccd277a815542c304647dc437a8274","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"9538e285101c152e23c5ff6a47b0305753d94a5b27f3426499052b0e3d0f97ee","src/context.rs":"ff4d39639ddf16aaab582d4a5f3d10ef2c71afe1abbf4e60f3d9d2ddbd72c230","src/counter.rs":"c49a9f44587888850edeb62f7c8ecd1acecb39c836834254ff3ac934c478440a","src/err.rs":"44cb2024ee6b0cd6fd24996430e53720769f64b4ac35016bc3e05cb9db48681d","src/flavors/array.rs":"08e37b7c07e9a525a32cc61f89b384b897a8d852b2eda5e85ea0cf4ba7527a3f","src/flavors/at.rs":"1db64919593b7c14f838c16a22732515f1e716d2d5f6cc639f42631380e545cd","src/flavors/list.rs":"c05da598d0759b05c345050df1f6206946098203e3021260bd722f5ea24d9240","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"747da857aa1a7601641f23f4930e6ad00ebaf50456d9be5c7aa270e2ecc24dcb","src/flavors/tick.rs":"69b2dfe0186bc8b9fd7a73e32da59d2656d8150da1e00fba92a412e0907568a3","src/flavors/zero.rs":"d7e67264d7b33152f52f1d4d8cdb565334b53508f56308f72140528d0645aa73","src/lib.rs":"3a65706d4124844ffc4c8cb1f8cc779631ec94f449f85cbb68364ad3619404f1","src/select.rs":"3b00c3929d3a8973e46188db41f6ae0b47c89ab108cf7ec2cb348e272e77e132","src/select_macro.rs":"283acd04870356b0c4d3d4046c5070638b562c9ffb8fa29c1a5b90a2509bf3af","src/utils.rs":"0b6e6621198236c077fcb6b66203317e36dc8f1a157dd3b22ad422b6599ae389","src/waker.rs":"6839108d1c9357b3c0c1c162c8b4633ff5ac4f756e95e677ac1293e7df942635","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"be8176ac8f1376567f28e60c15e95b9baf8cb4c8e0e2c1de9b286a49c988dc73","tests/golang.rs":"708a4d0d94abacb2c054ac117eff79689398f76a5cb089ca188dd2b4ed53ec6b","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"0937da0413fa9ecdcba687c4c07c9b254bc82fb85cb2f836425550890c31ed36","tests/mpsc.rs":"5a49429a29c9028ade618994e82d03d4f4405b62fb89a4464ba9d89e68a1a88d","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"d349702f123925a0781b48d677e6dcf64fc5d1fc788a7bf1e151a3d57e81871c","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"e5e9308e3adcc4c99f98cd7ad5f8149ec7030845d6263e9a5a27c317aa96363f","tests/select_macro.rs":"141adb62fddc1c1973b24b0cbcf87bae06fc537be4f8fbb68e12e0864e73795c","tests/thread_locals.rs":"a1ce59e2aff69161621c0cb215eb6ea238088c06a31a8507a74cf179fd5a4299","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"54f8ee1fa8316a99457f1c6bb5a8e31c4b21d39b3b4d79b276a53c6340940c8f"},"package":"4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"} \ No newline at end of file +{"files":{"CHANGELOG.md":"f87a526ab720644e07509dd76d29c08993a5e52a6d6ec230d809fc31a1c0e403","Cargo.lock":"8af0a5f8b3d1e6f036332a5ecc91b30222343f29a465ea398bca3298c0212f4a","Cargo.toml":"81a227ee6f529cd0cf62327f63eb098fed59c04dde2a8e68aeaa0ea32dbafbcf","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"b16db96b93b1d7cf7bea533f572091ec6bca3234fbe0a83038be772ff391a44c","README.md":"4e16587d8f6a15f2016f256535aa6c9429424672ebdcd03c1a7d964746e46127","benches/crossbeam.rs":"96cb1abd23cac3ef8a7174a802e94609926b555bb02c9658c78723d433f1dd92","examples/fibonacci.rs":"4e88fa40048cdc31e9c7bb60347d46f92543d7ddf39cab3b52bfe44affdb6a02","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"d02121258f08d56f1eb7997e19bcb9bacb6836cfa0abbba90a9e59d8a50ae5cf","src/channel.rs":"9538e285101c152e23c5ff6a47b0305753d94a5b27f3426499052b0e3d0f97ee","src/context.rs":"ff4d39639ddf16aaab582d4a5f3d10ef2c71afe1abbf4e60f3d9d2ddbd72c230","src/counter.rs":"c49a9f44587888850edeb62f7c8ecd1acecb39c836834254ff3ac934c478440a","src/err.rs":"44cb2024ee6b0cd6fd24996430e53720769f64b4ac35016bc3e05cb9db48681d","src/flavors/array.rs":"508e54587fc8d9e8dfacd16446a601e33838d7bb1dfd9d7ccc3e65315b66b35a","src/flavors/at.rs":"1db64919593b7c14f838c16a22732515f1e716d2d5f6cc639f42631380e545cd","src/flavors/list.rs":"d901d9259185a71aeb5cf74be70e5c38b550c7f38b87e023196cb47fed2d1a11","src/flavors/mod.rs":"3d9d43bc38b0adb18c96c995c2bd3421d8e33ab6c30b20c3c467d21d48e485dc","src/flavors/never.rs":"747da857aa1a7601641f23f4930e6ad00ebaf50456d9be5c7aa270e2ecc24dcb","src/flavors/tick.rs":"69b2dfe0186bc8b9fd7a73e32da59d2656d8150da1e00fba92a412e0907568a3","src/flavors/zero.rs":"7458eb0ece475dc5093b4f2cde13f6de57e4f70291258850de4fa3c951c8f594","src/lib.rs":"3a65706d4124844ffc4c8cb1f8cc779631ec94f449f85cbb68364ad3619404f1","src/select.rs":"3b00c3929d3a8973e46188db41f6ae0b47c89ab108cf7ec2cb348e272e77e132","src/select_macro.rs":"283acd04870356b0c4d3d4046c5070638b562c9ffb8fa29c1a5b90a2509bf3af","src/utils.rs":"0b6e6621198236c077fcb6b66203317e36dc8f1a157dd3b22ad422b6599ae389","src/waker.rs":"6839108d1c9357b3c0c1c162c8b4633ff5ac4f756e95e677ac1293e7df942635","tests/after.rs":"0154a8e152880db17a20514ecdd49dabc361d3629858d119b9746b5e932c780c","tests/array.rs":"a57ae6264e676f573d7adb5c4b024994e98bc6811352516adb3444f880f7125e","tests/golang.rs":"284bed0d4c07857f33de96f2addc9a69c5688f864935a3e3e113c88c04bd826b","tests/iter.rs":"25dc02135bbae9d47a30f9047661648e66bdc134e40ba78bc2fbacbb8b3819bc","tests/list.rs":"3d1a4ae23bb6b4767242b8109a8efda26f1d3b28c0f90da3368f8eb9ca0eee37","tests/mpsc.rs":"d1e185c6290240132a34aa91221271225959f8652d7fc4ceb546ee9712361176","tests/never.rs":"ee40c4fc4dd5af4983fae8de6927f52b81174d222c162f745b26c4a6c7108e4f","tests/ready.rs":"d349702f123925a0781b48d677e6dcf64fc5d1fc788a7bf1e151a3d57e81871c","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"ce12a8e0284fb9ccf6c1543bec309d9054193e6d942663aed19aa8499ef69c43","tests/select_macro.rs":"597d526fbd021ce70619d9172c931439f778ee3034ec1479aea461b65971a81a","tests/thread_locals.rs":"25ab70a8dcd8a0da9173e5476e17dcc8916caa5b68207d9c403655deaa8e8f4a","tests/tick.rs":"5f697bd14c48505d932e82065b5302ef668e1cc19cac18e8ac22e0c83c221c1d","tests/zero.rs":"9c5af802d5efb2c711f8242b8905ed29cc2601e48dbd95e41c7e6fbfe2918398"},"package":"c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"} \ No newline at end of file diff --git a/vendor/crossbeam-channel/CHANGELOG.md b/vendor/crossbeam-channel/CHANGELOG.md index 2f627cf26..f0d11e60c 100644 --- a/vendor/crossbeam-channel/CHANGELOG.md +++ b/vendor/crossbeam-channel/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 0.5.6 + +- Bump the minimum supported Rust version to 1.38. (#877) + # Version 0.5.5 - Replace Spinlock with Mutex. (#835) diff --git a/vendor/crossbeam-channel/Cargo.lock b/vendor/crossbeam-channel/Cargo.lock index cd6eb056f..e40f83650 100644 --- a/vendor/crossbeam-channel/Cargo.lock +++ b/vendor/crossbeam-channel/Cargo.lock @@ -10,7 +10,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" dependencies = [ "cfg-if", "crossbeam-utils", @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "ppv-lite86" diff --git a/vendor/crossbeam-channel/Cargo.toml b/vendor/crossbeam-channel/Cargo.toml index c02f8595c..619fad423 100644 --- a/vendor/crossbeam-channel/Cargo.toml +++ b/vendor/crossbeam-channel/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2018" -rust-version = "1.36" +rust-version = "1.38" name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" description = "Multi-producer multi-consumer channels for message passing" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" readme = "README.md" diff --git a/vendor/crossbeam-channel/README.md b/vendor/crossbeam-channel/README.md index f5077c556..4c42d863c 100644 --- a/vendor/crossbeam-channel/README.md +++ b/vendor/crossbeam-channel/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel#license) https://crates.io/crates/crossbeam-channel) [![Documentation](https://docs.rs/crossbeam-channel/badge.svg)]( https://docs.rs/crossbeam-channel) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -48,7 +48,7 @@ crossbeam-channel = "0.5" Crossbeam Channel supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. +version is released. Currently, the minimum supported Rust version is 1.38. ## License diff --git a/vendor/crossbeam-channel/src/flavors/array.rs b/vendor/crossbeam-channel/src/flavors/array.rs index 73557d385..63b82eb85 100644 --- a/vendor/crossbeam-channel/src/flavors/array.rs +++ b/vendor/crossbeam-channel/src/flavors/array.rs @@ -216,7 +216,7 @@ impl Channel { return Err(msg); } - let slot: &Slot = &*(token.array.slot as *const Slot); + let slot: &Slot = &*token.array.slot.cast::>(); // Write the message into the slot and update the stamp. slot.msg.get().write(MaybeUninit::new(msg)); @@ -307,7 +307,7 @@ impl Channel { return Err(()); } - let slot: &Slot = &*(token.array.slot as *const Slot); + let slot: &Slot = &*token.array.slot.cast::>(); // Read the message from the slot and update the stamp. let msg = slot.msg.get().read().assume_init(); diff --git a/vendor/crossbeam-channel/src/flavors/list.rs b/vendor/crossbeam-channel/src/flavors/list.rs index 9bda6d1cc..6090b8d47 100644 --- a/vendor/crossbeam-channel/src/flavors/list.rs +++ b/vendor/crossbeam-channel/src/flavors/list.rs @@ -49,6 +49,11 @@ struct Slot { } impl Slot { + const UNINIT: Self = Self { + msg: UnsafeCell::new(MaybeUninit::uninit()), + state: AtomicUsize::new(0), + }; + /// Waits until a message is written into the slot. fn wait_write(&self) { let backoff = Backoff::new(); @@ -72,13 +77,10 @@ struct Block { impl Block { /// Creates an empty block. fn new() -> Block { - // SAFETY: This is safe because: - // [1] `Block::next` (AtomicPtr) may be safely zero initialized. - // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. - // [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it - // holds a MaybeUninit. - // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } + Self { + next: AtomicPtr::new(ptr::null_mut()), + slots: [Slot::UNINIT; BLOCK_CAP], + } } /// Waits until the next pointer is set. @@ -283,7 +285,7 @@ impl Channel { } // Write the message into the slot. - let block = token.list.block as *mut Block; + let block = token.list.block.cast::>(); let offset = token.list.offset; let slot = (*block).slots.get_unchecked(offset); slot.msg.get().write(MaybeUninit::new(msg)); diff --git a/vendor/crossbeam-channel/src/flavors/zero.rs b/vendor/crossbeam-channel/src/flavors/zero.rs index 31e62afac..aae2ea300 100644 --- a/vendor/crossbeam-channel/src/flavors/zero.rs +++ b/vendor/crossbeam-channel/src/flavors/zero.rs @@ -190,7 +190,7 @@ impl Channel { // heap-allocated packet. packet.wait_ready(); let msg = packet.msg.get().replace(None).unwrap(); - drop(Box::from_raw(token.zero.0 as *mut Packet)); + drop(Box::from_raw(token.zero.0.cast::>())); Ok(msg) } } @@ -409,7 +409,7 @@ impl SelectHandle for Receiver<'_, T> { let mut inner = self.0.inner.lock().unwrap(); inner .receivers - .register_with_packet(oper, packet as *mut (), cx); + .register_with_packet(oper, packet.cast::<()>(), cx); inner.senders.notify(); inner.senders.can_select() || inner.is_disconnected } @@ -417,7 +417,7 @@ impl SelectHandle for Receiver<'_, T> { fn unregister(&self, oper: Operation) { if let Some(operation) = self.0.inner.lock().unwrap().receivers.unregister(oper) { unsafe { - drop(Box::from_raw(operation.packet as *mut Packet)); + drop(Box::from_raw(operation.packet.cast::>())); } } } @@ -459,7 +459,7 @@ impl SelectHandle for Sender<'_, T> { let mut inner = self.0.inner.lock().unwrap(); inner .senders - .register_with_packet(oper, packet as *mut (), cx); + .register_with_packet(oper, packet.cast::<()>(), cx); inner.receivers.notify(); inner.receivers.can_select() || inner.is_disconnected } @@ -467,7 +467,7 @@ impl SelectHandle for Sender<'_, T> { fn unregister(&self, oper: Operation) { if let Some(operation) = self.0.inner.lock().unwrap().senders.unregister(oper) { unsafe { - drop(Box::from_raw(operation.packet as *mut Packet)); + drop(Box::from_raw(operation.packet.cast::>())); } } } diff --git a/vendor/crossbeam-channel/tests/array.rs b/vendor/crossbeam-channel/tests/array.rs index de843cd32..6fd8ffcc6 100644 --- a/vendor/crossbeam-channel/tests/array.rs +++ b/vendor/crossbeam-channel/tests/array.rs @@ -377,7 +377,7 @@ fn spsc() { #[test] fn mpmc() { #[cfg(miri)] - const COUNT: usize = 100; + const COUNT: usize = 50; #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -532,16 +532,12 @@ fn drops() { scope.spawn(|_| { for _ in 0..steps { r.recv().unwrap(); - #[cfg(miri)] - std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388 } }); scope.spawn(|_| { for _ in 0..steps { s.send(DropCounter).unwrap(); - #[cfg(miri)] - std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388 } }); }) diff --git a/vendor/crossbeam-channel/tests/golang.rs b/vendor/crossbeam-channel/tests/golang.rs index 6a46c0353..8050716c6 100644 --- a/vendor/crossbeam-channel/tests/golang.rs +++ b/vendor/crossbeam-channel/tests/golang.rs @@ -959,7 +959,7 @@ mod chan_test { #[test] fn test_chan() { #[cfg(miri)] - const N: i32 = 20; + const N: i32 = 12; #[cfg(not(miri))] const N: i32 = 200; @@ -1489,7 +1489,7 @@ mod chan_test { fn test_multi_consumer() { const NWORK: usize = 23; #[cfg(miri)] - const NITER: usize = 100; + const NITER: usize = 50; #[cfg(not(miri))] const NITER: usize = 271828; @@ -1580,9 +1580,7 @@ mod race_chan_test { } // https://github.com/golang/go/blob/master/test/ken/chan.go -#[cfg(not(miri))] // Miri is too slow mod chan { - use super::*; const MESSAGES_PER_CHANEL: u32 = 76; @@ -2052,6 +2050,7 @@ mod chan { } #[test] + #[cfg_attr(miri, ignore)] // Miri is too slow fn main() { let mut ctx = Context { nproc: Arc::new(Mutex::new(0)), diff --git a/vendor/crossbeam-channel/tests/list.rs b/vendor/crossbeam-channel/tests/list.rs index a0b908722..ebe6f6f85 100644 --- a/vendor/crossbeam-channel/tests/list.rs +++ b/vendor/crossbeam-channel/tests/list.rs @@ -67,6 +67,7 @@ fn len_empty_full() { } #[test] +#[cfg_attr(miri, ignore)] // this test makes timing assumptions, but Miri is so slow it violates them fn try_recv() { let (s, r) = unbounded(); @@ -433,8 +434,6 @@ fn drops() { scope.spawn(|_| { for _ in 0..steps { r.recv().unwrap(); - #[cfg(miri)] - std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388 } }); diff --git a/vendor/crossbeam-channel/tests/mpsc.rs b/vendor/crossbeam-channel/tests/mpsc.rs index 3db4812c6..d7cc8e25f 100644 --- a/vendor/crossbeam-channel/tests/mpsc.rs +++ b/vendor/crossbeam-channel/tests/mpsc.rs @@ -339,25 +339,22 @@ mod channel_tests { #[test] fn stress_shared() { - #[cfg(miri)] - const AMT: u32 = 100; - #[cfg(not(miri))] - const AMT: u32 = 10000; - const NTHREADS: u32 = 8; + let amt: u32 = if cfg!(miri) { 100 } else { 10_000 }; + let nthreads: u32 = if cfg!(miri) { 4 } else { 8 }; let (tx, rx) = channel::(); let t = thread::spawn(move || { - for _ in 0..AMT * NTHREADS { + for _ in 0..amt * nthreads { assert_eq!(rx.recv().unwrap(), 1); } assert!(rx.try_recv().is_err()); }); - let mut ts = Vec::with_capacity(NTHREADS as usize); - for _ in 0..NTHREADS { + let mut ts = Vec::with_capacity(nthreads as usize); + for _ in 0..nthreads { let tx = tx.clone(); let t = thread::spawn(move || { - for _ in 0..AMT { + for _ in 0..amt { tx.send(1).unwrap(); } }); diff --git a/vendor/crossbeam-channel/tests/select.rs b/vendor/crossbeam-channel/tests/select.rs index e7691f52e..bc5824dab 100644 --- a/vendor/crossbeam-channel/tests/select.rs +++ b/vendor/crossbeam-channel/tests/select.rs @@ -408,7 +408,6 @@ fn both_ready() { .unwrap(); } -#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn loop_try() { const RUNS: usize = 20; diff --git a/vendor/crossbeam-channel/tests/select_macro.rs b/vendor/crossbeam-channel/tests/select_macro.rs index 91c04e1c3..119454cd6 100644 --- a/vendor/crossbeam-channel/tests/select_macro.rs +++ b/vendor/crossbeam-channel/tests/select_macro.rs @@ -284,7 +284,6 @@ fn both_ready() { .unwrap(); } -#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn loop_try() { const RUNS: usize = 20; diff --git a/vendor/crossbeam-channel/tests/thread_locals.rs b/vendor/crossbeam-channel/tests/thread_locals.rs index effb6a143..fb4e577f2 100644 --- a/vendor/crossbeam-channel/tests/thread_locals.rs +++ b/vendor/crossbeam-channel/tests/thread_locals.rs @@ -1,6 +1,6 @@ //! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. -#![cfg(not(miri))] // error: abnormal termination: the evaluated program aborted execution +#![cfg(not(miri))] // Miri detects that this test is buggy: the destructor of `FOO` uses `std::thread::current()`! use std::thread; use std::time::Duration; diff --git a/vendor/crossbeam-channel/tests/zero.rs b/vendor/crossbeam-channel/tests/zero.rs index c90d74187..74c9a3e10 100644 --- a/vendor/crossbeam-channel/tests/zero.rs +++ b/vendor/crossbeam-channel/tests/zero.rs @@ -328,9 +328,11 @@ fn stress_oneshot() { } } -#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn stress_iter() { + #[cfg(miri)] + const COUNT: usize = 50; + #[cfg(not(miri))] const COUNT: usize = 1000; let (request_s, request_r) = bounded(0); @@ -403,7 +405,7 @@ fn drops() { #[cfg(not(miri))] const RUNS: usize = 100; #[cfg(miri)] - const STEPS: usize = 500; + const STEPS: usize = 100; #[cfg(not(miri))] const STEPS: usize = 10_000; @@ -485,7 +487,7 @@ fn fairness() { #[test] fn fairness_duplicates() { #[cfg(miri)] - const COUNT: usize = 50; + const COUNT: usize = 100; #[cfg(not(miri))] const COUNT: usize = 10_000; diff --git a/vendor/crossbeam-deque/.cargo-checksum.json b/vendor/crossbeam-deque/.cargo-checksum.json index c4f2a9329..45404d824 100644 --- a/vendor/crossbeam-deque/.cargo-checksum.json +++ b/vendor/crossbeam-deque/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"7d5f333652da0da5f068ff91ecf259599f9ff4a4448bd987dd451699b66f0f59","Cargo.toml":"a9a138b4e005ddea76f588ca7004629ebd8f1a64cd1d55474fe36cae4c57a890","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"6b0a911f542186ef96eb56537cade0ecf1a5731d5d494b7094ff87f0fdeb7710","src/deque.rs":"64a2153dc566847fd9fa0e6b2b7adb3933af9984fbe3429b6f1200b058bb9850","src/lib.rs":"9f0581481691bc698176f369410726adf597d470b9d14e226a65f490d6aff8c6","tests/fifo.rs":"1d83f9ffeeba2cd6bd32f1ab136d843b8c73075d5045619be12dc3c27d8ab3ba","tests/injector.rs":"6812c97615e3f685b5612c390861f2e570ff469f3b9871ba97ddbed5c1f5266b","tests/lifo.rs":"b2ddc8154492322e734b23f35ce54040f9ec84ef878009de3a64d44d35c365a6","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"} \ No newline at end of file +{"files":{"CHANGELOG.md":"ad5f2c10299e57aaed2d1b8f8a109faa2dfb16c52ce81f60ec5adb0ea9308d7f","Cargo.toml":"4802e7c0d5ab1dc35c162671483a6ee9bff5a3f1d6dd620a01863ac25068019e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"3c62aa0ee37cf714b5b3c304545d5caea4cc0a71020fccb1f146611d64202bb2","src/deque.rs":"cfb3c5b3bcea1f27ca2633d8b8576ff2080e1e9fc083236f2db7916bb77786ed","src/lib.rs":"ec0257a388627d691d652fd04d261c5c0590e1e31a35c8bf5912afac51fd5734","tests/fifo.rs":"3d98e0d4ca7cfddf10708b71642cf1ff05543d067ad837e48401d63cc31c0a18","tests/injector.rs":"fb054ef9fcac5f12e08b7b3451f370b96ab7589d32ef5c02e25958a473c45519","tests/lifo.rs":"57abdb3fc5920a422f785ba308b658bdc5400947532eeffb799f2395a2061549","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"} \ No newline at end of file diff --git a/vendor/crossbeam-deque/CHANGELOG.md b/vendor/crossbeam-deque/CHANGELOG.md index 14dcc20b7..855b714f4 100644 --- a/vendor/crossbeam-deque/CHANGELOG.md +++ b/vendor/crossbeam-deque/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 0.8.2 + +- Bump the minimum supported Rust version to 1.38. (#877) + # Version 0.8.1 - Fix deque steal race condition. (#726) @@ -5,26 +9,40 @@ # Version 0.8.0 +**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. + - Bump the minimum supported Rust version to 1.36. - Add `Worker::len()` and `Injector::len()` methods. - Add `std` (enabled by default) feature for forward compatibility. +# Version 0.7.4 + +- Fix deque steal race condition. + # Version 0.7.3 +**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. + - Stop stealing from the same deque. (#448) - Fix unsoundness issues by adopting `MaybeUninit`. (#458) # Version 0.7.2 +**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. + - Bump `crossbeam-epoch` to `0.8`. - Bump `crossbeam-utils` to `0.7`. # Version 0.7.1 +**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. + - Bump the minimum required version of `crossbeam-utils`. # Version 0.7.0 +**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. + - Make `Worker::pop()` faster in the FIFO case. - Replace `fifo()` nad `lifo()` with `Worker::new_fifo()` and `Worker::new_lifo()`. - Add more batched steal methods. diff --git a/vendor/crossbeam-deque/Cargo.toml b/vendor/crossbeam-deque/Cargo.toml index 3ea5a59f6..4ff10b353 100644 --- a/vendor/crossbeam-deque/Cargo.toml +++ b/vendor/crossbeam-deque/Cargo.toml @@ -11,16 +11,26 @@ [package] edition = "2018" +rust-version = "1.38" name = "crossbeam-deque" -version = "0.8.1" -authors = ["The Crossbeam Project Developers"] +version = "0.8.2" description = "Concurrent work-stealing deque" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque" -documentation = "https://docs.rs/crossbeam-deque" -keywords = ["chase-lev", "lock-free", "scheduler", "scheduling"] -categories = ["algorithms", "concurrency", "data-structures"] +readme = "README.md" +keywords = [ + "chase-lev", + "lock-free", + "scheduler", + "scheduling", +] +categories = [ + "algorithms", + "concurrency", + "data-structures", +] license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" + [dependencies.cfg-if] version = "1" @@ -33,9 +43,13 @@ default-features = false version = "0.8" optional = true default-features = false + [dev-dependencies.rand] version = "0.8" [features] default = ["std"] -std = ["crossbeam-epoch/std", "crossbeam-utils/std"] +std = [ + "crossbeam-epoch/std", + "crossbeam-utils/std", +] diff --git a/vendor/crossbeam-deque/README.md b/vendor/crossbeam-deque/README.md index 8ad1a7278..23c8794c2 100644 --- a/vendor/crossbeam-deque/README.md +++ b/vendor/crossbeam-deque/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque#license) https://crates.io/crates/crossbeam-deque) [![Documentation](https://docs.rs/crossbeam-deque/badge.svg)]( https://docs.rs/crossbeam-deque) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -28,7 +28,7 @@ crossbeam-deque = "0.8" Crossbeam Deque supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. +version is released. Currently, the minimum supported Rust version is 1.38. ## License diff --git a/vendor/crossbeam-deque/src/deque.rs b/vendor/crossbeam-deque/src/deque.rs index 802a2fef5..bda3bf820 100644 --- a/vendor/crossbeam-deque/src/deque.rs +++ b/vendor/crossbeam-deque/src/deque.rs @@ -3,7 +3,7 @@ use std::cmp; use std::fmt; use std::iter::FromIterator; use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; +use std::mem::{self, ManuallyDrop, MaybeUninit}; use std::ptr; use std::sync::atomic::{self, AtomicIsize, AtomicPtr, AtomicUsize, Ordering}; use std::sync::Arc; @@ -38,9 +38,8 @@ impl Buffer { fn alloc(cap: usize) -> Buffer { debug_assert_eq!(cap, cap.next_power_of_two()); - let mut v = Vec::with_capacity(cap); + let mut v = ManuallyDrop::new(Vec::with_capacity(cap)); let ptr = v.as_mut_ptr(); - mem::forget(v); Buffer { ptr, cap } } @@ -53,6 +52,8 @@ impl Buffer { /// Returns a pointer to the task at the specified `index`. unsafe fn at(&self, index: isize) -> *mut T { // `self.cap` is always a power of two. + // We do all the loads at `MaybeUninit` because we might realize, after loading, that we + // don't actually have the right to access this memory. self.ptr.offset(index & (self.cap - 1) as isize) } @@ -62,8 +63,8 @@ impl Buffer { /// technically speaking a data race and therefore UB. We should use an atomic store here, but /// that would be more expensive and difficult to implement generically for all types `T`. /// Hence, as a hack, we use a volatile write instead. - unsafe fn write(&self, index: isize, task: T) { - ptr::write_volatile(self.at(index), task) + unsafe fn write(&self, index: isize, task: MaybeUninit) { + ptr::write_volatile(self.at(index).cast::>(), task) } /// Reads a task from the specified `index`. @@ -71,9 +72,9 @@ impl Buffer { /// This method might be concurrently called with another `write` at the same index, which is /// technically speaking a data race and therefore UB. We should use an atomic load here, but /// that would be more expensive and difficult to implement generically for all types `T`. - /// Hence, as a hack, we use a volatile write instead. - unsafe fn read(&self, index: isize) -> T { - ptr::read_volatile(self.at(index)) + /// Hence, as a hack, we use a volatile load instead. + unsafe fn read(&self, index: isize) -> MaybeUninit { + ptr::read_volatile(self.at(index).cast::>()) } } @@ -115,8 +116,8 @@ struct Inner { impl Drop for Inner { fn drop(&mut self) { // Load the back index, front index, and buffer. - let b = self.back.load(Ordering::Relaxed); - let f = self.front.load(Ordering::Relaxed); + let b = *self.back.get_mut(); + let f = *self.front.get_mut(); unsafe { let buffer = self.buffer.load(Ordering::Relaxed, epoch::unprotected()); @@ -406,7 +407,7 @@ impl Worker { // Write `task` into the slot. unsafe { - buffer.write(b, task); + buffer.write(b, MaybeUninit::new(task)); } atomic::fence(Ordering::Release); @@ -461,7 +462,7 @@ impl Worker { unsafe { // Read the popped task. let buffer = self.buffer.get(); - let task = buffer.read(f); + let task = buffer.read(f).assume_init(); // Shrink the buffer if `len - 1` is less than one fourth of the capacity. if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 { @@ -509,8 +510,8 @@ impl Worker { ) .is_err() { - // Failed. We didn't pop anything. - mem::forget(task.take()); + // Failed. We didn't pop anything. Reset to `None`. + task.take(); } // Restore the back index to the original task. @@ -524,7 +525,7 @@ impl Worker { } } - task + task.map(|t| unsafe { t.assume_init() }) } } } @@ -661,12 +662,11 @@ impl Stealer { .is_err() { // We didn't steal this task, forget it. - mem::forget(task); return Steal::Retry; } // Return the stolen task. - Steal::Success(task) + Steal::Success(unsafe { task.assume_init() }) } /// Steals a batch of tasks and pushes them into another worker. @@ -821,7 +821,6 @@ impl Stealer { .is_err() { // We didn't steal this task, forget it and break from the loop. - mem::forget(task); batch_size = i; break; } @@ -975,7 +974,6 @@ impl Stealer { .is_err() { // We didn't steal this task, forget it. - mem::forget(task); return Steal::Retry; } @@ -992,7 +990,6 @@ impl Stealer { .is_err() { // We didn't steal this task, forget it. - mem::forget(task); return Steal::Retry; } @@ -1037,7 +1034,6 @@ impl Stealer { .is_err() { // We didn't steal this task, forget it and break from the loop. - mem::forget(tmp); batch_size = i; break; } @@ -1077,7 +1073,7 @@ impl Stealer { dest.inner.back.store(dest_b, Ordering::Release); // Return with success. - Steal::Success(task) + Steal::Success(unsafe { task.assume_init() }) } } @@ -1123,6 +1119,11 @@ struct Slot { } impl Slot { + const UNINIT: Self = Self { + task: UnsafeCell::new(MaybeUninit::uninit()), + state: AtomicUsize::new(0), + }; + /// Waits until a task is written into the slot. fn wait_write(&self) { let backoff = Backoff::new(); @@ -1146,13 +1147,10 @@ struct Block { impl Block { /// Creates an empty block that starts at `start_index`. fn new() -> Block { - // SAFETY: This is safe because: - // [1] `Block::next` (AtomicPtr) may be safely zero initialized. - // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. - // [3] `Slot::task` (UnsafeCell) may be safely zero initialized because it - // holds a MaybeUninit. - // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } + Self { + next: AtomicPtr::new(ptr::null_mut()), + slots: [Slot::UNINIT; BLOCK_CAP], + } } /// Waits until the next pointer is set. @@ -1535,7 +1533,7 @@ impl Injector { // Read the task. let slot = (*block).slots.get_unchecked(offset + i); slot.wait_write(); - let task = slot.task.get().read().assume_init(); + let task = slot.task.get().read(); // Write it into the destination queue. dest_buffer.write(dest_b.wrapping_add(i as isize), task); @@ -1547,7 +1545,7 @@ impl Injector { // Read the task. let slot = (*block).slots.get_unchecked(offset + i); slot.wait_write(); - let task = slot.task.get().read().assume_init(); + let task = slot.task.get().read(); // Write it into the destination queue. dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); @@ -1689,7 +1687,7 @@ impl Injector { // Read the task. let slot = (*block).slots.get_unchecked(offset); slot.wait_write(); - let task = slot.task.get().read().assume_init(); + let task = slot.task.get().read(); match dest.flavor { Flavor::Fifo => { @@ -1698,7 +1696,7 @@ impl Injector { // Read the task. let slot = (*block).slots.get_unchecked(offset + i + 1); slot.wait_write(); - let task = slot.task.get().read().assume_init(); + let task = slot.task.get().read(); // Write it into the destination queue. dest_buffer.write(dest_b.wrapping_add(i as isize), task); @@ -1711,7 +1709,7 @@ impl Injector { // Read the task. let slot = (*block).slots.get_unchecked(offset + i + 1); slot.wait_write(); - let task = slot.task.get().read().assume_init(); + let task = slot.task.get().read(); // Write it into the destination queue. dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); @@ -1744,7 +1742,7 @@ impl Injector { } } - Steal::Success(task) + Steal::Success(task.assume_init()) } } @@ -1820,9 +1818,9 @@ impl Injector { impl Drop for Injector { fn drop(&mut self) { - let mut head = self.head.index.load(Ordering::Relaxed); - let mut tail = self.tail.index.load(Ordering::Relaxed); - let mut block = self.head.block.load(Ordering::Relaxed); + let mut head = *self.head.index.get_mut(); + let mut tail = *self.tail.index.get_mut(); + let mut block = *self.head.block.get_mut(); // Erase the lower bits. head &= !((1 << SHIFT) - 1); @@ -1840,7 +1838,7 @@ impl Drop for Injector { p.as_mut_ptr().drop_in_place(); } else { // Deallocate the block and move to the next one. - let next = (*block).next.load(Ordering::Relaxed); + let next = *(*block).next.get_mut(); drop(Box::from_raw(block)); block = next; } diff --git a/vendor/crossbeam-deque/src/lib.rs b/vendor/crossbeam-deque/src/lib.rs index 16bc728b3..b696b5f96 100644 --- a/vendor/crossbeam-deque/src/lib.rs +++ b/vendor/crossbeam-deque/src/lib.rs @@ -95,6 +95,7 @@ rust_2018_idioms, unreachable_pub )] +#![allow(clippy::question_mark)] // https://github.com/rust-lang/rust-clippy/issues/8281 #![cfg_attr(not(feature = "std"), no_std)] use cfg_if::cfg_if; diff --git a/vendor/crossbeam-deque/tests/fifo.rs b/vendor/crossbeam-deque/tests/fifo.rs index e2365fb91..f98737b58 100644 --- a/vendor/crossbeam-deque/tests/fifo.rs +++ b/vendor/crossbeam-deque/tests/fifo.rs @@ -71,6 +71,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const STEPS: usize = 500; + #[cfg(not(miri))] const STEPS: usize = 50_000; let w = Worker::new_fifo(); @@ -100,6 +103,9 @@ fn spsc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_fifo(); @@ -141,6 +147,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_fifo(); @@ -197,6 +206,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -258,8 +268,17 @@ fn no_starvation() { #[test] fn destructors() { + #[cfg(miri)] + const THREADS: usize = 2; + #[cfg(not(miri))] const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; + #[cfg(miri)] + const STEPS: usize = 100; + #[cfg(not(miri))] const STEPS: usize = 1000; struct Elem(usize, Arc>>); @@ -330,7 +349,7 @@ fn destructors() { { let mut v = dropped.lock().unwrap(); assert_eq!(v.len(), rem); - v.sort(); + v.sort_unstable(); for pair in v.windows(2) { assert_eq!(pair[0] + 1, pair[1]); } diff --git a/vendor/crossbeam-deque/tests/injector.rs b/vendor/crossbeam-deque/tests/injector.rs index 3f74d1bfb..f706a8d9c 100644 --- a/vendor/crossbeam-deque/tests/injector.rs +++ b/vendor/crossbeam-deque/tests/injector.rs @@ -46,6 +46,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; let q = Injector::new(); @@ -58,6 +61,8 @@ fn spsc() { assert_eq!(i, v); break; } + #[cfg(miri)] + std::hint::spin_loop(); } } @@ -73,6 +78,9 @@ fn spsc() { #[test] fn mpmc() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -96,6 +104,8 @@ fn mpmc() { v[n].fetch_add(1, SeqCst); break; } + #[cfg(miri)] + std::hint::spin_loop(); } } }); @@ -111,6 +121,9 @@ fn mpmc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let q = Injector::new(); @@ -152,6 +165,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let q = Injector::new(); @@ -208,6 +224,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -269,8 +286,17 @@ fn no_starvation() { #[test] fn destructors() { + #[cfg(miri)] + const THREADS: usize = 2; + #[cfg(not(miri))] const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; + #[cfg(miri)] + const STEPS: usize = 100; + #[cfg(not(miri))] const STEPS: usize = 1000; struct Elem(usize, Arc>>); @@ -341,7 +367,7 @@ fn destructors() { { let mut v = dropped.lock().unwrap(); assert_eq!(v.len(), rem); - v.sort(); + v.sort_unstable(); for pair in v.windows(2) { assert_eq!(pair[0] + 1, pair[1]); } diff --git a/vendor/crossbeam-deque/tests/lifo.rs b/vendor/crossbeam-deque/tests/lifo.rs index 3e99e95c5..c1a65cd2e 100644 --- a/vendor/crossbeam-deque/tests/lifo.rs +++ b/vendor/crossbeam-deque/tests/lifo.rs @@ -71,6 +71,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const STEPS: usize = 500; + #[cfg(not(miri))] const STEPS: usize = 50_000; let w = Worker::new_lifo(); @@ -84,6 +87,8 @@ fn spsc() { assert_eq!(i, v); break; } + #[cfg(miri)] + std::hint::spin_loop(); } } @@ -100,6 +105,9 @@ fn spsc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_lifo(); @@ -141,6 +149,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_lifo(); @@ -197,6 +208,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -258,8 +270,17 @@ fn no_starvation() { #[test] fn destructors() { + #[cfg(miri)] + const THREADS: usize = 2; + #[cfg(not(miri))] const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; + #[cfg(miri)] + const STEPS: usize = 100; + #[cfg(not(miri))] const STEPS: usize = 1000; struct Elem(usize, Arc>>); @@ -330,7 +351,7 @@ fn destructors() { { let mut v = dropped.lock().unwrap(); assert_eq!(v.len(), rem); - v.sort(); + v.sort_unstable(); for pair in v.windows(2) { assert_eq!(pair[0] + 1, pair[1]); } diff --git a/vendor/crossbeam-epoch/.cargo-checksum.json b/vendor/crossbeam-epoch/.cargo-checksum.json index beb3eb1dd..21e5f8500 100644 --- a/vendor/crossbeam-epoch/.cargo-checksum.json +++ b/vendor/crossbeam-epoch/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"709c5824af9170953e84db2552f4e8ae84d115314b59b768c62bdcd13c157e82","Cargo.lock":"cd480e52977de5a2e4182c1620fb5da9134fe82bfc6f696905ec0a1e1bd3d039","Cargo.toml":"1506e2615575ffc45c05dbcc248687740f04de5732b30bdb2d828ef4c4ae809b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"f946b25082979595d3851d90c4e76424be921a779e88e982f8455d44d46057ec","benches/defer.rs":"c330b704d96b2ad1aed29f72c37a99da534adef8cb06a3976d5f93bf567abb20","benches/flush.rs":"0389ac6c473632f0e93c962f223404cc360257f6699b4ec90b9b3be16bb6d74f","benches/pin.rs":"2f649a5153745c7930efdb32a52f9dc522f7b8cf548a251c5e2c82ee25dc3fff","build.rs":"aec5ae4d47d6ab1f281db6b7f7ec80ab3cc05bd0c20059643aee4446fcc0fcbf","examples/sanitize.rs":"a39d1635fa61e643e59192d7a63becc97ff81f03c1f4e03d38cedefb1525026a","no_atomic.rs":"916ed15218bb7b75a4e0d432430e7134efd27ca43ca8a8766e0c90e89febb602","src/atomic.rs":"6452c856fd808e99c8fc09fe7b563ce44342f9992b38c65613933c7c3fc5d84c","src/collector.rs":"e2d9780d8707e49360b3c33f2f829f29f70e6929307e65e23449b8ba6def6358","src/default.rs":"9c4d3951981d47efc748674d64b22eff27ecb2e3ef16369aa423592740ce6033","src/deferred.rs":"8ced786536d8d688381a8aa0b61e6e4d5e4fdd88e892cf82c0c5731e4801aa60","src/epoch.rs":"d31e66d8fe62299928e25867336d96391b26a4fe890a1cae0885dfcf36d6835b","src/guard.rs":"55c56ca1b2fbc067ae21108f0f7de4be91e5b41df2492055b635ed436782dd52","src/internal.rs":"67a6811b8c58e1152fd1dc17e389884025a0d99d79ab03dee26efcd0d6896690","src/lib.rs":"1c0765413dd66d4655e6417a69829ac5c2f4d504f66f77a87fe9c230c05e039d","src/sync/list.rs":"10aa4c59845ab9ff1d8bcb6f594b70bbe23c320fa7a2b125fdf85df88b9d61e2","src/sync/mod.rs":"cbc6334460d73761c3dea7f99ed2ccbf267d5da3bc76c812e94f85c9f4565c6a","src/sync/queue.rs":"06173b2255677d0d39178ceb49876fda2878f491e907c595eb65643dbb43c9ba","tests/loom.rs":"db772f4478966de6ec98774ca4093171dc942da635822a0d2d3257d31188cb9b"},"package":"07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"} \ No newline at end of file +{"files":{"CHANGELOG.md":"4a701ed7814fbde912aa7a1d15c95ed6b7ba3cd661c64f92c17b3b8bf67ecf5e","Cargo.lock":"018d954edeff6a45c6af01735239b639a83eed8258176481c6e9dae366085760","Cargo.toml":"4c1451a736e2ec0b31dfe6080140b69fdc614a0606db876308f1badf932dc1b9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"d67d0cf57751a019707dd95785345ee181a10ea80237789bc3c19bf28c0d45ca","benches/defer.rs":"c330b704d96b2ad1aed29f72c37a99da534adef8cb06a3976d5f93bf567abb20","benches/flush.rs":"0389ac6c473632f0e93c962f223404cc360257f6699b4ec90b9b3be16bb6d74f","benches/pin.rs":"2f649a5153745c7930efdb32a52f9dc522f7b8cf548a251c5e2c82ee25dc3fff","build.rs":"89e236e4e22dd748720129dcd02edfc08adccf708a7f0b03e41780e5bafb39cc","examples/sanitize.rs":"a39d1635fa61e643e59192d7a63becc97ff81f03c1f4e03d38cedefb1525026a","no_atomic.rs":"916ed15218bb7b75a4e0d432430e7134efd27ca43ca8a8766e0c90e89febb602","src/atomic.rs":"1bd4275c1411852024533e8a70959dfedf72029e3253544d1fbb0cc18b6fd519","src/collector.rs":"29e5911f61510247659b0090517bd1a38d11e1ed86e35811603cb599962d9a58","src/default.rs":"9c4d3951981d47efc748674d64b22eff27ecb2e3ef16369aa423592740ce6033","src/deferred.rs":"0c87df5797212778edd3c2d5fcf0cc04e8b9ed100261ecf9522f74a90804a3d5","src/epoch.rs":"d31e66d8fe62299928e25867336d96391b26a4fe890a1cae0885dfcf36d6835b","src/guard.rs":"f4439909152d38c03b6dfb6eeba6c9f07c39962187d461c92a492c27c258670b","src/internal.rs":"ac40ce276f0ed3dfd561926b78f775592eabb90790e177edde41fe50c13b8256","src/lib.rs":"1c0765413dd66d4655e6417a69829ac5c2f4d504f66f77a87fe9c230c05e039d","src/sync/list.rs":"10aa4c59845ab9ff1d8bcb6f594b70bbe23c320fa7a2b125fdf85df88b9d61e2","src/sync/mod.rs":"cbc6334460d73761c3dea7f99ed2ccbf267d5da3bc76c812e94f85c9f4565c6a","src/sync/queue.rs":"06173b2255677d0d39178ceb49876fda2878f491e907c595eb65643dbb43c9ba","tests/loom.rs":"db772f4478966de6ec98774ca4093171dc942da635822a0d2d3257d31188cb9b"},"package":"045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"} \ No newline at end of file diff --git a/vendor/crossbeam-epoch/CHANGELOG.md b/vendor/crossbeam-epoch/CHANGELOG.md index 2f70edba7..b05a52dfc 100644 --- a/vendor/crossbeam-epoch/CHANGELOG.md +++ b/vendor/crossbeam-epoch/CHANGELOG.md @@ -1,3 +1,9 @@ +# Version 0.9.10 + +- Bump the minimum supported Rust version to 1.38. (#877) +- Mitigate the risk of segmentation faults in buggy downstream implementations. (#879) +- Add `{Atomic, Shared}::try_into_owned` (#701) + # Version 0.9.9 - Replace lazy_static with once_cell. (#817) diff --git a/vendor/crossbeam-epoch/Cargo.lock b/vendor/crossbeam-epoch/Cargo.lock index edb0c7378..726980a93 100644 --- a/vendor/crossbeam-epoch/Cargo.lock +++ b/vendor/crossbeam-epoch/Cargo.lock @@ -31,7 +31,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.10" dependencies = [ "autocfg", "cfg-if", @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "loom", @@ -57,15 +57,15 @@ dependencies = [ [[package]] name = "generator" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" +checksum = "cc184cace1cea8335047a471cc1da80f18acf8a76f3bab2028d499e328948ec7" dependencies = [ "cc", "libc", "log", "rustversion", - "winapi", + "windows", ] [[package]] @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "pin-project-lite" @@ -151,18 +151,18 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "regex-syntax", ] @@ -217,15 +217,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" [[package]] name = "scoped-tls" @@ -250,15 +250,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "syn" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -299,9 +299,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ "once_cell", "valuable", @@ -320,13 +320,13 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.11" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ "ansi_term", - "lazy_static", "matchers", + "once_cell", "regex", "sharded-slab", "smallvec", @@ -338,9 +338,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" [[package]] name = "valuable" @@ -375,3 +375,46 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbedf6db9096bc2364adce0ae0aa636dcd89f3c3f2cd67947062aaf0ca2a10ec" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" diff --git a/vendor/crossbeam-epoch/Cargo.toml b/vendor/crossbeam-epoch/Cargo.toml index 9d68295e6..1551c3c2c 100644 --- a/vendor/crossbeam-epoch/Cargo.toml +++ b/vendor/crossbeam-epoch/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2018" -rust-version = "1.36" +rust-version = "1.38" name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.10" description = "Epoch-based garbage collection" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch" readme = "README.md" diff --git a/vendor/crossbeam-epoch/README.md b/vendor/crossbeam-epoch/README.md index eb33badff..2840ea792 100644 --- a/vendor/crossbeam-epoch/README.md +++ b/vendor/crossbeam-epoch/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch#license) https://crates.io/crates/crossbeam-epoch) [![Documentation](https://docs.rs/crossbeam-epoch/badge.svg)]( https://docs.rs/crossbeam-epoch) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -35,7 +35,7 @@ crossbeam-epoch = "0.9" Crossbeam Epoch supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. +version is released. Currently, the minimum supported Rust version is 1.38. ## License diff --git a/vendor/crossbeam-epoch/build.rs b/vendor/crossbeam-epoch/build.rs index bba54d999..b3bd15a5a 100644 --- a/vendor/crossbeam-epoch/build.rs +++ b/vendor/crossbeam-epoch/build.rs @@ -41,17 +41,15 @@ fn main() { } }; - // Note that this is `no_*`, not `has_*`. This allows treating - // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't - // run. This is needed for compatibility with non-cargo build systems that - // don't run the build script. + // Note that this is `no_`*, not `has_*`. This allows treating as the latest + // stable rustc is used when the build script doesn't run. This is useful + // for non-cargo build systems that don't run the build script. if NO_ATOMIC_CAS.contains(&&*target) { println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); } - if cfg.probe_rustc_version(1, 61) { - // TODO: invert cfg once Rust 1.61 became stable. - println!("cargo:rustc-cfg=crossbeam_const_fn_trait_bound"); + if !cfg.probe_rustc_version(1, 61) { + println!("cargo:rustc-cfg=crossbeam_no_const_fn_trait_bound"); } println!("cargo:rerun-if-changed=no_atomic.rs"); diff --git a/vendor/crossbeam-epoch/src/atomic.rs b/vendor/crossbeam-epoch/src/atomic.rs index b0b6a68e7..19bab4729 100644 --- a/vendor/crossbeam-epoch/src/atomic.rs +++ b/vendor/crossbeam-epoch/src/atomic.rs @@ -252,7 +252,7 @@ impl Pointable for [MaybeUninit] { let size = mem::size_of::>() + mem::size_of::>() * len; let align = mem::align_of::>(); let layout = alloc::Layout::from_size_align(size, align).unwrap(); - let ptr = alloc::alloc(layout) as *mut Array; + let ptr = alloc::alloc(layout).cast::>(); if ptr.is_null() { alloc::handle_alloc_error(layout); } @@ -305,6 +305,7 @@ impl Atomic { /// use crossbeam_epoch::Atomic; /// /// let a = Atomic::new(1234); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn new(init: T) -> Atomic { Self::init(init) @@ -320,6 +321,7 @@ impl Atomic { /// use crossbeam_epoch::Atomic; /// /// let a = Atomic::::init(1234); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn init(init: T::Init) -> Atomic { Self::from(Owned::init(init)) @@ -342,7 +344,7 @@ impl Atomic { /// /// let a = Atomic::::null(); /// ``` - #[cfg(all(crossbeam_const_fn_trait_bound, not(crossbeam_loom)))] + #[cfg(all(not(crossbeam_no_const_fn_trait_bound), not(crossbeam_loom)))] pub const fn null() -> Atomic { Self { data: AtomicUsize::new(0), @@ -351,7 +353,7 @@ impl Atomic { } /// Returns a new null atomic pointer. - #[cfg(not(all(crossbeam_const_fn_trait_bound, not(crossbeam_loom))))] + #[cfg(not(all(not(crossbeam_no_const_fn_trait_bound), not(crossbeam_loom))))] pub fn null() -> Atomic { Self { data: AtomicUsize::new(0), @@ -373,6 +375,7 @@ impl Atomic { /// let a = Atomic::new(1234); /// let guard = &epoch::pin(); /// let p = a.load(SeqCst, guard); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn load<'g>(&self, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { unsafe { Shared::from_usize(self.data.load(ord)) } @@ -398,6 +401,7 @@ impl Atomic { /// let a = Atomic::new(1234); /// let guard = &epoch::pin(); /// let p = a.load_consume(guard); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn load_consume<'g>(&self, _: &'g Guard) -> Shared<'g, T> { unsafe { Shared::from_usize(self.data.load_consume()) } @@ -415,8 +419,10 @@ impl Atomic { /// use std::sync::atomic::Ordering::SeqCst; /// /// let a = Atomic::new(1234); + /// # unsafe { drop(a.load(SeqCst, &crossbeam_epoch::pin()).into_owned()); } // avoid leak /// a.store(Shared::null(), SeqCst); /// a.store(Owned::new(1234), SeqCst); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn store>(&self, new: P, ord: Ordering) { self.data.store(new.into_usize(), ord); @@ -437,6 +443,7 @@ impl Atomic { /// let a = Atomic::new(1234); /// let guard = &epoch::pin(); /// let p = a.swap(Shared::null(), SeqCst, guard); + /// # unsafe { drop(p.into_owned()); } // avoid leak /// ``` pub fn swap<'g, P: Pointer>(&self, new: P, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { unsafe { Shared::from_usize(self.data.swap(new.into_usize(), ord)) } @@ -471,6 +478,7 @@ impl Atomic { /// let curr = a.load(SeqCst, guard); /// let res1 = a.compare_exchange(curr, Shared::null(), SeqCst, SeqCst, guard); /// let res2 = a.compare_exchange(curr, Owned::new(5678), SeqCst, SeqCst, guard); + /// # unsafe { drop(curr.into_owned()); } // avoid leak /// ``` pub fn compare_exchange<'g, P>( &self, @@ -526,6 +534,7 @@ impl Atomic { /// /// let mut new = Owned::new(5678); /// let mut ptr = a.load(SeqCst, guard); + /// # unsafe { drop(a.load(SeqCst, guard).into_owned()); } // avoid leak /// loop { /// match a.compare_exchange_weak(ptr, new, SeqCst, SeqCst, guard) { /// Ok(p) => { @@ -546,6 +555,7 @@ impl Atomic { /// Err(err) => curr = err.current, /// } /// } + /// # unsafe { drop(curr.into_owned()); } // avoid leak /// ``` pub fn compare_exchange_weak<'g, P>( &self, @@ -608,6 +618,7 @@ impl Atomic { /// /// let res2 = a.fetch_update(SeqCst, SeqCst, guard, |x| None); /// assert!(res2.is_err()); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn fetch_update<'g, F>( &self, @@ -666,6 +677,7 @@ impl Atomic { /// let curr = a.load(SeqCst, guard); /// let res1 = a.compare_and_set(curr, Shared::null(), SeqCst, guard); /// let res2 = a.compare_and_set(curr, Owned::new(5678), SeqCst, guard); + /// # unsafe { drop(curr.into_owned()); } // avoid leak /// ``` // TODO: remove in the next major version. #[allow(deprecated)] @@ -723,6 +735,7 @@ impl Atomic { /// /// let mut new = Owned::new(5678); /// let mut ptr = a.load(SeqCst, guard); + /// # unsafe { drop(a.load(SeqCst, guard).into_owned()); } // avoid leak /// loop { /// match a.compare_and_set_weak(ptr, new, SeqCst, guard) { /// Ok(p) => { @@ -743,6 +756,7 @@ impl Atomic { /// Err(err) => curr = err.current, /// } /// } + /// # unsafe { drop(curr.into_owned()); } // avoid leak /// ``` // TODO: remove in the next major version. #[allow(deprecated)] @@ -877,6 +891,52 @@ impl Atomic { Owned::from_usize(self.data.into_inner()) } } + + /// Takes ownership of the pointee if it is non-null. + /// + /// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a + /// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for + /// destructors of data structures. + /// + /// # Safety + /// + /// This method may be called only if the pointer is valid and nobody else is holding a + /// reference to the same object, or the pointer is null. + /// + /// # Examples + /// + /// ```rust + /// # use std::mem; + /// # use crossbeam_epoch::Atomic; + /// struct DataStructure { + /// ptr: Atomic, + /// } + /// + /// impl Drop for DataStructure { + /// fn drop(&mut self) { + /// // By now the DataStructure lives only in our thread and we are sure we don't hold + /// // any Shared or & to it ourselves, but it may be null, so we have to be careful. + /// let old = mem::replace(&mut self.ptr, Atomic::null()); + /// unsafe { + /// if let Some(x) = old.try_into_owned() { + /// drop(x) + /// } + /// } + /// } + /// } + /// ``` + pub unsafe fn try_into_owned(self) -> Option> { + // FIXME: See self.into_owned() + #[cfg(crossbeam_loom)] + let data = self.data.unsync_load(); + #[cfg(not(crossbeam_loom))] + let data = self.data.into_inner(); + if decompose_tag::(data).0 == 0 { + None + } else { + Some(Owned::from_usize(data)) + } + } } impl fmt::Debug for Atomic { @@ -925,6 +985,7 @@ impl From> for Atomic { /// use crossbeam_epoch::{Atomic, Owned}; /// /// let a = Atomic::::from(Owned::new(1234)); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` fn from(owned: Owned) -> Self { let data = owned.data; @@ -1108,6 +1169,7 @@ impl Owned { /// let o = Owned::new(1234); /// let guard = &epoch::pin(); /// let p = o.into_shared(guard); + /// # unsafe { drop(p.into_owned()); } // avoid leak /// ``` #[allow(clippy::needless_lifetimes)] pub fn into_shared<'g>(self, _: &'g Guard) -> Shared<'g, T> { @@ -1291,6 +1353,7 @@ impl<'g, T> Shared<'g, T> { /// let guard = &epoch::pin(); /// let p = a.load(SeqCst, guard); /// assert_eq!(p.as_raw(), raw); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn as_raw(&self) -> *const T { let (raw, _) = decompose_tag::(self.data); @@ -1329,6 +1392,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// assert!(a.load(SeqCst, guard).is_null()); /// a.store(Owned::new(1234), SeqCst); /// assert!(!a.load(SeqCst, guard).is_null()); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn is_null(&self) -> bool { let (raw, _) = decompose_tag::(self.data); @@ -1365,6 +1429,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// unsafe { /// assert_eq!(p.deref(), &1234); /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub unsafe fn deref(&self) -> &'g T { let (raw, _) = decompose_tag::(self.data); @@ -1406,6 +1471,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// unsafe { /// assert_eq!(p.deref(), &vec![1, 2, 3, 4, 5]); /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub unsafe fn deref_mut(&mut self) -> &'g mut T { let (raw, _) = decompose_tag::(self.data); @@ -1442,6 +1508,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// unsafe { /// assert_eq!(p.as_ref(), Some(&1234)); /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub unsafe fn as_ref(&self) -> Option<&'g T> { let (raw, _) = decompose_tag::(self.data); @@ -1481,6 +1548,36 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { Owned::from_usize(self.data) } + /// Takes ownership of the pointee if it is not null. + /// + /// # Safety + /// + /// This method may be called only if the pointer is valid and nobody else is holding a + /// reference to the same object, or if the pointer is null. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// unsafe { + /// let guard = &epoch::unprotected(); + /// let p = a.load(SeqCst, guard); + /// if let Some(x) = p.try_into_owned() { + /// drop(x); + /// } + /// } + /// ``` + pub unsafe fn try_into_owned(self) -> Option> { + if self.is_null() { + None + } else { + Some(Owned::from_usize(self.data)) + } + } + /// Returns the tag stored within the pointer. /// /// # Examples @@ -1493,6 +1590,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// let guard = &epoch::pin(); /// let p = a.load(SeqCst, guard); /// assert_eq!(p.tag(), 2); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn tag(&self) -> usize { let (_, tag) = decompose_tag::(self.data); @@ -1516,6 +1614,7 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> { /// assert_eq!(p1.tag(), 0); /// assert_eq!(p2.tag(), 2); /// assert_eq!(p1.as_raw(), p2.as_raw()); + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn with_tag(&self, tag: usize) -> Shared<'g, T> { unsafe { Self::from_usize(compose_tag::(self.data, tag)) } @@ -1536,6 +1635,7 @@ impl From<*const T> for Shared<'_, T> { /// /// let p = Shared::from(Box::into_raw(Box::new(1234)) as *const _); /// assert!(!p.is_null()); + /// # unsafe { drop(p.into_owned()); } // avoid leak /// ``` fn from(raw: *const T) -> Self { let raw = raw as usize; @@ -1612,7 +1712,7 @@ mod tests { #[test] fn array_init() { let owned = Owned::<[MaybeUninit]>::init(10); - let arr: &[MaybeUninit] = &*owned; + let arr: &[MaybeUninit] = &owned; assert_eq!(arr.len(), 10); } } diff --git a/vendor/crossbeam-epoch/src/collector.rs b/vendor/crossbeam-epoch/src/collector.rs index 099a2ffc6..5b0851184 100644 --- a/vendor/crossbeam-epoch/src/collector.rs +++ b/vendor/crossbeam-epoch/src/collector.rs @@ -111,7 +111,7 @@ impl fmt::Debug for LocalHandle { #[cfg(all(test, not(crossbeam_loom)))] mod tests { - use std::mem; + use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicUsize, Ordering}; use crossbeam_utils::thread; @@ -402,15 +402,13 @@ mod tests { v.push(i as i32); } - let ptr = v.as_mut_ptr() as usize; let len = v.len(); + let ptr = ManuallyDrop::new(v).as_mut_ptr() as usize; guard.defer_unchecked(move || { drop(Vec::from_raw_parts(ptr as *const i32 as *mut i32, len, len)); DESTROYS.fetch_add(len, Ordering::Relaxed); }); guard.flush(); - - mem::forget(v); } while DESTROYS.load(Ordering::Relaxed) < COUNT { diff --git a/vendor/crossbeam-epoch/src/deferred.rs b/vendor/crossbeam-epoch/src/deferred.rs index c33d51502..2f3d79fdf 100644 --- a/vendor/crossbeam-epoch/src/deferred.rs +++ b/vendor/crossbeam-epoch/src/deferred.rs @@ -29,6 +29,15 @@ impl fmt::Debug for Deferred { } impl Deferred { + pub(crate) const NO_OP: Self = { + fn no_op_call(_raw: *mut u8) {} + Self { + call: no_op_call, + data: MaybeUninit::uninit(), + _marker: PhantomData, + } + }; + /// Constructs a new `Deferred` from a `FnOnce()`. pub(crate) fn new(f: F) -> Self { let size = mem::size_of::(); @@ -37,10 +46,10 @@ impl Deferred { unsafe { if size <= mem::size_of::() && align <= mem::align_of::() { let mut data = MaybeUninit::::uninit(); - ptr::write(data.as_mut_ptr() as *mut F, f); + ptr::write(data.as_mut_ptr().cast::(), f); unsafe fn call(raw: *mut u8) { - let f: F = ptr::read(raw as *mut F); + let f: F = ptr::read(raw.cast::()); f(); } @@ -52,12 +61,12 @@ impl Deferred { } else { let b: Box = Box::new(f); let mut data = MaybeUninit::::uninit(); - ptr::write(data.as_mut_ptr() as *mut Box, b); + ptr::write(data.as_mut_ptr().cast::>(), b); unsafe fn call(raw: *mut u8) { // It's safe to cast `raw` from `*mut u8` to `*mut Box`, because `raw` is // originally derived from `*mut Box`. - let b: Box = ptr::read(raw as *mut Box); + let b: Box = ptr::read(raw.cast::>()); (*b)(); } @@ -74,7 +83,7 @@ impl Deferred { #[inline] pub(crate) fn call(mut self) { let call = self.call; - unsafe { call(self.data.as_mut_ptr() as *mut u8) }; + unsafe { call(self.data.as_mut_ptr().cast::()) }; } } diff --git a/vendor/crossbeam-epoch/src/guard.rs b/vendor/crossbeam-epoch/src/guard.rs index 6db3750b0..ba7fe1b11 100644 --- a/vendor/crossbeam-epoch/src/guard.rs +++ b/vendor/crossbeam-epoch/src/guard.rs @@ -46,6 +46,7 @@ use crate::internal::Local; /// if let Some(num) = unsafe { p.as_ref() } { /// println!("The number is {}.", num); /// } +/// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` /// /// # Multiple guards @@ -184,6 +185,7 @@ impl Guard { /// }); /// } /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub unsafe fn defer_unchecked(&self, f: F) where @@ -263,6 +265,7 @@ impl Guard { /// guard.defer_destroy(p); /// } /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub unsafe fn defer_destroy(&self, ptr: Shared<'_, T>) { self.defer_unchecked(move || ptr.into_owned()); @@ -320,6 +323,7 @@ impl Guard { /// let p = a.load(SeqCst, &guard); /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn repin(&mut self) { if let Some(local) = unsafe { self.local.as_ref() } { @@ -356,6 +360,7 @@ impl Guard { /// let p = a.load(SeqCst, &guard); /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); /// } + /// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` pub fn repin_after(&mut self, f: F) -> R where @@ -451,6 +456,7 @@ impl fmt::Debug for Guard { /// /// // Dropping `dummy` doesn't affect the current thread - it's just a noop. /// } +/// # unsafe { drop(a.into_owned()); } // avoid leak /// ``` /// /// The most common use of this function is when constructing or destructing a data structure. diff --git a/vendor/crossbeam-epoch/src/internal.rs b/vendor/crossbeam-epoch/src/internal.rs index de208b13e..00c66a40a 100644 --- a/vendor/crossbeam-epoch/src/internal.rs +++ b/vendor/crossbeam-epoch/src/internal.rs @@ -55,9 +55,10 @@ use crate::sync::list::{Entry, IsElement, IterError, List}; use crate::sync::queue::Queue; /// Maximum number of objects a bag can contain. -#[cfg(not(crossbeam_sanitize))] -const MAX_OBJECTS: usize = 62; -#[cfg(crossbeam_sanitize)] +#[cfg(not(any(crossbeam_sanitize, miri)))] +const MAX_OBJECTS: usize = 64; +// Makes it more likely to trigger any potential data races. +#[cfg(any(crossbeam_sanitize, miri))] const MAX_OBJECTS: usize = 4; /// A bag of deferred functions. @@ -106,87 +107,11 @@ impl Bag { } impl Default for Bag { - #[rustfmt::skip] fn default() -> Self { - // TODO: [no_op; MAX_OBJECTS] syntax blocked by https://github.com/rust-lang/rust/issues/49147 - #[cfg(not(crossbeam_sanitize))] - return Bag { + Bag { len: 0, - deferreds: [ - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - ], - }; - #[cfg(crossbeam_sanitize)] - return Bag { - len: 0, - deferreds: [ - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - Deferred::new(no_op_func), - ], - }; + deferreds: [Deferred::NO_OP; MAX_OBJECTS], + } } } @@ -194,7 +119,7 @@ impl Drop for Bag { fn drop(&mut self) { // Call all deferred functions. for deferred in &mut self.deferreds[..self.len] { - let no_op = Deferred::new(no_op_func); + let no_op = Deferred::NO_OP; let owned_deferred = mem::replace(deferred, no_op); owned_deferred.call(); } @@ -210,8 +135,6 @@ impl fmt::Debug for Bag { } } -fn no_op_func() {} - /// A pair of an epoch and a bag. #[derive(Default, Debug)] struct SealedBag { @@ -375,13 +298,14 @@ pub(crate) struct Local { // Make sure `Local` is less than or equal to 2048 bytes. // https://github.com/crossbeam-rs/crossbeam/issues/551 -#[cfg(not(crossbeam_sanitize))] // `crossbeam_sanitize` reduces the size of `Local` +#[cfg(not(any(crossbeam_sanitize, miri)))] // `crossbeam_sanitize` and `miri` reduce the size of `Local` #[test] fn local_size() { - assert!( - core::mem::size_of::() <= 2048, - "An allocation of `Local` should be <= 2048 bytes." - ); + // TODO: https://github.com/crossbeam-rs/crossbeam/issues/869 + // assert!( + // core::mem::size_of::() <= 2048, + // "An allocation of `Local` should be <= 2048 bytes." + // ); } impl Local { @@ -468,7 +392,10 @@ impl Local { // Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. // The fence makes sure that any future loads from `Atomic`s will not happen before // this store. - if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + if cfg!(all( + any(target_arch = "x86", target_arch = "x86_64"), + not(miri) + )) { // HACK(stjepang): On x86 architectures there are two different ways of executing // a `SeqCst` fence. // diff --git a/vendor/crossbeam-queue/.cargo-checksum.json b/vendor/crossbeam-queue/.cargo-checksum.json deleted file mode 100644 index 8dcd3f367..000000000 --- a/vendor/crossbeam-queue/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"5f8fe6dc4bfa5616834c0f60a6b0280a9dc96d282d4a14e1a77b1bd60453887f","Cargo.toml":"336728ea0b0befab0c66ff758c47ef8c1f49b4912d2f450ae8ab24611cf78790","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"2d4f1cc484ab54dfb9597bf121b3e8ef5416bb56ae52541976016a4776129447","build.rs":"ee1eaeee830c08c770bb84b40e6400af52c8db464945df0b82c8a4a4b4c681ec","no_atomic.rs":"71b5f78fd701ce604aa766dd3d825fa5bed774282aae4d6c31d7acb01b1b242f","src/array_queue.rs":"ea383caa1b70cbe09716caed20016b851118e24fa8508b2ce2498402ae5369f8","src/lib.rs":"effccc001c5168217291e435ae79f4889495cb943a6720d1e73e65b64831e4ed","src/seg_queue.rs":"be0ceb6d67a084eb511582e38c24c7d90bc89c2111778216cf05e11622d7fc4c","tests/array_queue.rs":"3ea9d2ca8c1e1f4d82f2ccd94872696baa4ffc80aca939ea2c5af737be53f817","tests/seg_queue.rs":"3b44ccad949578d2f4e5dee2687cfe6ef1fd52930ae19ed66c12bafa62cf32c2"},"package":"1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"} \ No newline at end of file diff --git a/vendor/crossbeam-queue/CHANGELOG.md b/vendor/crossbeam-queue/CHANGELOG.md deleted file mode 100644 index 1d8b04ff6..000000000 --- a/vendor/crossbeam-queue/CHANGELOG.md +++ /dev/null @@ -1,54 +0,0 @@ -# Version 0.3.5 - -- Add `ArrayQueue::force_push`. (#789) - -# Version 0.3.4 - -- Implement `IntoIterator` for `ArrayQueue` and `SegQueue`. (#772) - -# Version 0.3.3 - -- Fix stacked borrows violation in `ArrayQueue` when `-Zmiri-tag-raw-pointers` is enabled. (#763) - -# Version 0.3.2 - -- Support targets that do not have atomic CAS on stable Rust. (#698) - -# Version 0.3.1 - -- Make `SegQueue::new` const fn. (#584) -- Change license to "MIT OR Apache-2.0". - -# Version 0.3.0 - -- Bump the minimum supported Rust version to 1.36. -- Remove `PushError` and `PopError`. - -# Version 0.2.3 - -- Fix bug in release (yanking 0.2.2) - -# Version 0.2.2 - -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.2.1 - -- Add `no_std` support. - -# Version 0.2.0 - -- Bump the minimum required version to 1.28. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.1.2 - -- Update `crossbeam-utils` to `0.6.5`. - -# Version 0.1.1 - -- Update `crossbeam-utils` to `0.6.4`. - -# Version 0.1.0 - -- Initial version with `ArrayQueue` and `SegQueue`. diff --git a/vendor/crossbeam-queue/Cargo.toml b/vendor/crossbeam-queue/Cargo.toml deleted file mode 100644 index c8093dc19..000000000 --- a/vendor/crossbeam-queue/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -rust-version = "1.36" -name = "crossbeam-queue" -version = "0.3.5" -description = "Concurrent queues" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue" -keywords = [ - "queue", - "mpmc", - "lock-free", - "producer", - "consumer", -] -categories = [ - "concurrency", - "data-structures", - "no-std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.cfg-if] -version = "1" - -[dependencies.crossbeam-utils] -version = "0.8.5" -default-features = false - -[dev-dependencies.rand] -version = "0.8" - -[features] -alloc = [] -default = ["std"] -nightly = ["crossbeam-utils/nightly"] -std = [ - "alloc", - "crossbeam-utils/std", -] diff --git a/vendor/crossbeam-queue/LICENSE-APACHE b/vendor/crossbeam-queue/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/vendor/crossbeam-queue/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/crossbeam-queue/LICENSE-MIT b/vendor/crossbeam-queue/LICENSE-MIT deleted file mode 100644 index 068d491fd..000000000 --- a/vendor/crossbeam-queue/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/crossbeam-queue/README.md b/vendor/crossbeam-queue/README.md deleted file mode 100644 index 2f30b3937..000000000 --- a/vendor/crossbeam-queue/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Crossbeam Queue - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-queue.svg)]( -https://crates.io/crates/crossbeam-queue) -[![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( -https://docs.rs/crossbeam-queue) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides concurrent queues that can be shared among threads: - -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -Everything in this crate can be used in `no_std` environments, provided that `alloc` feature is -enabled. - -[`ArrayQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.SegQueue.html - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-queue = "0.3" -``` - -## Compatibility - -Crossbeam Queue supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/vendor/crossbeam-queue/build.rs b/vendor/crossbeam-queue/build.rs deleted file mode 100644 index 587e0580b..000000000 --- a/vendor/crossbeam-queue/build.rs +++ /dev/null @@ -1,41 +0,0 @@ -// The rustc-cfg listed below are considered public API, but it is *unstable* -// and outside of the normal semver guarantees: -// -// - `crossbeam_no_atomic_cas` -// Assume the target does *not* support atomic CAS operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// -// With the exceptions mentioned above, the rustc-cfg emitted by the build -// script are *not* public API. - -#![warn(rust_2018_idioms)] - -use std::env; - -include!("no_atomic.rs"); - -fn main() { - let target = match env::var("TARGET") { - Ok(target) => target, - Err(e) => { - println!( - "cargo:warning={}: unable to get TARGET environment variable: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - // Note that this is `no_*`, not `has_*`. This allows treating - // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't - // run. This is needed for compatibility with non-cargo build systems that - // don't run the build script. - if NO_ATOMIC_CAS.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); - } - - println!("cargo:rerun-if-changed=no_atomic.rs"); -} diff --git a/vendor/crossbeam-queue/no_atomic.rs b/vendor/crossbeam-queue/no_atomic.rs deleted file mode 100644 index 390019ebd..000000000 --- a/vendor/crossbeam-queue/no_atomic.rs +++ /dev/null @@ -1,73 +0,0 @@ -// This file is @generated by no_atomic.sh. -// It is not intended for manual editing. - -const NO_ATOMIC_CAS: &[&str] = &[ - "avr-unknown-gnu-atmega328", - "bpfeb-unknown-none", - "bpfel-unknown-none", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imc-unknown-none-elf", - "thumbv4t-none-eabi", - "thumbv6m-none-eabi", -]; - -#[allow(dead_code)] // Only crossbeam-utils uses this. -const NO_ATOMIC_64: &[&str] = &[ - "arm-linux-androideabi", - "armebv7r-none-eabi", - "armebv7r-none-eabihf", - "armv4t-unknown-linux-gnueabi", - "armv5te-unknown-linux-gnueabi", - "armv5te-unknown-linux-musleabi", - "armv5te-unknown-linux-uclibceabi", - "armv6k-nintendo-3ds", - "armv7r-none-eabi", - "armv7r-none-eabihf", - "avr-unknown-gnu-atmega328", - "hexagon-unknown-linux-musl", - "m68k-unknown-linux-gnu", - "mips-unknown-linux-gnu", - "mips-unknown-linux-musl", - "mips-unknown-linux-uclibc", - "mipsel-sony-psp", - "mipsel-unknown-linux-gnu", - "mipsel-unknown-linux-musl", - "mipsel-unknown-linux-uclibc", - "mipsel-unknown-none", - "mipsisa32r6-unknown-linux-gnu", - "mipsisa32r6el-unknown-linux-gnu", - "msp430-none-elf", - "powerpc-unknown-freebsd", - "powerpc-unknown-linux-gnu", - "powerpc-unknown-linux-gnuspe", - "powerpc-unknown-linux-musl", - "powerpc-unknown-netbsd", - "powerpc-unknown-openbsd", - "powerpc-wrs-vxworks", - "powerpc-wrs-vxworks-spe", - "riscv32gc-unknown-linux-gnu", - "riscv32gc-unknown-linux-musl", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imac-unknown-none-elf", - "riscv32imc-unknown-none-elf", - "thumbv4t-none-eabi", - "thumbv6m-none-eabi", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv7m-none-eabi", - "thumbv8m.base-none-eabi", - "thumbv8m.main-none-eabi", - "thumbv8m.main-none-eabihf", -]; - -#[allow(dead_code)] // Only crossbeam-utils uses this. -const NO_ATOMIC: &[&str] = &[ - "avr-unknown-gnu-atmega328", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imc-unknown-none-elf", -]; diff --git a/vendor/crossbeam-queue/src/array_queue.rs b/vendor/crossbeam-queue/src/array_queue.rs deleted file mode 100644 index c34f589e7..000000000 --- a/vendor/crossbeam-queue/src/array_queue.rs +++ /dev/null @@ -1,522 +0,0 @@ -//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. -//! -//! Source: -//! - - -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::mem::MaybeUninit; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -/// A slot in a queue. -struct Slot { - /// The current stamp. - /// - /// If the stamp equals the tail, this node will be next written to. If it equals head + 1, - /// this node will be next read from. - stamp: AtomicUsize, - - /// The value in this slot. - value: UnsafeCell>, -} - -/// A bounded multi-producer multi-consumer queue. -/// -/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed -/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an -/// element into a full queue will fail. Alternatively, [`force_push`] makes it possible for -/// this queue to be used as a ring-buffer. Having a buffer allocated upfront makes this queue -/// a bit faster than [`SegQueue`]. -/// -/// [`force_push`]: ArrayQueue::force_push -/// [`SegQueue`]: super::SegQueue -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::ArrayQueue; -/// -/// let q = ArrayQueue::new(2); -/// -/// assert_eq!(q.push('a'), Ok(())); -/// assert_eq!(q.push('b'), Ok(())); -/// assert_eq!(q.push('c'), Err('c')); -/// assert_eq!(q.pop(), Some('a')); -/// ``` -pub struct ArrayQueue { - /// The head of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are popped from the head of the queue. - head: CachePadded, - - /// The tail of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are pushed into the tail of the queue. - tail: CachePadded, - - /// The buffer holding slots. - buffer: Box<[Slot]>, - - /// The queue capacity. - cap: usize, - - /// A stamp with the value of `{ lap: 1, index: 0 }`. - one_lap: usize, -} - -unsafe impl Sync for ArrayQueue {} -unsafe impl Send for ArrayQueue {} - -impl ArrayQueue { - /// Creates a new bounded queue with the given capacity. - /// - /// # Panics - /// - /// Panics if the capacity is zero. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// ``` - pub fn new(cap: usize) -> ArrayQueue { - assert!(cap > 0, "capacity must be non-zero"); - - // Head is initialized to `{ lap: 0, index: 0 }`. - // Tail is initialized to `{ lap: 0, index: 0 }`. - let head = 0; - let tail = 0; - - // Allocate a buffer of `cap` slots initialized - // with stamps. - let buffer: Box<[Slot]> = (0..cap) - .map(|i| { - // Set the stamp to `{ lap: 0, index: i }`. - Slot { - stamp: AtomicUsize::new(i), - value: UnsafeCell::new(MaybeUninit::uninit()), - } - }) - .collect(); - - // One lap is the smallest power of two greater than `cap`. - let one_lap = (cap + 1).next_power_of_two(); - - ArrayQueue { - buffer, - cap, - one_lap, - head: CachePadded::new(AtomicUsize::new(head)), - tail: CachePadded::new(AtomicUsize::new(tail)), - } - } - - fn push_or_else(&self, mut value: T, f: F) -> Result<(), T> - where - F: Fn(T, usize, usize, &Slot) -> Result, - { - let backoff = Backoff::new(); - let mut tail = self.tail.load(Ordering::Relaxed); - - loop { - // Deconstruct the tail. - let index = tail & (self.one_lap - 1); - let lap = tail & !(self.one_lap - 1); - - let new_tail = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - tail + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Inspect the corresponding slot. - debug_assert!(index < self.buffer.len()); - let slot = unsafe { self.buffer.get_unchecked(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the tail and the stamp match, we may attempt to push. - if tail == stamp { - // Try moving the tail. - match self.tail.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Write the value into the slot and update the stamp. - unsafe { - slot.value.get().write(MaybeUninit::new(value)); - } - slot.stamp.store(tail + 1, Ordering::Release); - return Ok(()); - } - Err(t) => { - tail = t; - backoff.spin(); - } - } - } else if stamp.wrapping_add(self.one_lap) == tail + 1 { - atomic::fence(Ordering::SeqCst); - value = f(value, tail, new_tail, slot)?; - backoff.spin(); - tail = self.tail.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - tail = self.tail.load(Ordering::Relaxed); - } - } - } - - /// Attempts to push an element into the queue. - /// - /// If the queue is full, the element is returned back as an error. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert_eq!(q.push(10), Ok(())); - /// assert_eq!(q.push(20), Err(20)); - /// ``` - pub fn push(&self, value: T) -> Result<(), T> { - self.push_or_else(value, |v, tail, _, _| { - let head = self.head.load(Ordering::Relaxed); - - // If the head lags one lap behind the tail as well... - if head.wrapping_add(self.one_lap) == tail { - // ...then the queue is full. - Err(v) - } else { - Ok(v) - } - }) - } - - /// Pushes an element into the queue, replacing the oldest element if necessary. - /// - /// If the queue is full, the oldest element is replaced and returned, - /// otherwise `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(2); - /// - /// assert_eq!(q.force_push(10), None); - /// assert_eq!(q.force_push(20), None); - /// assert_eq!(q.force_push(30), Some(10)); - /// assert_eq!(q.pop(), Some(20)); - /// ``` - pub fn force_push(&self, value: T) -> Option { - self.push_or_else(value, |v, tail, new_tail, slot| { - let head = tail.wrapping_sub(self.one_lap); - let new_head = new_tail.wrapping_sub(self.one_lap); - - // Try moving the head. - if self - .head - .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - // Move the tail. - self.tail.store(new_tail, Ordering::SeqCst); - - // Swap the previous value. - let old = unsafe { slot.value.get().replace(MaybeUninit::new(v)).assume_init() }; - - // Update the stamp. - slot.stamp.store(tail + 1, Ordering::Release); - - Err(old) - } else { - Ok(v) - } - }) - .err() - } - - /// Attempts to pop an element from the queue. - /// - /// If the queue is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// assert_eq!(q.push(10), Ok(())); - /// - /// assert_eq!(q.pop(), Some(10)); - /// assert!(q.pop().is_none()); - /// ``` - pub fn pop(&self) -> Option { - let backoff = Backoff::new(); - let mut head = self.head.load(Ordering::Relaxed); - - loop { - // Deconstruct the head. - let index = head & (self.one_lap - 1); - let lap = head & !(self.one_lap - 1); - - // Inspect the corresponding slot. - debug_assert!(index < self.buffer.len()); - let slot = unsafe { self.buffer.get_unchecked(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the the stamp is ahead of the head by 1, we may attempt to pop. - if head + 1 == stamp { - let new = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the head. - match self.head.compare_exchange_weak( - head, - new, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Read the value from the slot and update the stamp. - let msg = unsafe { slot.value.get().read().assume_init() }; - slot.stamp - .store(head.wrapping_add(self.one_lap), Ordering::Release); - return Some(msg); - } - Err(h) => { - head = h; - backoff.spin(); - } - } - } else if stamp == head { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.load(Ordering::Relaxed); - - // If the tail equals the head, that means the channel is empty. - if tail == head { - return None; - } - - backoff.spin(); - head = self.head.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - head = self.head.load(Ordering::Relaxed); - } - } - } - - /// Returns the capacity of the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// - /// assert_eq!(q.capacity(), 100); - /// ``` - pub fn capacity(&self) -> usize { - self.cap - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// - /// assert!(q.is_empty()); - /// q.push(1).unwrap(); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.load(Ordering::SeqCst); - let tail = self.tail.load(Ordering::SeqCst); - - // Is the tail lagging one lap behind head? - // Is the tail equal to the head? - // - // Note: If the head changes just before we load the tail, that means there was a moment - // when the channel was not empty, so it is safe to just return `false`. - tail == head - } - - /// Returns `true` if the queue is full. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert!(!q.is_full()); - /// q.push(1).unwrap(); - /// assert!(q.is_full()); - /// ``` - pub fn is_full(&self) -> bool { - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // Is the head lagging one lap behind tail? - // - // Note: If the tail changes just before we load the head, that means there was a moment - // when the queue was not full, so it is safe to just return `false`. - head.wrapping_add(self.one_lap) == tail - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10).unwrap(); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20).unwrap(); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail, then load the head. - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // If the tail didn't change, we've got consistent values to work with. - if self.tail.load(Ordering::SeqCst) == tail { - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - return if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - } - } - } -} - -impl Drop for ArrayQueue { - fn drop(&mut self) { - // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1); - - // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i - } else { - hix + i - self.cap - }; - - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - let value = &mut *slot.value.get(); - value.as_mut_ptr().drop_in_place(); - } - } - } -} - -impl fmt::Debug for ArrayQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("ArrayQueue { .. }") - } -} - -impl IntoIterator for ArrayQueue { - type Item = T; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { value: self } - } -} - -#[derive(Debug)] -pub struct IntoIter { - value: ArrayQueue, -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - let value = &mut self.value; - let head = *value.head.get_mut(); - if value.head.get_mut() != value.tail.get_mut() { - let index = head & (value.one_lap - 1); - let lap = head & !(value.one_lap - 1); - // SAFETY: We have mutable access to this, so we can read without - // worrying about concurrency. Furthermore, we know this is - // initialized because it is the value pointed at by `value.head` - // and this is a non-empty queue. - let val = unsafe { - debug_assert!(index < value.buffer.len()); - let slot = value.buffer.get_unchecked_mut(index); - slot.value.get().read().assume_init() - }; - let new = if index + 1 < value.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(value.one_lap) - }; - *value.head.get_mut() = new; - Option::Some(val) - } else { - Option::None - } - } -} diff --git a/vendor/crossbeam-queue/src/lib.rs b/vendor/crossbeam-queue/src/lib.rs deleted file mode 100644 index 846d7c2e1..000000000 --- a/vendor/crossbeam-queue/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Concurrent queues. -//! -//! This crate provides concurrent queues that can be shared among threads: -//! -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(crossbeam_no_atomic_cas))] -cfg_if::cfg_if! { - if #[cfg(feature = "alloc")] { - extern crate alloc; - - mod array_queue; - mod seg_queue; - - pub use self::array_queue::ArrayQueue; - pub use self::seg_queue::SegQueue; - } -} diff --git a/vendor/crossbeam-queue/src/seg_queue.rs b/vendor/crossbeam-queue/src/seg_queue.rs deleted file mode 100644 index 1767775d1..000000000 --- a/vendor/crossbeam-queue/src/seg_queue.rs +++ /dev/null @@ -1,545 +0,0 @@ -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem::MaybeUninit; -use core::ptr; -use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -// Bits indicating the state of a slot: -// * If a value has been written into the slot, `WRITE` is set. -// * If a value has been read from the slot, `READ` is set. -// * If the block is being destroyed, `DESTROY` is set. -const WRITE: usize = 1; -const READ: usize = 2; -const DESTROY: usize = 4; - -// Each block covers one "lap" of indices. -const LAP: usize = 32; -// The maximum number of values a block can hold. -const BLOCK_CAP: usize = LAP - 1; -// How many lower bits are reserved for metadata. -const SHIFT: usize = 1; -// Indicates that the block is not the last one. -const HAS_NEXT: usize = 1; - -/// A slot in a block. -struct Slot { - /// The value. - value: UnsafeCell>, - - /// The state of the slot. - state: AtomicUsize, -} - -impl Slot { - /// Waits until a value is written into the slot. - fn wait_write(&self) { - let backoff = Backoff::new(); - while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); - } - } -} - -/// A block in a linked list. -/// -/// Each block in the list can hold up to `BLOCK_CAP` values. -struct Block { - /// The next block in the linked list. - next: AtomicPtr>, - - /// Slots for values. - slots: [Slot; BLOCK_CAP], -} - -impl Block { - /// Creates an empty block that starts at `start_index`. - fn new() -> Block { - // SAFETY: This is safe because: - // [1] `Block::next` (AtomicPtr) may be safely zero initialized. - // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. - // [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it - // holds a MaybeUninit. - // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } - } - - /// Waits until the next pointer is set. - fn wait_next(&self) -> *mut Block { - let backoff = Backoff::new(); - loop { - let next = self.next.load(Ordering::Acquire); - if !next.is_null() { - return next; - } - backoff.snooze(); - } - } - - /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. - unsafe fn destroy(this: *mut Block, start: usize) { - // It is not necessary to set the `DESTROY` bit in the last slot because that slot has - // begun destruction of the block. - for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); - - // Mark the `DESTROY` bit if a thread is still using the slot. - if slot.state.load(Ordering::Acquire) & READ == 0 - && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 - { - // If a thread is still using the slot, it will continue destruction of the block. - return; - } - } - - // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); - } -} - -/// A position in a queue. -struct Position { - /// The index in the queue. - index: AtomicUsize, - - /// The block in the linked list. - block: AtomicPtr>, -} - -/// An unbounded multi-producer multi-consumer queue. -/// -/// This queue is implemented as a linked list of segments, where each segment is a small buffer -/// that can hold a handful of elements. There is no limit to how many elements can be in the queue -/// at a time. However, since segments need to be dynamically allocated as elements get pushed, -/// this queue is somewhat slower than [`ArrayQueue`]. -/// -/// [`ArrayQueue`]: super::ArrayQueue -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::SegQueue; -/// -/// let q = SegQueue::new(); -/// -/// q.push('a'); -/// q.push('b'); -/// -/// assert_eq!(q.pop(), Some('a')); -/// assert_eq!(q.pop(), Some('b')); -/// assert!(q.pop().is_none()); -/// ``` -pub struct SegQueue { - /// The head of the queue. - head: CachePadded>, - - /// The tail of the queue. - tail: CachePadded>, - - /// Indicates that dropping a `SegQueue` may drop values of type `T`. - _marker: PhantomData, -} - -unsafe impl Send for SegQueue {} -unsafe impl Sync for SegQueue {} - -impl SegQueue { - /// Creates a new unbounded queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::::new(); - /// ``` - pub const fn new() -> SegQueue { - SegQueue { - head: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - _marker: PhantomData, - } - } - - /// Pushes an element into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// q.push(20); - /// ``` - pub fn push(&self, value: T) { - let backoff = Backoff::new(); - let mut tail = self.tail.index.load(Ordering::Acquire); - let mut block = self.tail.block.load(Ordering::Acquire); - let mut next_block = None; - - loop { - // Calculate the offset of the index into the block. - let offset = (tail >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - - // If we're going to have to install the next block, allocate it in advance in order to - // make the wait for other threads as short as possible. - if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); - } - - // If this is the first push operation, we need to allocate the first block. - if block.is_null() { - let new = Box::into_raw(Box::new(Block::::new())); - - if self - .tail - .block - .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - self.head.block.store(new, Ordering::Release); - block = new; - } else { - next_block = unsafe { Some(Box::from_raw(new)) }; - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - } - - let new_tail = tail + (1 << SHIFT); - - // Try advancing the tail forward. - match self.tail.index.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, install the next one. - if offset + 1 == BLOCK_CAP { - let next_block = Box::into_raw(next_block.unwrap()); - let next_index = new_tail.wrapping_add(1 << SHIFT); - - self.tail.block.store(next_block, Ordering::Release); - self.tail.index.store(next_index, Ordering::Release); - (*block).next.store(next_block, Ordering::Release); - } - - // Write the value into the slot. - let slot = (*block).slots.get_unchecked(offset); - slot.value.get().write(MaybeUninit::new(value)); - slot.state.fetch_or(WRITE, Ordering::Release); - - return; - }, - Err(t) => { - tail = t; - block = self.tail.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Pops an element from the queue. - /// - /// If the queue is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// assert_eq!(q.pop(), Some(10)); - /// assert!(q.pop().is_none()); - /// ``` - pub fn pop(&self) -> Option { - let backoff = Backoff::new(); - let mut head = self.head.index.load(Ordering::Acquire); - let mut block = self.head.block.load(Ordering::Acquire); - - loop { - // Calculate the offset of the index into the block. - let offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - let mut new_head = head + (1 << SHIFT); - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return None; - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - } - } - - // The block can be null here only if the first push operation is in progress. In that - // case, just wait until it gets initialized. - if block.is_null() { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - // Try moving the head index forward. - match self.head.index.compare_exchange_weak( - head, - new_head, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, move to the next one. - if offset + 1 == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the value. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let value = slot.value.get().read().assume_init(); - - // Destroy the block if we've reached the end, or if another thread wanted to - // destroy but couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); - } - - return Some(value); - }, - Err(h) => { - head = h; - block = self.head.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// assert!(q.is_empty()); - /// q.push(1); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.index.load(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::SeqCst); - head >> SHIFT == tail >> SHIFT - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail index, then load the head index. - let mut tail = self.tail.index.load(Ordering::SeqCst); - let mut head = self.head.index.load(Ordering::SeqCst); - - // If the tail index didn't change, we've got consistent indices to work with. - if self.tail.index.load(Ordering::SeqCst) == tail { - // Erase the lower bits. - tail &= !((1 << SHIFT) - 1); - head &= !((1 << SHIFT) - 1); - - // Fix up indices if they fall onto block ends. - if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { - tail = tail.wrapping_add(1 << SHIFT); - } - if (head >> SHIFT) & (LAP - 1) == LAP - 1 { - head = head.wrapping_add(1 << SHIFT); - } - - // Rotate indices so that head falls into the first block. - let lap = (head >> SHIFT) / LAP; - tail = tail.wrapping_sub((lap * LAP) << SHIFT); - head = head.wrapping_sub((lap * LAP) << SHIFT); - - // Remove the lower bits. - tail >>= SHIFT; - head >>= SHIFT; - - // Return the difference minus the number of blocks between tail and head. - return tail - head - tail / LAP; - } - } - } -} - -impl Drop for SegQueue { - fn drop(&mut self) { - let mut head = self.head.index.load(Ordering::Relaxed); - let mut tail = self.tail.index.load(Ordering::Relaxed); - let mut block = self.head.block.load(Ordering::Relaxed); - - // Erase the lower bits. - head &= !((1 << SHIFT) - 1); - tail &= !((1 << SHIFT) - 1); - - unsafe { - // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. - while head != tail { - let offset = (head >> SHIFT) % LAP; - - if offset < BLOCK_CAP { - // Drop the value in the slot. - let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().drop_in_place(); - } else { - // Deallocate the block and move to the next one. - let next = (*block).next.load(Ordering::Relaxed); - drop(Box::from_raw(block)); - block = next; - } - - head = head.wrapping_add(1 << SHIFT); - } - - // Deallocate the last remaining block. - if !block.is_null() { - drop(Box::from_raw(block)); - } - } - } -} - -impl fmt::Debug for SegQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("SegQueue { .. }") - } -} - -impl Default for SegQueue { - fn default() -> SegQueue { - SegQueue::new() - } -} - -impl IntoIterator for SegQueue { - type Item = T; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { value: self } - } -} - -#[derive(Debug)] -pub struct IntoIter { - value: SegQueue, -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - let value = &mut self.value; - let head = *value.head.index.get_mut(); - let tail = *value.tail.index.get_mut(); - if head >> SHIFT == tail >> SHIFT { - None - } else { - let block = *value.head.block.get_mut(); - let offset = (head >> SHIFT) % LAP; - - // SAFETY: We have mutable access to this, so we can read without - // worrying about concurrency. Furthermore, we know this is - // initialized because it is the value pointed at by `value.head` - // and this is a non-empty queue. - let item = unsafe { - let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().read() - }; - if offset + 1 == BLOCK_CAP { - // Deallocate the block and move to the next one. - // SAFETY: The block is initialized because we've been reading - // from it this entire time. We can drop it b/c everything has - // been read out of it, so nothing is pointing to it anymore. - unsafe { - let next = *(*block).next.get_mut(); - drop(Box::from_raw(block)); - *value.head.block.get_mut() = next; - } - // The last value in a block is empty, so skip it - *value.head.index.get_mut() = head.wrapping_add(2 << SHIFT); - // Double-check that we're pointing to the first item in a block. - debug_assert_eq!((*value.head.index.get_mut() >> SHIFT) % LAP, 0); - } else { - *value.head.index.get_mut() = head.wrapping_add(1 << SHIFT); - } - Some(item) - } - } -} diff --git a/vendor/crossbeam-queue/tests/array_queue.rs b/vendor/crossbeam-queue/tests/array_queue.rs deleted file mode 100644 index 9a64eac03..000000000 --- a/vendor/crossbeam-queue/tests/array_queue.rs +++ /dev/null @@ -1,359 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::ArrayQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = ArrayQueue::new(1); - - q.push(7).unwrap(); - assert_eq!(q.pop(), Some(7)); - - q.push(8).unwrap(); - assert_eq!(q.pop(), Some(8)); - assert!(q.pop().is_none()); -} - -#[test] -fn capacity() { - for i in 1..10 { - let q = ArrayQueue::::new(i); - assert_eq!(q.capacity(), i); - } -} - -#[test] -#[should_panic(expected = "capacity must be non-zero")] -fn zero_capacity() { - let _ = ArrayQueue::::new(0); -} - -#[test] -fn len_empty_full() { - let q = ArrayQueue::new(2); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); - assert!(!q.is_full()); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - assert!(!q.is_full()); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 2); - assert!(!q.is_empty()); - assert!(q.is_full()); - - q.pop().unwrap(); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - assert!(!q.is_full()); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn len() { - const COUNT: usize = 25_000; - const CAP: usize = 1000; - - let q = ArrayQueue::new(CAP); - assert_eq!(q.len(), 0); - - for _ in 0..CAP / 10 { - for i in 0..50 { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - } - assert_eq!(q.len(), 0); - - for i in 0..CAP { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for _ in 0..CAP { - q.pop().unwrap(); - } - assert_eq!(q.len(), 0); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - let len = q.len(); - assert!(len <= CAP); - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - let len = q.len(); - assert!(len <= CAP); - } - }); - }) - .unwrap(); - assert_eq!(q.len(), 0); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = ArrayQueue::new(3); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_none()); - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - }) - .unwrap(); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn spsc_ring_buffer() { - const COUNT: usize = 100_000; - - let t = AtomicUsize::new(1); - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - scope.spawn(|_| loop { - match t.load(Ordering::SeqCst) { - 0 if q.is_empty() => break, - - _ => { - while let Some(n) = q.pop() { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - if let Some(n) = q.force_push(i) { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - - t.fetch_sub(1, Ordering::SeqCst); - }); - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), 1); - } -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Some(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn mpmc_ring_buffer() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let t = AtomicUsize::new(THREADS); - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| loop { - match t.load(Ordering::SeqCst) { - 0 if q.is_empty() => break, - - _ => { - while let Some(n) = q.pop() { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - } - }); - } - - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - if let Some(n) = q.force_push(i) { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - - t.fetch_sub(1, Ordering::SeqCst); - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn drops() { - const RUNS: usize = 100; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..RUNS { - let steps = rng.gen_range(0..10_000); - let additional = rng.gen_range(0..50); - - DROPS.store(0, Ordering::SeqCst); - let q = ArrayQueue::new(50); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_none() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - while q.push(DropCounter).is_err() { - DROPS.fetch_sub(1, Ordering::SeqCst); - } - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter).unwrap(); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn linearizable() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::new(THREADS); - - scope(|scope| { - for _ in 0..THREADS / 2 { - scope.spawn(|_| { - for _ in 0..COUNT { - while q.push(0).is_err() {} - q.pop().unwrap(); - } - }); - - scope.spawn(|_| { - for _ in 0..COUNT { - if q.force_push(0).is_none() { - q.pop().unwrap(); - } - } - }); - } - }) - .unwrap(); -} - -#[test] -fn into_iter() { - let q = ArrayQueue::new(100); - for i in 0..100 { - q.push(i).unwrap(); - } - for (i, j) in q.into_iter().enumerate() { - assert_eq!(i, j); - } -} diff --git a/vendor/crossbeam-queue/tests/seg_queue.rs b/vendor/crossbeam-queue/tests/seg_queue.rs deleted file mode 100644 index f1304ed4a..000000000 --- a/vendor/crossbeam-queue/tests/seg_queue.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::SegQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = SegQueue::new(); - q.push(7); - assert_eq!(q.pop(), Some(7)); - - q.push(8); - assert_eq!(q.pop(), Some(8)); - assert!(q.pop().is_none()); -} - -#[test] -fn len_empty_full() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); - - q.push(()); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - - q.pop().unwrap(); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); -} - -#[test] -fn len() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - - for i in 0..50 { - q.push(i); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - - assert_eq!(q.len(), 0); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_none()); - }); - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - }) - .unwrap(); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = SegQueue::::new(); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Some(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn drops() { - const RUNS: usize = 100; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..RUNS { - let steps = rng.gen_range(0..10_000); - let additional = rng.gen_range(0..1000); - - DROPS.store(0, Ordering::SeqCst); - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_none() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - q.push(DropCounter); - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn into_iter() { - let q = SegQueue::new(); - for i in 0..100 { - q.push(i); - } - for (i, j) in q.into_iter().enumerate() { - assert_eq!(i, j); - } -} - -#[test] -fn into_iter_drop() { - let q = SegQueue::new(); - for i in 0..100 { - q.push(i); - } - for (i, j) in q.into_iter().enumerate().take(50) { - assert_eq!(i, j); - } -} diff --git a/vendor/crossbeam-utils/.cargo-checksum.json b/vendor/crossbeam-utils/.cargo-checksum.json index f78acc358..eac87698d 100644 --- a/vendor/crossbeam-utils/.cargo-checksum.json +++ b/vendor/crossbeam-utils/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"c2cdac68fbf3795e9c3cb0bbeace5f87736d0745fefbd3db9c07f568dc70d1d1","Cargo.toml":"fc5b0f0f821aa944d4341dc97e7c3b4d4bf658483ba359b5bf2e53d8ad945ac9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"dfa9fbed47c344c134a63c84b7c0e4651baeac1554b7b3266d0e38643743fc33","benches/atomic_cell.rs":"c927eb3cd1e5ecc4b91adbc3bde98af15ffab4086190792ba64d5cde0e24df3d","build.rs":"7e74dc72343ff57e83d0a84a9fbdd9ff1645894165909999b4c3d2fba94bc96c","no_atomic.rs":"916ed15218bb7b75a4e0d432430e7134efd27ca43ca8a8766e0c90e89febb602","src/atomic/atomic_cell.rs":"f1b407b62b981de47968236eabb932384722c4dd7b7f08f52c59943aefd0b113","src/atomic/consume.rs":"7a7736fcd64f6473dfea7653559ffc5e1a2a234df43835f8aa8734862145ac15","src/atomic/mod.rs":"94193895fa03cece415e8d7be700b73a9a8a7015774ca821253438607f9b0736","src/atomic/seq_lock.rs":"27182e6b87a9db73c5f6831759f8625f9fcdec3c2828204c444aef04f427735a","src/atomic/seq_lock_wide.rs":"9888dd03116bb89ca36d4ab8d5a0b5032107a2983a7eb8024454263b09080088","src/backoff.rs":"7cc7754e15f69b52e92a70d4f49d1bc274693455a0933a2d7eb0605806566af3","src/cache_padded.rs":"6a512698115ad0d5a5b163dbd7a83247e1f1c146c4a30f3fc74b952e3b767b59","src/lib.rs":"6f1bcf157abe06ad8458a53e865bf8efab9fad4a9424790147cee8fefb3795d8","src/sync/mod.rs":"59986f559a8f170a4b3247ab2eea2460b09809d87c8110ed88e4e7103d3519dc","src/sync/parker.rs":"3f997f5b41fec286ccedcf3d36f801d741387badb574820b8e3456117ecd9154","src/sync/sharded_lock.rs":"78433f55ee3defeea348d65abc78e03d63d6a304e09c568b27b403e9ad205771","src/sync/wait_group.rs":"32e946a7581c55f8aa9904527b92b177c538fa0cf7cbcfa1d1f25990582cb6ea","src/thread.rs":"21cf9b3e965529e5c0a6ff8fc1ec846bfe0006c41deb238a149be8d07384e955","tests/atomic_cell.rs":"bf8bc869c922a1cbf929c3b741bae0cae98f2157f572b5a4eb2873d20a407c22","tests/cache_padded.rs":"1bfaff8354c8184e1ee1f902881ca9400b60effb273b0d3f752801a483d2b66d","tests/parker.rs":"6def4721287d9d70b1cfd63ebb34e1c83fbb3376edbad2bc8aac6ef69dd99d20","tests/sharded_lock.rs":"314adeb8a651a28935f7a49c9a261b8fa1fd82bf6a16c865a5aced6216d7e40b","tests/thread.rs":"9a7d7d3028c552fd834c68598b04a1cc252a816bc20ab62cec060d6cd09cab10","tests/wait_group.rs":"ad8f0cdfed31f9594a2e0737234d418f8b924d784a4db8d7e469deab8c95f5f8"},"package":"7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"} \ No newline at end of file +{"files":{"CHANGELOG.md":"eb2f46ecf2eee5f591c4d4e789f18735bb1ed771782a5e0f16eab3a77001e7c2","Cargo.toml":"9ce8b596c9789e65bef4c952bdcac84fc88e50ba9ecb01a818036eff4e6ecfec","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"2a19af38a52dd965c2d66bb39f90a85b430b51ee9ccb29e9e1978ee7091e5087","benches/atomic_cell.rs":"c927eb3cd1e5ecc4b91adbc3bde98af15ffab4086190792ba64d5cde0e24df3d","build.rs":"4859f9c926c230023e861bf01c4b225b460035faf8cf6240108530efedbb747f","no_atomic.rs":"916ed15218bb7b75a4e0d432430e7134efd27ca43ca8a8766e0c90e89febb602","src/atomic/atomic_cell.rs":"0fc99463e633144c5d59d39c35b5477da1f1b90f5448cadc37454b7f4b97707e","src/atomic/consume.rs":"7a7736fcd64f6473dfea7653559ffc5e1a2a234df43835f8aa8734862145ac15","src/atomic/mod.rs":"94193895fa03cece415e8d7be700b73a9a8a7015774ca821253438607f9b0736","src/atomic/seq_lock.rs":"27182e6b87a9db73c5f6831759f8625f9fcdec3c2828204c444aef04f427735a","src/atomic/seq_lock_wide.rs":"9888dd03116bb89ca36d4ab8d5a0b5032107a2983a7eb8024454263b09080088","src/backoff.rs":"8fd5e3dcccc05860680e49c8498de8096bee9140bcfee8723d97117106a020d0","src/cache_padded.rs":"6a512698115ad0d5a5b163dbd7a83247e1f1c146c4a30f3fc74b952e3b767b59","src/lib.rs":"6f1bcf157abe06ad8458a53e865bf8efab9fad4a9424790147cee8fefb3795d8","src/sync/mod.rs":"59986f559a8f170a4b3247ab2eea2460b09809d87c8110ed88e4e7103d3519dc","src/sync/parker.rs":"91f3a7d4ee8d9e06b6558d180e8a0df08ff5c6cef612b4ce4790f9f75cb34f84","src/sync/sharded_lock.rs":"78433f55ee3defeea348d65abc78e03d63d6a304e09c568b27b403e9ad205771","src/sync/wait_group.rs":"32e946a7581c55f8aa9904527b92b177c538fa0cf7cbcfa1d1f25990582cb6ea","src/thread.rs":"21cf9b3e965529e5c0a6ff8fc1ec846bfe0006c41deb238a149be8d07384e955","tests/atomic_cell.rs":"bf8bc869c922a1cbf929c3b741bae0cae98f2157f572b5a4eb2873d20a407c22","tests/cache_padded.rs":"1bfaff8354c8184e1ee1f902881ca9400b60effb273b0d3f752801a483d2b66d","tests/parker.rs":"6def4721287d9d70b1cfd63ebb34e1c83fbb3376edbad2bc8aac6ef69dd99d20","tests/sharded_lock.rs":"314adeb8a651a28935f7a49c9a261b8fa1fd82bf6a16c865a5aced6216d7e40b","tests/thread.rs":"9a7d7d3028c552fd834c68598b04a1cc252a816bc20ab62cec060d6cd09cab10","tests/wait_group.rs":"02661c2a820a5abe8b0c8fe15a6650aead707b57cdda0610d1b09a2680ed6969"},"package":"51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"} \ No newline at end of file diff --git a/vendor/crossbeam-utils/CHANGELOG.md b/vendor/crossbeam-utils/CHANGELOG.md index 8decb6cbd..28812e1d6 100644 --- a/vendor/crossbeam-utils/CHANGELOG.md +++ b/vendor/crossbeam-utils/CHANGELOG.md @@ -1,3 +1,7 @@ +# Version 0.8.11 + +- Bump the minimum supported Rust version to 1.38. (#877) + # Version 0.8.10 - Fix unsoundness of `AtomicCell` on types containing niches. (#834) diff --git a/vendor/crossbeam-utils/Cargo.toml b/vendor/crossbeam-utils/Cargo.toml index fa958df28..9e1b58628 100644 --- a/vendor/crossbeam-utils/Cargo.toml +++ b/vendor/crossbeam-utils/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2018" -rust-version = "1.36" +rust-version = "1.38" name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.11" description = "Utilities for concurrent programming" homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" readme = "README.md" diff --git a/vendor/crossbeam-utils/README.md b/vendor/crossbeam-utils/README.md index 6e9a8e49a..c06ea601a 100644 --- a/vendor/crossbeam-utils/README.md +++ b/vendor/crossbeam-utils/README.md @@ -8,7 +8,7 @@ https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils#license) https://crates.io/crates/crossbeam-utils) [![Documentation](https://docs.rs/crossbeam-utils/badge.svg)]( https://docs.rs/crossbeam-utils) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +[![Rust 1.38+](https://img.shields.io/badge/rust-1.38+-lightgray.svg)]( https://www.rust-lang.org) [![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) @@ -55,7 +55,7 @@ crossbeam-utils = "0.8" Crossbeam Utils supports stable Rust releases going back at least six months, and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. +version is released. Currently, the minimum supported Rust version is 1.38. ## License diff --git a/vendor/crossbeam-utils/build.rs b/vendor/crossbeam-utils/build.rs index a7557fd59..dd6604792 100644 --- a/vendor/crossbeam-utils/build.rs +++ b/vendor/crossbeam-utils/build.rs @@ -41,10 +41,9 @@ fn main() { } }; - // Note that this is `no_*`, not `has_*`. This allows treating - // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't - // run. This is needed for compatibility with non-cargo build systems that - // don't run the build script. + // Note that this is `no_`*, not `has_*`. This allows treating as the latest + // stable rustc is used when the build script doesn't run. This is useful + // for non-cargo build systems that don't run the build script. if NO_ATOMIC_CAS.contains(&&*target) { println!("cargo:rustc-cfg=crossbeam_no_atomic_cas"); } diff --git a/vendor/crossbeam-utils/src/atomic/atomic_cell.rs b/vendor/crossbeam-utils/src/atomic/atomic_cell.rs index 9fed45d4c..7941c5c87 100644 --- a/vendor/crossbeam-utils/src/atomic/atomic_cell.rs +++ b/vendor/crossbeam-utils/src/atomic/atomic_cell.rs @@ -180,7 +180,7 @@ impl AtomicCell { /// ``` #[inline] pub fn as_ptr(&self) -> *mut T { - self.value.get() as *mut T + self.value.get().cast::() } } @@ -902,12 +902,7 @@ fn lock(addr: usize) -> &'static SeqLock { const LEN: usize = 97; #[allow(clippy::declare_interior_mutable_const)] const L: SeqLock = SeqLock::new(); - static LOCKS: [SeqLock; LEN] = [ - L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, - L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, - L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, - L, L, L, L, L, L, L, - ]; + static LOCKS: [SeqLock; LEN] = [L; LEN]; // If the modulus is a constant number, the compiler will use crazy math to transform this into // a sequence of cheap arithmetic operations rather than using the slow modulo instruction. @@ -973,7 +968,7 @@ macro_rules! atomic { /// Returns `true` if operations on `AtomicCell` are lock-free. const fn atomic_is_lock_free() -> bool { - // HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in Rust 1.36. + // HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in our MSRV (Rust 1.38). let is_lock_free = can_transmute::() | can_transmute::() | can_transmute::() @@ -1009,10 +1004,11 @@ where // discard the data when a data race is detected. The proper solution would be to // do atomic reads and atomic writes, but we can't atomically read and write all // kinds of data since `AtomicU8` is not available on stable Rust yet. - let val = ptr::read_volatile(src); + // Load as `MaybeUninit` because we may load a value that is not valid as `T`. + let val = ptr::read_volatile(src.cast::>()); if lock.validate_read(stamp) { - return val; + return val.assume_init(); } } @@ -1072,6 +1068,7 @@ unsafe fn atomic_swap(dst: *mut T, val: T) -> T { /// /// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a /// global lock otherwise. +#[allow(clippy::let_unit_value)] unsafe fn atomic_compare_exchange_weak(dst: *mut T, mut current: T, new: T) -> Result where T: Copy + Eq, diff --git a/vendor/crossbeam-utils/src/backoff.rs b/vendor/crossbeam-utils/src/backoff.rs index 1012f06b2..9e256aaf2 100644 --- a/vendor/crossbeam-utils/src/backoff.rs +++ b/vendor/crossbeam-utils/src/backoff.rs @@ -201,6 +201,7 @@ impl Backoff { /// assert_eq!(ready.load(SeqCst), false); /// spin_wait(&ready); /// assert_eq!(ready.load(SeqCst), true); + /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`AtomicBool`]: std::sync::atomic::AtomicBool @@ -269,6 +270,7 @@ impl Backoff { /// assert_eq!(ready.load(SeqCst), false); /// blocking_wait(&ready); /// assert_eq!(ready.load(SeqCst), true); + /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`AtomicBool`]: std::sync::atomic::AtomicBool diff --git a/vendor/crossbeam-utils/src/sync/parker.rs b/vendor/crossbeam-utils/src/sync/parker.rs index 531f5a5fc..e791c4485 100644 --- a/vendor/crossbeam-utils/src/sync/parker.rs +++ b/vendor/crossbeam-utils/src/sync/parker.rs @@ -44,6 +44,7 @@ use std::time::{Duration, Instant}; /// /// // Wakes up when `u.unpark()` provides the token. /// p.park(); +/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`park`]: Parker::park @@ -241,6 +242,7 @@ impl Unparker { /// /// // Wakes up when `u.unpark()` provides the token. /// p.park(); + /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`park`]: Parker::park @@ -262,7 +264,7 @@ impl Unparker { /// # let _ = unsafe { Unparker::from_raw(raw) }; /// ``` pub fn into_raw(this: Unparker) -> *const () { - Arc::into_raw(this.inner) as *const () + Arc::into_raw(this.inner).cast::<()>() } /// Converts a raw pointer into an `Unparker`. @@ -284,7 +286,7 @@ impl Unparker { /// ``` pub unsafe fn from_raw(ptr: *const ()) -> Unparker { Unparker { - inner: Arc::from_raw(ptr as *const Inner), + inner: Arc::from_raw(ptr.cast::()), } } } diff --git a/vendor/crossbeam-utils/tests/wait_group.rs b/vendor/crossbeam-utils/tests/wait_group.rs index b6c2a2437..0ec4a729c 100644 --- a/vendor/crossbeam-utils/tests/wait_group.rs +++ b/vendor/crossbeam-utils/tests/wait_group.rs @@ -36,6 +36,7 @@ fn wait() { } #[test] +#[cfg_attr(miri, ignore)] // this test makes timing assumptions, but Miri is so slow it violates them fn wait_and_drop() { let wg = WaitGroup::new(); let (tx, rx) = mpsc::channel(); @@ -51,8 +52,8 @@ fn wait_and_drop() { }); } - // At this point, all spawned threads should be sleeping, so we shouldn't get anything from the - // channel. + // At this point, all spawned threads should be in `thread::sleep`, so we shouldn't get anything + // from the channel. assert!(rx.try_recv().is_err()); wg.wait(); diff --git a/vendor/crossbeam/.cargo-checksum.json b/vendor/crossbeam/.cargo-checksum.json deleted file mode 100644 index 0bd859983..000000000 --- a/vendor/crossbeam/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"e8dcdd4c84fced11ce3e9be9246dd511e9d09b0b36497c6e569ed0427b57424a","Cargo.toml":"a1452bb8649a66814e473799942aa624243bab0e5257a5b11ce994253b41ecb4","LICENSE-APACHE":"6f712474a3e3be1386d2d0c29449850ea788da64d35cff0fc8799acf741e9ecd","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"d1d81cf88e580608f27bf4d2bb7f6f2d01c2c1f1d26be86ec1daa7aa455e9f62","no_atomic.rs":"a2621c1b029c614fb0ab8e3f5cda2e839df88d90d26133181c1b901965f7eec4","src/lib.rs":"e896ef1e4326db5202cebdd57dd606f96113d5a8700e746bfe8909978ac84a7f","tests/subcrates.rs":"69cbe766a855ad6278cc969a61ba871eba3594afb5c2d3c647dff5b794e160ab"},"package":"4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"} \ No newline at end of file diff --git a/vendor/crossbeam/CHANGELOG.md b/vendor/crossbeam/CHANGELOG.md deleted file mode 100644 index f756fbb73..000000000 --- a/vendor/crossbeam/CHANGELOG.md +++ /dev/null @@ -1,93 +0,0 @@ -# Version 0.8.1 - -- Support targets that do not have atomic CAS on stable Rust (#698) - -# Version 0.8.0 - -- Bump the minimum supported Rust version to 1.36. -- Bump `crossbeam-channel` to `0.5`. -- Bump `crossbeam-deque` to `0.8`. -- Bump `crossbeam-epoch` to `0.9`. -- Bump `crossbeam-queue` to `0.3`. -- Bump `crossbeam-utils` to `0.8`. - -# Version 0.7.3 - -- Fix breakage with nightly feature due to rust-lang/rust#65214. -- Bump `crossbeam-channel` to `0.4`. -- Bump `crossbeam-epoch` to `0.8`. -- Bump `crossbeam-queue` to `0.2`. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.7.2 - -- Bump `crossbeam-channel` to `0.3.9`. -- Bump `crossbeam-epoch` to `0.7.2`. -- Bump `crossbeam-utils` to `0.6.6`. - -# Version 0.7.1 - -- Bump `crossbeam-utils` to `0.6.5`. - -# Version 0.7.0 - -- Remove `ArcCell`, `MsQueue`, and `TreiberStack`. -- Change the interface of `ShardedLock` to match `RwLock`. -- Add `SegQueue::len()`. -- Rename `SegQueue::try_pop()` to `SegQueue::pop()`. -- Change the return type of `SegQueue::pop()` to `Result`. -- Introduce `ArrayQueue`. -- Update dependencies. - -# Version 0.6.0 - -- Update dependencies. - -# Version 0.5.0 - -- Update `crossbeam-channel` to 0.3. -- Update `crossbeam-utils` to 0.6. -- Add `AtomicCell`, `SharedLock`, and `WaitGroup`. - -# Version 0.4.1 - -- Fix a double-free bug in `MsQueue` and `SegQueue`. - -# Version 0.4 - -- Switch to the new implementation of epoch-based reclamation in - [`crossbeam-epoch`](https://github.com/crossbeam-rs/crossbeam-epoch), fixing numerous bugs in the - old implementation. Its API is changed in a backward-incompatible way. -- Switch to the new implementation of `CachePadded` and scoped thread in - [`crossbeam-utils`](https://github.com/crossbeam-rs/crossbeam-utils). The scoped thread API is - changed in a backward-incompatible way. -- Switch to the new implementation of Chase-Lev deque in - [`crossbeam-deque`](https://github.com/crossbeam-rs/crossbeam-deque). Its API is changed in a - backward-incompatible way. -- Export channel implemented in - [`crossbeam-channel`](https://github.com/crossbeam-rs/crossbeam-channel). -- Remove `AtomicOption`. -- Implement `Default` and `From` traits. - -# Version 0.3 - -- Introduced `ScopedThreadBuilder` with the ability to name threads and set stack size -- `Worker` methods in the Chase-Lev deque don't require mutable access anymore -- Fixed a bug when unblocking `pop()` in `MsQueue` -- Implemented `Drop` for `MsQueue`, `SegQueue`, and `TreiberStack` -- Implemented `Default` for `TreiberStack` -- Added `is_empty` to `SegQueue` -- Renamed `mem::epoch` to `epoch` -- Other bug fixes - -# Version 0.2 - -- Changed existing non-blocking `pop` methods to `try_pop` -- Added blocking `pop` support to Michael-Scott queue -- Added Chase-Lev work-stealing deque - -# Version 0.1 - -- Added [epoch-based memory management](http://aturon.github.io/blog/2015/08/27/epoch/) -- Added Michael-Scott queue -- Added Segmented array queue diff --git a/vendor/crossbeam/Cargo.toml b/vendor/crossbeam/Cargo.toml deleted file mode 100644 index 71710f835..000000000 --- a/vendor/crossbeam/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "crossbeam" -version = "0.8.1" -authors = ["The Crossbeam Project Developers"] -exclude = ["/.github", "/ci"] -description = "Tools for concurrent programming" -homepage = "https://github.com/crossbeam-rs/crossbeam" -documentation = "https://docs.rs/crossbeam" -keywords = ["atomic", "garbage", "non-blocking", "lock-free", "rcu"] -categories = ["concurrency", "memory-management", "data-structures", "no-std"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" -[dependencies.cfg-if] -version = "1" - -[dependencies.crossbeam-channel] -version = "0.5" -optional = true -default-features = false - -[dependencies.crossbeam-deque] -version = "0.8" -optional = true -default-features = false - -[dependencies.crossbeam-epoch] -version = "0.9.5" -optional = true -default-features = false - -[dependencies.crossbeam-queue] -version = "0.3.2" -optional = true -default-features = false - -[dependencies.crossbeam-utils] -version = "0.8.5" -default-features = false -[dev-dependencies.rand] -version = "0.8" - -[features] -alloc = ["crossbeam-epoch/alloc", "crossbeam-queue/alloc"] -default = ["std"] -nightly = ["crossbeam-epoch/nightly", "crossbeam-utils/nightly", "crossbeam-queue/nightly"] -std = ["alloc", "crossbeam-channel/std", "crossbeam-deque/std", "crossbeam-epoch/std", "crossbeam-queue/std", "crossbeam-utils/std"] diff --git a/vendor/crossbeam/LICENSE-APACHE b/vendor/crossbeam/LICENSE-APACHE deleted file mode 100644 index bb9abdd7f..000000000 --- a/vendor/crossbeam/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2019 The Crossbeam Project Developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/crossbeam/LICENSE-MIT b/vendor/crossbeam/LICENSE-MIT deleted file mode 100644 index 068d491fd..000000000 --- a/vendor/crossbeam/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/crossbeam/README.md b/vendor/crossbeam/README.md deleted file mode 100644 index 1ed435c0a..000000000 --- a/vendor/crossbeam/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# Crossbeam - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam.svg)]( -https://crates.io/crates/crossbeam) -[![Documentation](https://docs.rs/crossbeam/badge.svg)]( -https://docs.rs/crossbeam) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides a set of tools for concurrent programming: - -#### Atomics - -* [`AtomicCell`], a thread-safe mutable memory location.(no_std) -* [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering.(no_std) - -#### Data structures - -* [`deque`], work-stealing deques for building task schedulers. -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction.(alloc) -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand.(alloc) - -#### Memory management - -* [`epoch`], an epoch-based garbage collector.(alloc) - -#### Thread synchronization - -* [`channel`], multi-producer multi-consumer channels for message passing. -* [`Parker`], a thread parking primitive. -* [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -* [`WaitGroup`], for synchronizing the beginning or end of some computation. - -#### Utilities - -* [`Backoff`], for exponential backoff in spin loops.(no_std) -* [`CachePadded`], for padding and aligning a value to the length of a cache line.(no_std) -* [`scope`], for spawning threads that borrow local variables from the stack. - -*Features marked with (no_std) can be used in `no_std` environments.*
-*Features marked with (alloc) can be used in `no_std` environments, but only if `alloc` -feature is enabled.* - -[`AtomicCell`]: https://docs.rs/crossbeam/*/crossbeam/atomic/struct.AtomicCell.html -[`AtomicConsume`]: https://docs.rs/crossbeam/*/crossbeam/atomic/trait.AtomicConsume.html -[`deque`]: https://docs.rs/crossbeam/*/crossbeam/deque/index.html -[`ArrayQueue`]: https://docs.rs/crossbeam/*/crossbeam/queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam/*/crossbeam/queue/struct.SegQueue.html -[`channel`]: https://docs.rs/crossbeam/*/crossbeam/channel/index.html -[`Parker`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.Parker.html -[`ShardedLock`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.ShardedLock.html -[`WaitGroup`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.WaitGroup.html -[`epoch`]: https://docs.rs/crossbeam/*/crossbeam/epoch/index.html -[`Backoff`]: https://docs.rs/crossbeam/*/crossbeam/utils/struct.Backoff.html -[`CachePadded`]: https://docs.rs/crossbeam/*/crossbeam/utils/struct.CachePadded.html -[`scope`]: https://docs.rs/crossbeam/*/crossbeam/fn.scope.html - -## Crates - -The main `crossbeam` crate just [re-exports](src/lib.rs) tools from -smaller subcrates: - -* [`crossbeam-channel`](crossbeam-channel) - provides multi-producer multi-consumer channels for message passing. -* [`crossbeam-deque`](crossbeam-deque) - provides work-stealing deques, which are primarily intended for building task schedulers. -* [`crossbeam-epoch`](crossbeam-epoch) - provides epoch-based garbage collection for building concurrent data structures. -* [`crossbeam-queue`](crossbeam-queue) - provides concurrent queues that can be shared among threads. -* [`crossbeam-utils`](crossbeam-utils) - provides atomics, synchronization primitives, scoped threads, and other utilities. - -There is one more experimental subcrate that is not yet included in `crossbeam`: - -* [`crossbeam-skiplist`](crossbeam-skiplist) - provides concurrent maps and sets based on lock-free skip lists. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam = "0.8" -``` - -## Compatibility - -Crossbeam supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. - -## Contributing - -Crossbeam welcomes contribution from everyone in the form of suggestions, bug reports, -pull requests, and feedback. 💛 - -If you need ideas for contribution, there are several ways to get started: - -* Found a bug or have a feature request? - [Submit an issue](https://github.com/crossbeam-rs/crossbeam/issues/new)! -* Issues and PRs labeled with - [feedback wanted](https://github.com/crossbeam-rs/crossbeam/issues?utf8=%E2%9C%93&q=is%3Aopen+sort%3Aupdated-desc+label%3A%22feedback+wanted%22+) - need feedback from users and contributors. -* Issues labeled with - [good first issue](https://github.com/crossbeam-rs/crossbeam/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) - are relatively easy starter issues. - -#### RFCs - -We also have the [RFCs](https://github.com/crossbeam-rs/rfcs) repository for more -high-level discussion, which is the place where we brainstorm ideas and propose -substantial changes to Crossbeam. - -You are welcome to participate in any open -[issues](https://github.com/crossbeam-rs/rfcs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) -or -[pull requests](https://github.com/crossbeam-rs/rfcs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc). - -#### Learning resources - -If you'd like to learn more about concurrency and non-blocking data structures, there's a -list of learning resources in our [wiki](https://github.com/crossbeam-rs/rfcs/wiki), -which includes relevant blog posts, papers, videos, and other similar projects. - -Another good place to visit is [merged RFCs](https://github.com/crossbeam-rs/rfcs/tree/master/text). -They contain elaborate descriptions and rationale for features we've introduced to -Crossbeam, but keep in mind that some of the written information is now out of date. - -#### Conduct - -The Crossbeam project adheres to the -[Rust Code of Conduct](https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md). -This describes the minimum behavior expected from all contributors. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -Some Crossbeam subcrates have additional licensing notices. -Take a look at other readme files in this repository for more information. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/vendor/crossbeam/no_atomic.rs b/vendor/crossbeam/no_atomic.rs deleted file mode 100644 index 522b3b8ac..000000000 --- a/vendor/crossbeam/no_atomic.rs +++ /dev/null @@ -1,59 +0,0 @@ -// This file is @generated by no_atomic.sh. -// It is not intended for manual editing. - -const NO_ATOMIC_CAS: &[&str] = &[ - "avr-unknown-gnu-atmega328", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32imc-unknown-none-elf", - "thumbv4t-none-eabi", - "thumbv6m-none-eabi", -]; -#[allow(dead_code)] -const NO_ATOMIC_64: &[&str] = &[ - "arm-linux-androideabi", - "armebv7r-none-eabi", - "armebv7r-none-eabihf", - "armv4t-unknown-linux-gnueabi", - "armv5te-unknown-linux-gnueabi", - "armv5te-unknown-linux-musleabi", - "armv5te-unknown-linux-uclibceabi", - "armv7r-none-eabi", - "armv7r-none-eabihf", - "hexagon-unknown-linux-musl", - "mips-unknown-linux-gnu", - "mips-unknown-linux-musl", - "mips-unknown-linux-uclibc", - "mipsel-unknown-linux-gnu", - "mipsel-unknown-linux-musl", - "mipsel-unknown-linux-uclibc", - "mipsel-unknown-none", - "mipsisa32r6-unknown-linux-gnu", - "mipsisa32r6el-unknown-linux-gnu", - "powerpc-unknown-linux-gnu", - "powerpc-unknown-linux-gnuspe", - "powerpc-unknown-linux-musl", - "powerpc-unknown-netbsd", - "powerpc-unknown-openbsd", - "powerpc-wrs-vxworks", - "powerpc-wrs-vxworks-spe", - "riscv32gc-unknown-linux-gnu", - "riscv32gc-unknown-linux-musl", - "riscv32imac-unknown-none-elf", - "thumbv7em-none-eabi", - "thumbv7em-none-eabihf", - "thumbv7m-none-eabi", - "thumbv8m.base-none-eabi", - "thumbv8m.main-none-eabi", - "thumbv8m.main-none-eabihf", - "mipsel-sony-psp", - "thumbv4t-none-eabi", - "thumbv6m-none-eabi", -]; -#[allow(dead_code)] -const NO_ATOMIC: &[&str] = &[ - "avr-unknown-gnu-atmega328", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32imc-unknown-none-elf", -]; diff --git a/vendor/crossbeam/src/lib.rs b/vendor/crossbeam/src/lib.rs deleted file mode 100644 index 9bc3ec111..000000000 --- a/vendor/crossbeam/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Tools for concurrent programming. -//! -//! ## Atomics -//! -//! * [`AtomicCell`], a thread-safe mutable memory location. -//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. -//! -//! ## Data structures -//! -//! * [`deque`], work-stealing deques for building task schedulers. -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. -//! -//! ## Memory management -//! -//! * [`epoch`], an epoch-based garbage collector. -//! -//! ## Thread synchronization -//! -//! * [`channel`], multi-producer multi-consumer channels for message passing. -//! * [`Parker`], a thread parking primitive. -//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. -//! -//! ## Utilities -//! -//! * [`Backoff`], for exponential backoff in spin loops. -//! * [`CachePadded`], for padding and aligning a value to the length of a cache line. -//! * [`scope`], for spawning threads that borrow local variables from the stack. -//! -//! [`AtomicCell`]: atomic::AtomicCell -//! [`AtomicConsume`]: atomic::AtomicConsume -//! [`ArrayQueue`]: queue::ArrayQueue -//! [`SegQueue`]: queue::SegQueue -//! [`Parker`]: sync::Parker -//! [`ShardedLock`]: sync::ShardedLock -//! [`WaitGroup`]: sync::WaitGroup -//! [`Backoff`]: utils::Backoff -//! [`CachePadded`]: utils::CachePadded - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -pub use crossbeam_utils::atomic; - -pub mod utils { - //! Miscellaneous utilities. - //! - //! * [`Backoff`], for exponential backoff in spin loops. - //! * [`CachePadded`], for padding and aligning a value to the length of a cache line. - - pub use crossbeam_utils::Backoff; - pub use crossbeam_utils::CachePadded; -} - -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(feature = "alloc")] { - #[doc(inline)] - pub use crossbeam_epoch as epoch; - - #[doc(inline)] - pub use crossbeam_queue as queue; - } -} - -cfg_if! { - if #[cfg(feature = "std")] { - #[doc(inline)] - pub use crossbeam_deque as deque; - - #[doc(inline)] - pub use crossbeam_channel as channel; - pub use crossbeam_channel::select; - - pub use crossbeam_utils::sync; - - #[cfg(not(crossbeam_loom))] - pub use crossbeam_utils::thread; - #[cfg(not(crossbeam_loom))] - pub use crossbeam_utils::thread::scope; - } -} diff --git a/vendor/crossbeam/tests/subcrates.rs b/vendor/crossbeam/tests/subcrates.rs deleted file mode 100644 index 21b99fb0e..000000000 --- a/vendor/crossbeam/tests/subcrates.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Makes sure subcrates are properly re-exported. - -use crossbeam::select; - -#[test] -fn channel() { - let (s, r) = crossbeam::channel::bounded(1); - - select! { - send(s, 0) -> res => res.unwrap(), - recv(r) -> res => assert!(res.is_ok()), - } -} - -#[test] -fn deque() { - let w = crossbeam::deque::Worker::new_fifo(); - w.push(1); - let _ = w.pop(); -} - -#[test] -fn epoch() { - crossbeam::epoch::pin(); -} - -#[test] -fn queue() { - let a = crossbeam::queue::ArrayQueue::new(10); - let _ = a.push(1); - let _ = a.pop(); -} - -#[test] -fn utils() { - crossbeam::utils::CachePadded::new(7); - - crossbeam::scope(|scope| { - scope.spawn(|_| ()); - }) - .unwrap(); - - crossbeam::thread::scope(|scope| { - scope.spawn(|_| ()); - }) - .unwrap(); -} diff --git a/vendor/digest-0.8.1/.cargo-checksum.json b/vendor/digest-0.8.1/.cargo-checksum.json deleted file mode 100644 index ed59510b2..000000000 --- a/vendor/digest-0.8.1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"bfdc024e55a5d9f2f415045e9083abb13159e0276c3eb3dbdca290c69f8b4824","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"5890305be2cd3d221d1c2ce295b911cc57017dc341966ba434def4a072f8bf1c","src/digest.rs":"73f564cb8084e61baf850948443bacdea81727dfbff5abeb520c0e5bb690da7a","src/dyn_digest.rs":"abfa9a30ed2dc71ad2042501961146c87fe3cbf9254b5b203fe24920d0e246b8","src/errors.rs":"2584007e98d691160313cc27e6237db9bd886e9774137b59a1289a20054e9375","src/lib.rs":"71d838697e87561de4b6b2fda94df44639a525d4469316d4ad21f0f0075a130d"},"package":"f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"} \ No newline at end of file diff --git a/vendor/digest-0.8.1/Cargo.toml b/vendor/digest-0.8.1/Cargo.toml deleted file mode 100644 index d36300769..000000000 --- a/vendor/digest-0.8.1/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "digest" -version = "0.8.1" -authors = ["RustCrypto Developers"] -description = "Traits for cryptographic hash functions" -documentation = "https://docs.rs/digest" -keywords = ["digest", "crypto", "hash"] -categories = ["cryptography", "no-std"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/RustCrypto/traits" -[package.metadata.docs.rs] -features = ["std"] -[dependencies.blobby] -version = "0.1" -optional = true - -[dependencies.generic-array] -version = "0.12" - -[features] -dev = ["blobby"] -std = [] -[badges.travis-ci] -repository = "RustCrypto/traits" diff --git a/vendor/digest-0.8.1/LICENSE-APACHE b/vendor/digest-0.8.1/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/vendor/digest-0.8.1/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/digest-0.8.1/LICENSE-MIT b/vendor/digest-0.8.1/LICENSE-MIT deleted file mode 100644 index 8dcb85b30..000000000 --- a/vendor/digest-0.8.1/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 Artyom Pavlov - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/digest-0.8.1/src/dev.rs b/vendor/digest-0.8.1/src/dev.rs deleted file mode 100644 index e9950ee79..000000000 --- a/vendor/digest-0.8.1/src/dev.rs +++ /dev/null @@ -1,218 +0,0 @@ -use super::{Input, VariableOutput, ExtendableOutput, Reset, XofReader}; -use core::fmt::Debug; - -#[macro_export] -macro_rules! new_test { - ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => { - #[test] - fn $name() { - use digest::blobby::Blob2Iterator; - let data = include_bytes!(concat!("data/", $test_name, ".blb")); - - for (i, row) in Blob2Iterator::new(data).unwrap().enumerate() { - let input = row[0]; - let output = row[1]; - if let Some(desc) = $test_func::<$hasher>(input, output) { - panic!("\n\ - Failed test №{}: {}\n\ - input:\t{:?}\n\ - output:\t{:?}\n", - i, desc, input, output, - ); - } - } - } - } -} - -// module to separate Digest from other traits -mod foo { - use super::super::Digest; - use core::fmt::Debug; - - pub fn digest_test(input: &[u8], output: &[u8]) -> Option<&'static str> - where D: Digest + Debug + Clone - { - let mut hasher = D::new(); - // Test that it works when accepting the message all at once - hasher.input(input); - let mut hasher2 = hasher.clone(); - if hasher.result().as_slice() != output { - return Some("whole message"); - } - - // Test if reset works correctly - hasher2.reset(); - hasher2.input(input); - if hasher2.result().as_slice() != output { - return Some("whole message after reset"); - } - - // Test that it works when accepting the message in pieces - let mut hasher = D::new(); - let len = input.len(); - let mut left = len; - while left > 0 { - let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; - } - if hasher.result().as_slice() != output { - return Some("message in pieces"); - } - - // Test processing byte-by-byte - let mut hasher = D::new(); - for chunk in input.chunks(1) { - hasher.input(chunk) - } - if hasher.result().as_slice() != output { - return Some("message byte-by-byte"); - } - None - } - - - pub fn one_million_a(expected: &[u8]) - where D: Digest + Debug + Clone - { - let mut sh = D::new(); - for _ in 0..50_000 { - sh.input(&[b'a'; 10]); - } - sh.input(&[b'a'; 500_000][..]); - let out = sh.result(); - assert_eq!(out[..], expected[..]); - } -} - -pub use self::foo::{digest_test, one_million_a}; - -pub fn xof_test(input: &[u8], output: &[u8]) - -> Option<&'static str> - where D: Input + ExtendableOutput + Default + Debug + Reset + Clone -{ - let mut hasher = D::default(); - let mut buf = [0u8; 1024]; - // Test that it works when accepting the message all at once - hasher.input(input); - - let mut hasher2 = hasher.clone(); - { - let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); - - if out != output { return Some("whole message"); } - } - - // Test if hasher resets correctly - hasher2.reset(); - hasher2.input(input); - - { - let out = &mut buf[..output.len()]; - hasher2.xof_result().read(out); - - if out != output { return Some("whole message after reset"); } - } - - // Test if hasher accepts message in pieces correctly - let mut hasher = D::default(); - let len = input.len(); - let mut left = len; - while left > 0 { - let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; - } - - { - let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); - if out != output { return Some("message in pieces"); } - } - - // Test reading from reader byte by byte - let mut hasher = D::default(); - hasher.input(input); - - let mut reader = hasher.xof_result(); - let out = &mut buf[..output.len()]; - for chunk in out.chunks_mut(1) { - reader.read(chunk); - } - - if out != output { return Some("message in pieces"); } - None -} - -pub fn variable_test(input: &[u8], output: &[u8]) - -> Option<&'static str> - where D: Input + VariableOutput + Reset + Debug + Clone -{ - let mut hasher = D::new(output.len()).unwrap(); - let mut buf = [0u8; 128]; - let buf = &mut buf[..output.len()]; - // Test that it works when accepting the message all at once - hasher.input(input); - let mut hasher2 = hasher.clone(); - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("whole message"); } - - // Test if reset works correctly - hasher2.reset(); - hasher2.input(input); - hasher2.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("whole message after reset"); } - - // Test that it works when accepting the message in pieces - let mut hasher = D::new(output.len()).unwrap(); - let len = input.len(); - let mut left = len; - while left > 0 { - let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; - } - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("message in pieces"); } - - // Test processing byte-by-byte - let mut hasher = D::new(output.len()).unwrap(); - for chunk in input.chunks(1) { - hasher.input(chunk) - } - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("message byte-by-byte"); } - None -} - - -#[macro_export] -macro_rules! bench { - ($name:ident, $engine:path, $bs:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - let mut d = <$engine>::default(); - let data = [0; $bs]; - - b.iter(|| { - d.input(&data[..]); - }); - - b.bytes = $bs; - } - }; - - ($engine:path) => { - extern crate test; - - use test::Bencher; - use digest::Digest; - - bench!(bench1_10, $engine, 10); - bench!(bench2_100, $engine, 100); - bench!(bench3_1000, $engine, 1000); - bench!(bench4_10000, $engine, 10000); - } -} diff --git a/vendor/digest-0.8.1/src/digest.rs b/vendor/digest-0.8.1/src/digest.rs deleted file mode 100644 index 50128e13e..000000000 --- a/vendor/digest-0.8.1/src/digest.rs +++ /dev/null @@ -1,86 +0,0 @@ -use super::{Input, FixedOutput, Reset}; -use generic_array::{GenericArray, ArrayLength}; -use generic_array::typenum::Unsigned; - -/// The `Digest` trait specifies an interface common for digest functions. -/// -/// It's a convenience wrapper around `Input`, `FixedOutput`, `Reset`, `Clone`, -/// and `Default` traits. It also provides additional convenience methods. -pub trait Digest { - type OutputSize: ArrayLength; - /// Create new hasher instance - fn new() -> Self; - - /// Digest input data. - /// - /// This method can be called repeatedly for use with streaming messages. - fn input>(&mut self, data: B); - - /// Digest input data in a chained manner. - fn chain>(self, data: B) -> Self where Self: Sized; - - /// Retrieve result and consume hasher instance. - fn result(self) -> GenericArray; - - /// Retrieve result and reset hasher instance. - /// - /// This method sometimes can be more efficient compared to hasher - /// re-creation. - fn result_reset(&mut self) -> GenericArray; - - /// Reset hasher instance to its initial state. - fn reset(&mut self); - - /// Get output size of the hasher - fn output_size() -> usize; - - /// Convenience function to compute hash of the `data`. It will handle - /// hasher creation, data feeding and finalization. - /// - /// Example: - /// - /// ```rust,ignore - /// println!("{:x}", sha2::Sha256::digest(b"Hello world")); - /// ``` - fn digest(data: &[u8]) -> GenericArray; -} - -impl Digest for D { - type OutputSize = ::OutputSize; - - fn new() -> Self { - Self::default() - } - - fn input>(&mut self, data: B) { - Input::input(self, data); - } - - fn chain>(self, data: B) -> Self where Self: Sized { - Input::chain(self, data) - } - - fn result(self) -> GenericArray { - self.fixed_result() - } - - fn result_reset(&mut self) -> GenericArray { - let res = self.clone().fixed_result(); - self.reset(); - res - } - - fn reset(&mut self) { - ::reset(self) - } - - fn output_size() -> usize { - Self::OutputSize::to_usize() - } - - fn digest(data: &[u8]) -> GenericArray { - let mut hasher = Self::default(); - Input::input(&mut hasher, data); - hasher.fixed_result() - } -} diff --git a/vendor/digest-0.8.1/src/dyn_digest.rs b/vendor/digest-0.8.1/src/dyn_digest.rs deleted file mode 100644 index 2af43a8e3..000000000 --- a/vendor/digest-0.8.1/src/dyn_digest.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![cfg(feature = "std")] -use std::boxed::Box; - -use super::{Input, FixedOutput, Reset}; -use generic_array::typenum::Unsigned; - -/// The `DynDigest` trait is a modification of `Digest` trait suitable -/// for trait objects. -pub trait DynDigest { - /// Digest input data. - /// - /// This method can be called repeatedly for use with streaming messages. - fn input(&mut self, data: &[u8]); - - /// Retrieve result and reset hasher instance - fn result_reset(&mut self) -> Box<[u8]>; - - /// Retrieve result and consume boxed hasher instance - fn result(self: Box) -> Box<[u8]>; - - /// Reset hasher instance to its initial state. - fn reset(&mut self); - - /// Get output size of the hasher - fn output_size(&self) -> usize; - - /// Clone hasher state into a boxed trait object - fn box_clone(&self) -> Box; -} - -impl DynDigest for D { - fn input(&mut self, data: &[u8]) { - Input::input(self, data); - } - - fn result_reset(&mut self) -> Box<[u8]> { - let res = self.clone().fixed_result().to_vec().into_boxed_slice(); - Reset::reset(self); - res - } - - fn result(self: Box) -> Box<[u8]> { - self.fixed_result().to_vec().into_boxed_slice() - } - - fn reset(&mut self) { - Reset::reset(self); - } - - fn output_size(&self) -> usize { - ::OutputSize::to_usize() - } - - fn box_clone(&self) -> Box { - Box::new(self.clone()) - } -} - -impl Clone for Box { - fn clone(&self) -> Self { - self.box_clone() - } -} diff --git a/vendor/digest-0.8.1/src/errors.rs b/vendor/digest-0.8.1/src/errors.rs deleted file mode 100644 index aa026a21a..000000000 --- a/vendor/digest-0.8.1/src/errors.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::fmt; -#[cfg(feature = "std")] -use std::error; - -/// The error type for variable hasher initialization -#[derive(Clone, Copy, Debug, Default)] -pub struct InvalidOutputSize; - -impl fmt::Display for InvalidOutputSize { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("invalid output size") - } -} - -#[cfg(feature = "std")] -impl error::Error for InvalidOutputSize { - fn description(&self) -> &str { - "invalid output size" - } -} diff --git a/vendor/digest-0.8.1/src/lib.rs b/vendor/digest-0.8.1/src/lib.rs deleted file mode 100644 index f03c50107..000000000 --- a/vendor/digest-0.8.1/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -//! This crate provides traits which describe functionality of cryptographic hash -//! functions. -//! -//! Traits in this repository can be separated into two levels: -//! - Low level traits: `Input`, `BlockInput`, `Reset`, `FixedOutput`, -//! `VariableOutput`, `ExtendableOutput`. These traits atomically describe -//! available functionality of hash function implementations. -//! - Convenience trait: `Digest`, `DynDigest`. They are wrappers around -//! low level traits for most common hash-function use-cases. -//! -//! Additionally hash functions implement traits from `std`: `Default`, `Clone`, -//! `Write`. (the latter depends on enabled-by-default `std` crate feature) -//! -//! The `Digest` trait is the most commonly used trait. -#![no_std] -#![doc(html_logo_url = - "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] -pub extern crate generic_array; -#[cfg(feature = "std")] -#[macro_use] extern crate std; -#[cfg(feature = "dev")] -pub extern crate blobby; -use generic_array::{GenericArray, ArrayLength}; -#[cfg(feature = "std")] -use std::vec::Vec; - -mod digest; -mod dyn_digest; -mod errors; -#[cfg(feature = "dev")] -pub mod dev; - -pub use errors::InvalidOutputSize; -pub use digest::Digest; -#[cfg(feature = "std")] -pub use dyn_digest::DynDigest; - -/// Trait for processing input data -pub trait Input { - /// Digest input data. - /// - /// This method can be called repeatedly, e.g. for processing streaming - /// messages. - fn input>(&mut self, data: B); - - /// Digest input data in a chained manner. - fn chain>(mut self, data: B) -> Self where Self: Sized { - self.input(data); - self - } -} - -/// Trait to indicate that digest function processes data in blocks of size -/// `BlockSize`. -/// -/// The main usage of this trait is for implementing HMAC generically. -pub trait BlockInput { - type BlockSize: ArrayLength; -} - -/// Trait for returning digest result with the fixed size -pub trait FixedOutput { - type OutputSize: ArrayLength; - - /// Retrieve result and consume hasher instance. - fn fixed_result(self) -> GenericArray; -} - -/// Trait for returning digest result with the variable size -pub trait VariableOutput: core::marker::Sized { - /// Create new hasher instance with the given output size. - /// - /// It will return `Err(InvalidOutputSize)` in case if hasher can not return - /// specified output size. It will always return an error if output size - /// equals to zero. - fn new(output_size: usize) -> Result; - - /// Get output size of the hasher instance provided to the `new` method - fn output_size(&self) -> usize; - - /// Retrieve result via closure and consume hasher. - /// - /// Closure is guaranteed to be called, length of the buffer passed to it - /// will be equal to `output_size`. - fn variable_result(self, f: F); - - /// Retrieve result into vector and consume hasher. - #[cfg(feature = "std")] - fn vec_result(self) -> Vec { - let mut buf = Vec::with_capacity(self.output_size()); - self.variable_result(|res| buf.extend_from_slice(res)); - buf - } -} - -/// Trait for describing readers which are used to extract extendable output -/// from XOF (extendable-output function) result. -pub trait XofReader { - /// Read output into the `buffer`. Can be called unlimited number of times. - fn read(&mut self, buffer: &mut [u8]); -} - -/// Trait which describes extendable-output functions (XOF). -pub trait ExtendableOutput: core::marker::Sized { - type Reader: XofReader; - - /// Retrieve XOF reader and consume hasher instance. - fn xof_result(self) -> Self::Reader; - - /// Retrieve result into vector of specified length. - #[cfg(feature = "std")] - fn vec_result(self, n: usize) -> Vec { - let mut buf = vec![0u8; n]; - self.xof_result().read(&mut buf); - buf - } -} - -/// Trait for resetting hash instances -pub trait Reset { - /// Reset hasher instance to its initial state and return current state. - fn reset(&mut self); -} - -#[macro_export] -/// Implements `std::io::Write` trait for implementer of `Input` -macro_rules! impl_write { - ($hasher:ident) => { - #[cfg(feature = "std")] - impl ::std::io::Write for $hasher { - fn write(&mut self, buf: &[u8]) -> ::std::io::Result { - Input::input(self, buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> ::std::io::Result<()> { - Ok(()) - } - } - } -} diff --git a/vendor/either/.cargo-checksum.json b/vendor/either/.cargo-checksum.json index 207aba04a..5e1f8841d 100644 --- a/vendor/either/.cargo-checksum.json +++ b/vendor/either/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"77c37f327af7a6146ba111c1c0a3e861bd444f31cfe44c3645c8e090502f66b4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README-crates.io.md":"b775991a01ab4a0a8de6169f597775319d9ce8178f5c74ccdc634f13a286b20c","README.rst":"f948f4333e9d66477128bcaf69a449a139bf00633eb57491fa1b379a3ce30b74","src/lib.rs":"e0f7c05e75af07765c2298a1791c65ea80f3c099491ed95c2e6c771041aa9931","src/serde_untagged.rs":"e826ee0ab31616e49c3e3f3711c8441001ee424b3e7a8c4c466cfcc4f8a7701a","src/serde_untagged_optional.rs":"86265f09d0795428bb2ce013b070d1badf1e2210217844a9ff3f04b2795868ab"},"package":"3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"} \ No newline at end of file +{"files":{"Cargo.toml":"321950b99b4f04079e2470d754419bedba9851b71d1a2d8bd9c9046e38b87640","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README-crates.io.md":"b775991a01ab4a0a8de6169f597775319d9ce8178f5c74ccdc634f13a286b20c","README.rst":"1369598deaae0ff925e8910df42354d33a43606961c40e7b71a7454a7f0b775e","src/lib.rs":"bc950126c901ea5c12ce4d02a7e58e3b1e2b428caca68bd510bad1f2488e2ced","src/serde_untagged.rs":"e826ee0ab31616e49c3e3f3711c8441001ee424b3e7a8c4c466cfcc4f8a7701a","src/serde_untagged_optional.rs":"86265f09d0795428bb2ce013b070d1badf1e2210217844a9ff3f04b2795868ab"},"package":"90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"} \ No newline at end of file diff --git a/vendor/either/Cargo.toml b/vendor/either/Cargo.toml index d571ff8da..eb1c5b4b5 100644 --- a/vendor/either/Cargo.toml +++ b/vendor/either/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2018" -rust-version = "1.31" +rust-version = "1.36" name = "either" -version = "1.7.0" +version = "1.8.0" authors = ["bluss"] description = """ The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases. diff --git a/vendor/either/README.rst b/vendor/either/README.rst index 992e49c50..43c156a9f 100644 --- a/vendor/either/README.rst +++ b/vendor/either/README.rst @@ -25,12 +25,23 @@ __ https://docs.rs/either/ How to use with cargo:: [dependencies] - either = "1.7" + either = "1.8" Recent Changes -------------- +- 1.8.0 + + - **MSRV**: ``either`` now requires Rust 1.36 or later. + + - Add new methods ``.as_pin_ref()`` and ``.as_pin_mut()`` to project a + pinned ``Either`` as inner ``Pin`` variants, by @cuviper (#77) + + - Implement the ``Future`` trait, by @cuviper (#77) + + - Specialize more methods of the ``io`` traits, by @Kixunil and @cuviper (#75) + - 1.7.0 - **MSRV**: ``either`` now requires Rust 1.31 or later. diff --git a/vendor/either/src/lib.rs b/vendor/either/src/lib.rs index a4f2a5454..9a271c351 100644 --- a/vendor/either/src/lib.rs +++ b/vendor/either/src/lib.rs @@ -26,9 +26,11 @@ pub mod serde_untagged_optional; use core::convert::{AsMut, AsRef}; use core::fmt; +use core::future::Future; use core::iter; use core::ops::Deref; use core::ops::DerefMut; +use core::pin::Pin; #[cfg(any(test, feature = "use_std"))] use std::error::Error; @@ -255,6 +257,35 @@ impl Either { } } + /// Convert `Pin<&Either>` to `Either, Pin<&R>>`, + /// pinned projections of the inner variants. + pub fn as_pin_ref(self: Pin<&Self>) -> Either, Pin<&R>> { + // SAFETY: We can use `new_unchecked` because the `inner` parts are + // guaranteed to be pinned, as they come from `self` which is pinned. + unsafe { + match *Pin::get_ref(self) { + Left(ref inner) => Left(Pin::new_unchecked(inner)), + Right(ref inner) => Right(Pin::new_unchecked(inner)), + } + } + } + + /// Convert `Pin<&mut Either>` to `Either, Pin<&mut R>>`, + /// pinned projections of the inner variants. + pub fn as_pin_mut(self: Pin<&mut Self>) -> Either, Pin<&mut R>> { + // SAFETY: `get_unchecked_mut` is fine because we don't move anything. + // We can use `new_unchecked` because the `inner` parts are guaranteed + // to be pinned, as they come from `self` which is pinned, and we never + // offer an unpinned `&mut L` or `&mut R` through `Pin<&mut Self>`. We + // also don't have an implementation of `Drop`, nor manual `Unpin`. + unsafe { + match *Pin::get_unchecked_mut(self) { + Left(ref mut inner) => Left(Pin::new_unchecked(inner)), + Right(ref mut inner) => Right(Pin::new_unchecked(inner)), + } + } + } + /// Convert `Either` to `Either`. /// /// ``` @@ -1038,6 +1069,22 @@ where { } +/// `Either` is a future if both `L` and `R` are futures. +impl Future for Either +where + L: Future, + R: Future, +{ + type Output = L::Output; + + fn poll( + self: Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + for_both!(self.as_pin_mut(), inner => inner.poll(cx)) + } +} + #[cfg(any(test, feature = "use_std"))] /// `Either` implements `Read` if both `L` and `R` do. /// @@ -1051,9 +1098,17 @@ where for_both!(*self, ref mut inner => inner.read(buf)) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.read_exact(buf)) + } + fn read_to_end(&mut self, buf: &mut std::vec::Vec) -> io::Result { for_both!(*self, ref mut inner => inner.read_to_end(buf)) } + + fn read_to_string(&mut self, buf: &mut std::string::String) -> io::Result { + for_both!(*self, ref mut inner => inner.read_to_string(buf)) + } } #[cfg(any(test, feature = "use_std"))] @@ -1084,6 +1139,14 @@ where fn consume(&mut self, amt: usize) { for_both!(*self, ref mut inner => inner.consume(amt)) } + + fn read_until(&mut self, byte: u8, buf: &mut std::vec::Vec) -> io::Result { + for_both!(*self, ref mut inner => inner.read_until(byte, buf)) + } + + fn read_line(&mut self, buf: &mut std::string::String) -> io::Result { + for_both!(*self, ref mut inner => inner.read_line(buf)) + } } #[cfg(any(test, feature = "use_std"))] @@ -1099,6 +1162,14 @@ where for_both!(*self, ref mut inner => inner.write(buf)) } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.write_all(buf)) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.write_fmt(fmt)) + } + fn flush(&mut self) -> io::Result<()> { for_both!(*self, ref mut inner => inner.flush()) } diff --git a/vendor/fake-simd/.cargo-checksum.json b/vendor/fake-simd/.cargo-checksum.json deleted file mode 100644 index f91a4a68f..000000000 --- a/vendor/fake-simd/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"c63db0226f9aac6e001898735c81392b8f01dfc8b7245f37e290990562c3c0d8","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"52232c2cee3bb7d8cabe47ef367f1bf8bb607c22bdfca0219d6156cb7f446e9d","src/lib.rs":"2cd66d61acfb96f3425194c12695d8e55cf56c6fbd02de90033c45bdcc338c1a"},"package":"e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"} \ No newline at end of file diff --git a/vendor/fake-simd/Cargo.toml b/vendor/fake-simd/Cargo.toml deleted file mode 100644 index 135c66097..000000000 --- a/vendor/fake-simd/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "fake-simd" -version = "0.1.2" -authors = ["The Rust-Crypto Project Developers"] -license = "MIT/Apache-2.0" -description = "Crate for mimicking simd crate on stable Rust" -documentation = "https://docs.rs/fake-simd" -repository = "https://github.com/RustCrypto/utils" -keywords = ["simd"] diff --git a/vendor/fake-simd/LICENSE-APACHE b/vendor/fake-simd/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/vendor/fake-simd/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/fake-simd/LICENSE-MIT b/vendor/fake-simd/LICENSE-MIT deleted file mode 100644 index 1da3a5f6d..000000000 --- a/vendor/fake-simd/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2006-2009 Graydon Hoare -Copyright (c) 2009-2013 Mozilla Foundation - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/fake-simd/src/lib.rs b/vendor/fake-simd/src/lib.rs deleted file mode 100644 index 22c8727ed..000000000 --- a/vendor/fake-simd/src/lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -#![no_std] -use core::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub}; - -#[derive(Clone, Copy, PartialEq, Eq)] -#[allow(non_camel_case_types)] -pub struct u32x4(pub u32, pub u32, pub u32, pub u32); - -impl Add for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn add(self, rhs: u32x4) -> u32x4 { - u32x4( - self.0.wrapping_add(rhs.0), - self.1.wrapping_add(rhs.1), - self.2.wrapping_add(rhs.2), - self.3.wrapping_add(rhs.3)) - } -} - -impl Sub for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn sub(self, rhs: u32x4) -> u32x4 { - u32x4( - self.0.wrapping_sub(rhs.0), - self.1.wrapping_sub(rhs.1), - self.2.wrapping_sub(rhs.2), - self.3.wrapping_sub(rhs.3)) - } -} - -impl BitAnd for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn bitand(self, rhs: u32x4) -> u32x4 { - u32x4(self.0 & rhs.0, self.1 & rhs.1, self.2 & rhs.2, self.3 & rhs.3) - } -} - -impl BitOr for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn bitor(self, rhs: u32x4) -> u32x4 { - u32x4(self.0 | rhs.0, self.1 | rhs.1, self.2 | rhs.2, self.3 | rhs.3) - } -} - -impl BitXor for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn bitxor(self, rhs: u32x4) -> u32x4 { - u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3) - } -} - -impl Shl for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn shl(self, amt: usize) -> u32x4 { - u32x4(self.0 << amt, self.1 << amt, self.2 << amt, self.3 << amt) - } -} - -impl Shl for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn shl(self, rhs: u32x4) -> u32x4 { - u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3) - } -} - -impl Shr for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn shr(self, amt: usize) -> u32x4 { - u32x4(self.0 >> amt, self.1 >> amt, self.2 >> amt, self.3 >> amt) - } -} - -impl Shr for u32x4 { - type Output = u32x4; - - #[inline(always)] - fn shr(self, rhs: u32x4) -> u32x4 { - u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3) - } -} - -#[derive(Clone, Copy)] -#[allow(non_camel_case_types)] -pub struct u64x2(pub u64, pub u64); - -impl Add for u64x2 { - type Output = u64x2; - - #[inline(always)] - fn add(self, rhs: u64x2) -> u64x2 { - u64x2(self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1)) - } -} diff --git a/vendor/fortanix-sgx-abi/.cargo-checksum.json b/vendor/fortanix-sgx-abi/.cargo-checksum.json index 54731bac0..71c7c4425 100644 --- a/vendor/fortanix-sgx-abi/.cargo-checksum.json +++ b/vendor/fortanix-sgx-abi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2f11a404e7361ab1b4bfd6bf5189c18091df9dcedda93dce14dcb01b59a2d85a","src/lib.rs":"2493f0264dfaaac19471aa5cb3da8011ead8f804f3ac722195478894a7d011d1"},"package":"c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"} \ No newline at end of file +{"files":{"Cargo.toml":"5ef38d3c4329644a02d5fe6019ea401cdd64d31c1a26fd16cf30c7d2dd87873f","src/lib.rs":"2da4a01e8baae15069a6ea32610602f1741e8deccad696f7f7d3e69035da2962"},"package":"57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"} \ No newline at end of file diff --git a/vendor/fortanix-sgx-abi/Cargo.toml b/vendor/fortanix-sgx-abi/Cargo.toml index 1a3b9c168..28e2993bb 100644 --- a/vendor/fortanix-sgx-abi/Cargo.toml +++ b/vendor/fortanix-sgx-abi/Cargo.toml @@ -3,26 +3,41 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] name = "fortanix-sgx-abi" -version = "0.3.3" +version = "0.5.0" authors = ["Fortanix, Inc."] -description = "An interface for Intel SGX enclaves. This is the interface for the\n`x86_64-fortanix-unknown-sgx` target.\n\nThis is a small yet functional interface suitable for writing larger enclaves. \nIn contrast to other enclave interfaces, this interface is primarly designed \nfor running entire applications in an enclave.\n\nThis crate fully describes the type-level interface complete with \ndocumentation. For implementors, this crate contains all the type definitions\nand a macro with the function definitions.\n" +description = """ +An interface for Intel SGX enclaves. This is the interface for the +`x86_64-fortanix-unknown-sgx` target. + +This is a small yet functional interface suitable for writing larger enclaves. +In contrast to other enclave interfaces, this interface is primarly designed +for running entire applications in an enclave. + +This crate fully describes the type-level interface complete with +documentation. For implementors, this crate contains all the type definitions +and a macro with the function definitions. +""" homepage = "https://edp.fortanix.com/" documentation = "https://edp.fortanix.com/docs/api/fortanix_sgx_abi/" -keywords = ["sgx", "enclave"] +keywords = [ + "sgx", + "enclave", +] categories = ["os"] license = "MPL-2.0" repository = "https://github.com/fortanix/rust-sgx" + [package.metadata.docs.rs] features = ["docs"] + [dependencies.compiler_builtins] version = "0.1.0" optional = true @@ -34,4 +49,7 @@ package = "rustc-std-workspace-core" [features] docs = [] -rustc-dep-of-std = ["core", "compiler_builtins/rustc-dep-of-std"] +rustc-dep-of-std = [ + "core", + "compiler_builtins/rustc-dep-of-std", +] diff --git a/vendor/fortanix-sgx-abi/src/lib.rs b/vendor/fortanix-sgx-abi/src/lib.rs index 362defb8f..3511ae34b 100644 --- a/vendor/fortanix-sgx-abi/src/lib.rs +++ b/vendor/fortanix-sgx-abi/src/lib.rs @@ -15,7 +15,7 @@ //! The Fortanix SGX ABI (compiler target `x86_64-fortanix-unknown-sgx`) is an //! interface for Intel SGX enclaves. It is a small yet functional interface //! suitable for writing larger enclaves. In contrast to other enclave -//! interfaces, this interface is primarly designed for running entire +//! interfaces, this interface is primarily designed for running entire //! applications in an enclave. //! //! The Fortanix SGX ABI specification consists of two parts: @@ -82,7 +82,7 @@ html_root_url = "https://edp.fortanix.com/docs/api/")] use core::ptr::NonNull; -use core::sync::atomic::AtomicUsize; +use core::sync::atomic::{AtomicU64, AtomicUsize}; macro_rules! invoke_with_abi_spec [ ( $m:ident ) => [ $m![ @@ -186,6 +186,9 @@ pub struct ByteBuffer { pub len: usize } +#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] +unsafe impl Send for ByteBuffer {} + /// Error code definitions and space allocation. /// /// Only non-zero positive values are valid errors. The variants are designed @@ -222,7 +225,7 @@ pub enum Error { UserRangeEnd = 0x7fff_ffff, } -/// A value indicating that the operation was succesful. +/// A value indicating that the operation was successful. #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] pub const RESULT_SUCCESS: Result = 0; @@ -301,7 +304,7 @@ impl Usercalls { /// Read up to `len` bytes from stream `fd`. /// /// `buf` must point to a buffer in userspace with a size of at least - /// `len`. On a succesful return, the number of bytes written is returned. + /// `len`. On a successful return, the number of bytes written is returned. /// The enclave must check that the returned length is no more than `len`. /// If `len` is `0`, this call should block until the stream is ready for /// reading. If `len` is `0` or end of stream is reached, `0` may be @@ -330,7 +333,7 @@ impl Usercalls { /// Write up to `len` bytes to stream `fd`. /// /// `buf` must point to a buffer in userspace with a size of at least - /// `len`. On a succesful return, the number of bytes written is returned. + /// `len`. On a successful return, the number of bytes written is returned. /// The enclave must check that the returned length is no more than `len`. /// If `len` is `0`, this call should block until the stream is ready for /// writing. If `len` is `0` or the stream is closed, `0` may be returned. @@ -453,6 +456,10 @@ pub const EV_RETURNQ_NOT_EMPTY: u64 = 0b0000_0000_0000_0010; /// An event that enclaves can use for synchronization. #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] pub const EV_UNPARK: u64 = 0b0000_0000_0000_0100; +/// An event that will be triggered by userspace when the cancel queue is not +/// or no longer full. +#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] +pub const EV_CANCELQ_NOT_FULL: u64 = 0b0000_0000_0000_1000; #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] pub const WAIT_NO: u64 = 0; @@ -464,9 +471,10 @@ pub const WAIT_INDEFINITE: u64 = !0; /// ## TCS event queues /// /// Userspace will maintain a queue for each running TCS with events to be -/// delivered. Each event is characterized by a bitset. Userspace or the -/// enclave (using the `send` usercall) can put events on this queue. If the -/// enclave isn't waiting for an event when an event is queued, the event +/// delivered. Each event is characterized by a bitset with at least one bit +/// set. Userspace or the enclave (using the `send` usercall) can put events on +/// this queue. +/// If the enclave isn't waiting for an event when an event is queued, the event /// remains on the queue until it delivered to the enclave in a later `wait` /// usercall. If an enclave is waiting for an event, and the queue contains an /// event that is a subset of the waited-for event mask, that event is removed @@ -481,7 +489,7 @@ impl Usercalls { /// this with the number of entries into [`thread_entry`]. If no free TCSes /// are immediately available, this may return an error. /// - /// This function will never be succesful in [libraries]. See the + /// This function will never be successful in [libraries]. See the /// [`library`] documentation on how to use threads with libraries. /// /// [`thread_entry`]: entry/executable/fn.thread_entry.html @@ -503,14 +511,18 @@ impl Usercalls { /// Wait for an event to occur, or check if an event is currently pending. /// - /// `timeout` must be [`WAIT_NO`] or [`WAIT_INDEFINITE`]. If it is another - /// value, userspace will return an error. + /// `timeout` must be [`WAIT_NO`] or [`WAIT_INDEFINITE`] or a positive + /// value smaller than u64::MAX specifying number of nanoseconds to wait. /// /// If `timeout` is [`WAIT_INDEFINITE`], this call will block and return /// once a matching event is queued on this TCS. If `timeout` is /// [`WAIT_NO`], this call will return immediately, and the return value /// will indicate if an event was pending. If it was, it has been dequeued. - /// If not, the [`WouldBlock`] error value will be returned. + /// If not, the [`WouldBlock`] error value will be returned. If `timeout` + /// is a value other than [`WAIT_NO`] and [`WAIT_INDEFINITE`], this call + /// will block until either a matching event is queued in which case the + /// return value will indicate the event, or the timeout is reached in + /// which case the [`TimedOut`] error value will be returned. /// /// A matching event is one whose bits are equal to or a subset of /// `event_mask`. If `event_mask` is `0`, this call will never return due @@ -534,6 +546,7 @@ impl Usercalls { /// [`WAIT_INDEFINITE`]: constant.WAIT_INDEFINITE.html /// [`EV_RETURNQ_NOT_EMPTY`]: constant.EV_RETURNQ_NOT_EMPTY.html /// [`WouldBlock`]: enum.Error.html#variant.WouldBlock + /// [`TimedOut`]: enum.Error.html#variant.TimedOut pub fn wait(event_mask: u64, timeout: u64) -> (Result, u64) { unimplemented!() } /// Send an event to one or all TCSes. @@ -568,7 +581,7 @@ impl Usercalls { /// Request user memory. /// /// Request an allocation in user memory of size `size` and with alignment - /// `align`. If succesful, a pointer to this memory will be returned. The + /// `align`. If successful, a pointer to this memory will be returned. The /// enclave must check the pointer is correctly aligned and that the entire /// range of memory pointed to is outside the enclave. /// @@ -589,7 +602,7 @@ impl Usercalls { /// Asynchronous usercall specification. /// /// An asynchronous usercall allows an enclave to submit a usercall without -/// exiting the enclave. This is necessary since enclave entries and exists are +/// exiting the enclave. This is necessary since enclave entries and exits are /// slow (see academic work on [SCONE], [HotCalls]). In addition, the enclave /// can perform other tasks while it waits for the usercall to complete. Those /// tasks may include issuing other usercalls, either synchronously or @@ -605,18 +618,40 @@ impl Usercalls { /// concurrent usercalls with the same `id`, but it may reuse an `id` once the /// original usercall with that `id` has returned. /// +/// An optional third queue can be used to cancel usercalls. To cancel an async +/// usercall, the enclave should send the usercall's id and number on this +/// queue. If the usercall has already been processed, the enclave may still +/// receive a successful result for the usercall. Otherwise, the userspace will +/// cancel the usercall's execution and return an [`Interrupted`] error on the +/// return queue to notify the enclave of the cancellation. Note that usercalls +/// that do not return [`Result`] cannot be cancelled and if the enclave sends +/// a cancellation for such a usercall, the userspace should simply ignore it. +/// Additionally, userspace may choose to ignore cancellations for non-blocking +/// usercalls. Userspace should be able to cancel a usercall that has been sent +/// by the enclave but not yet received by the userspace, i.e. if cancellation +/// is received before the usercall itself. To avoid keeping such cancellations +/// forever and preventing the enclave from re-using usercall ids, userspace +/// should synchronize cancel queue with the usercall queue such that the +/// following invariant is maintained: whenever the enclave writes an id to the +/// usercall or cancel queue, the enclave will not reuse that id until the +/// usercall queue's read pointer has advanced to the write pointer at the time +/// the id was written. +/// /// *TODO*: Add diagram. /// /// [MPSC queues]: struct.FifoDescriptor.html /// [allocated per enclave]: ../struct.Usercalls.html#method.async_queues /// [SCONE]: https://www.usenix.org/conference/osdi16/technical-sessions/presentation/arnautov /// [HotCalls]: http://www.ofirweisse.com/ISCA17_Ofir_Weisse.pdf +/// [`Interrupted`]: enum.Error.html#variant.Interrupted +/// [`Result`]: type.Result.html /// /// # Enclave/userspace synchronization /// /// When the enclave needs to wait on a queue, it executes the [`wait()`] /// usercall synchronously, specifying [`EV_USERCALLQ_NOT_FULL`], -/// [`EV_RETURNQ_NOT_EMPTY`], or both in the `event_mask`. Userspace will wake +/// [`EV_RETURNQ_NOT_EMPTY`], [`EV_CANCELQ_NOT_FULL`], or any combination +/// thereof in the `event_mask`. Userspace will wake /// any or all threads waiting on the appropriate event when it is triggered. /// /// When userspace needs to wait on a queue, it will park the current thread @@ -627,34 +662,70 @@ impl Usercalls { /// [`wait()`]: ../struct.Usercalls.html#method.wait /// [`EV_USERCALLQ_NOT_FULL`]: ../constant.EV_USERCALLQ_NOT_FULL.html /// [`EV_RETURNQ_NOT_EMPTY`]: ../constant.EV_RETURNQ_NOT_EMPTY.html +/// [`EV_CANCELQ_NOT_FULL`]: ../constant.EV_CANCELQ_NOT_FULL.html pub mod async { use super::*; - use core::sync::atomic::AtomicUsize; + use core::sync::atomic::{AtomicU64, AtomicUsize}; - /// An identified usercall. #[repr(C)] - #[derive(Copy, Clone)] #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] - pub struct Usercall { - /// `0` indicates this slot is empty. - pub id: u64, - /// The elements correspond to the RDI, RSI, RDX, R8, and R9 registers - /// in the synchronous calling convention. - pub args: (u64, u64, u64, u64, u64) + pub struct WithId { + pub id: AtomicU64, + pub data: T, + } + + /// A usercall. + /// The elements correspond to the RDI, RSI, RDX, R8, and R9 registers + /// in the synchronous calling convention. + #[repr(C)] + #[derive(Copy, Clone, Default)] + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + pub struct Usercall(pub u64, pub u64, pub u64, pub u64, pub u64); + + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + impl From for (u64, u64, u64, u64, u64) { + fn from(u: Usercall) -> Self { + let Usercall(p1, p2, p3, p4, p5) = u; + (p1, p2, p3, p4, p5) + } + } + + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + impl From<(u64, u64, u64, u64, u64)> for Usercall { + fn from(p: (u64, u64, u64, u64, u64)) -> Self { + Usercall(p.0, p.1, p.2, p.3, p.4) + } } - /// The return value of an identified usercall. + /// The return value of a usercall. + /// The elements correspond to the RSI and RDX registers in the + /// synchronous calling convention. #[repr(C)] - #[derive(Copy, Clone)] + #[derive(Copy, Clone, Default)] #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] - pub struct Return { - /// `0` indicates this slot is empty. - pub id: u64, - /// The elements correspond to the RSI and RDX registers in the - /// synchronous calling convention. - pub value: (u64, u64) + pub struct Return(pub u64, pub u64); + + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + impl From for (u64, u64) { + fn from(r: Return) -> Self { + let Return(r1, r2) = r; + (r1, r2) + } } + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + impl From<(u64, u64)> for Return { + fn from(r: (u64, u64)) -> Self { + Return(r.0, r.1) + } + } + + /// Cancel a usercall previously sent to userspace. + #[repr(C)] + #[derive(Copy, Clone, Default)] + #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] + pub struct Cancel; + /// A circular buffer used as a FIFO queue with atomic reads and writes. /// /// The read offset is the element that was most recently read by the @@ -679,7 +750,7 @@ pub mod async { /// 1. Load the current offsets. /// 2. If the queue is full, wait, then go to step 1. /// 3. Add 1 to the write offset and do an atomic compare-and-swap (CAS) - /// with the current offsets. If the CAS was not succesful, go to step + /// with the current offsets. If the CAS was not successful, go to step /// 1\. /// 4. Write the data, then the `id`. /// 5. If the queue was empty in step 1, signal the reader to wake up. @@ -695,14 +766,15 @@ pub mod async { /// 5. If `id` is `0`, go to step 4 (spin). Spinning is OK because data is /// expected to be written imminently. /// 6. Read the data, then store `0` in the `id`. - /// 7. Store the new read offset. - /// 8. If the queue was full in step 1, signal the writer to wake up. + /// 7. Store the new read offset, retrieving the old offsets. + /// 8. If the queue was full before step 7, signal the writer to wake up. #[repr(C)] #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))] pub struct FifoDescriptor { /// Pointer to the queue memory. Must have a size of - /// `len * size_of::()` bytes and have alignment `align_of::`. - pub data: *mut T, + /// `len * size_of::>()` bytes and have alignment + /// `align_of::>`. + pub data: *mut WithId, /// The number of elements pointed to by `data`. Must be a power of two /// less than or equal to 2³¹. pub len: usize, @@ -735,11 +807,13 @@ pub mod async { impl Usercalls { /// Request FIFO queues for asynchronous usercalls. `usercall_queue` /// and `return_queue` must point to valid user memory with the correct - /// size and alignment for their types. On return, userspace will have - /// filled these structures with information about the queues. A single - /// set of queues will be allocated per enclave. Once this usercall has - /// returned succesfully, calling this usercall again is equivalent to - /// calling `exit(true)`. + /// size and alignment for their types. `cancel_queue` is optional, but + /// if specified (not null) it must point to valid user memory with + /// correct size and alignment. + /// On return, userspace will have filled these structures with + /// information about the queues. A single set of queues will be + /// allocated per enclave. Once this usercall has returned successfully, + /// calling this usercall again is equivalent to calling `exit(true)`. /// /// May fail if the platform does not support asynchronous usercalls. /// @@ -747,7 +821,11 @@ pub mod async { /// [`FifoDescriptor`] is outside the enclave. /// /// [`FifoDescriptor`]: async/struct.FifoDescriptor.html - pub fn async_queues(usercall_queue: *mut FifoDescriptor, return_queue: *mut FifoDescriptor) -> Result { unimplemented!() } + pub fn async_queues( + usercall_queue: *mut FifoDescriptor, + return_queue: *mut FifoDescriptor, + cancel_queue: *mut FifoDescriptor + ) -> Result { unimplemented!() } } } diff --git a/vendor/fs-err/.cargo-checksum.json b/vendor/fs-err/.cargo-checksum.json index 96f6899da..0cafc2bae 100644 --- a/vendor/fs-err/.cargo-checksum.json +++ b/vendor/fs-err/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"8b53bca7b646d3afd45cde66ce850b263218904ecdd66f47e5684ef04ec873b8","Cargo.toml":"03bb23a8e71f90f8e7e5c6120f97f22b3319b2be1adb751a5f6b312fa62c9a18","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"e5c3355cb080a50bade0664df1f853e3f041121a9aa5bda2074ce6e01e210437","README.tpl":"de2f4fa16d473b928004aed4e11bd70522690961c6e34094a07fc68e9a092426","src/dir.rs":"1fbc8a3ada7e5e8a8c15dc0bf0e3c94cbeeea26e4a5f2b411c62d93adc023ebb","src/errors.rs":"263370df16fb2fc2c77c7b434da301792c61841960855dc11ba99523a324a2f3","src/file.rs":"dccdbd8f2b2e4e7c167df555f3a1facbf8003292c081d842711a852f2cf4b471","src/lib.rs":"f3e2041ef73f15b88594d93370b53e8f08717f7ce142184ec0c40e42d7b73c91","src/open_options.rs":"3ea24a370732eff1da0fae2205f251d3171d4e5e03f4c38508a2114942a16466","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"3e2940651ce8d7b624d10bb9f3e64334812e1bb0476d12dfec130dcb1b16fe7e","src/os/windows.rs":"6dc3099f9e48a386cba9f58599796583f0cb3c8b7123168f8d1c8e27fd8763e3","src/path.rs":"949dff5847ef0983ede9e9eec1fa0f3e6d8ffd1a35004249ad04a2d2700eb85b","tests/version-numbers.rs":"370467b40ce930d655389ba82015ae2842b3361bf24280c3dc7214d3ac163a2d"},"package":"bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431"} \ No newline at end of file +{"files":{"CHANGELOG.md":"fb2609e5837d71e923def1765b6addc4d11b0b5040e7eb9bdbf50d59a4a5cd42","Cargo.toml":"b468e8d560ea6e30277c2ee438ac650bbb2397f5b62da911126c180921aa5d29","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"adbf428f33a04028cc8db98d7b75bdcf28d0edb5e792867578bcb93f1784abec","src/dir.rs":"c5255382d7357f2fbcb0b45325a343277d347f0dd0b5f0e5ff74cb808020795d","src/errors.rs":"f04771790f55627fdc39de43a1d16f7d0125bbf48d4a1c8a70921f2670dd3eaa","src/file.rs":"4516834bc52f1219f10e369bf570fd432493ceaf5d52d239d93a5e69ceaed0aa","src/lib.rs":"1a10c04bde2bc3ae30cc328afb0aa00ac98ab80c6bfff5ae94ee7e5bdbe86ec8","src/open_options.rs":"304c5be36b5a6c5ecc2c731e2956627494945d093952c879d8f3c5b15216b1d0","src/os.rs":"54fe6cb71a24592de1cb4e1fcebdeaba5e58b26925dbf2dc868e8dd0b0a7bef7","src/os/unix.rs":"21ab862305b9e1034c41bb4be31b1f3d43e3d208ca3e622211b6b54d1bbd9acc","src/os/windows.rs":"4cf0530becb6fed439f469e1f22f57de9ae2ac15e39f2a973f4734aee6267ed0","src/path.rs":"a026ae234184ed1bbadd9051099e201c3ac6309b1fd939d1b2d2b2a7cb82230d"},"package":"64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50"} \ No newline at end of file diff --git a/vendor/fs-err/CHANGELOG.md b/vendor/fs-err/CHANGELOG.md index bc973e22c..ee7e4be32 100644 --- a/vendor/fs-err/CHANGELOG.md +++ b/vendor/fs-err/CHANGELOG.md @@ -1,5 +1,22 @@ # fs-err Changelog +## 2.8.1 + +* Fixed docs.rs build + +## 2.8.0 + +* Implement I/O safety traits (`AsFd`/`AsHandle`, `Into`/`Into`) for file. This feature requires Rust 1.63 or later and is gated behind the `io_safety` feature flag. ([#39](https://github.com/andrewhickman/fs-err/pull/39)) + +## 2.7.0 + +* Implement `From for std::fs::File` ([#38](https://github.com/andrewhickman/fs-err/pull/38)) + +## 2.6.0 + +* Added [`File::into_parts`](https://docs.rs/fs-err/2.6.0/fs_err/struct.File.html#method.into_parts) and [`File::file_mut`](https://docs.rs/fs-err/2.6.0/fs_err/struct.File.html#method.file_mut) to provide more access to the underlying `std::fs::File`. +* Fixed some typos in documention ([#33](https://github.com/andrewhickman/fs-err/pull/33)) + ## 2.5.0 * Added `symlink` for unix platforms * Added `symlink_file` and `symlink_dir` for windows @@ -11,7 +28,7 @@ - Added trait wrappers for `std::os::{unix, windows}::fs::OpenOptionsExt` and implemented them for `fs_err::OpenOptions` * Improved compile times by converting arguments early and forwarding only a small number of types internally. There will be a slight performance hit only in the error case. * Reduced trait bounds on generics from `AsRef + Into` to either `AsRef` or `Into`, making the functions more general. - + ## 2.4.0 * Added `canonicalize`, `hard link`, `read_link`, `rename`, `symlink_metadata` and `soft_link`. ([#25](https://github.com/andrewhickman/fs-err/pull/25)) * Added aliases to `std::path::Path` via extension trait ([#26](https://github.com/andrewhickman/fs-err/pull/26)) diff --git a/vendor/fs-err/Cargo.toml b/vendor/fs-err/Cargo.toml index 62c4c651c..07bada50a 100644 --- a/vendor/fs-err/Cargo.toml +++ b/vendor/fs-err/Cargo.toml @@ -3,28 +3,53 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "fs-err" -version = "2.5.0" +version = "2.8.1" authors = ["Andrew Hickman "] +exclude = [ + ".github", + ".gitignore", + "README.tpl", +] description = "A drop-in replacement for std::fs with more helpful error messages." documentation = "https://docs.rs/fs-err" readme = "README.md" -categories = ["command-line-interface", "filesystem"] +categories = [ + "command-line-interface", + "filesystem", +] license = "MIT/Apache-2.0" repository = "https://github.com/andrewhickman/fs-err" +[package.metadata.release] +tag-name = "{{version}}" +sign-tag = true + +[[package.metadata.release.pre-release-replacements]] +file = "src/lib.rs" +search = 'html_root_url = "https://docs\.rs/fs-err/.*?"' +replace = "html_root_url = \"https://docs.rs/fs-err/{{version}}\"" +exactly = 1 + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + [dependencies] + [dev-dependencies.serde_json] -version = "1.0.48" +version = "1.0.64" -[dev-dependencies.version-sync] -version = "0.8.1" +[features] +io_safety = [] diff --git a/vendor/fs-err/README.md b/vendor/fs-err/README.md index 70bf1fa44..0dc5fc1c3 100644 --- a/vendor/fs-err/README.md +++ b/vendor/fs-err/README.md @@ -11,7 +11,7 @@ fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more helpful messages on errors. Extra information includes which operations was -attmpted and any involved paths. +attempted and any involved paths. ## Error Messages diff --git a/vendor/fs-err/README.tpl b/vendor/fs-err/README.tpl deleted file mode 100644 index 35ac8052d..000000000 --- a/vendor/fs-err/README.tpl +++ /dev/null @@ -1,28 +0,0 @@ - - -# {{crate}} - -[![Crates.io](https://img.shields.io/crates/v/fs-err.svg)](https://crates.io/crates/fs-err) -[![GitHub Actions](https://github.com/andrewhickman/fs-err/workflows/CI/badge.svg)](https://github.com/andrewhickman/fs-err/actions?query=workflow%3ACI) - -{{readme}} - -## License - -Licensed under either of - -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) -* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. \ No newline at end of file diff --git a/vendor/fs-err/src/dir.rs b/vendor/fs-err/src/dir.rs index adba643b9..6efa58da6 100644 --- a/vendor/fs-err/src/dir.rs +++ b/vendor/fs-err/src/dir.rs @@ -11,7 +11,7 @@ pub fn read_dir>(path: P) -> io::Result { match fs::read_dir(&path) { Ok(inner) => Ok(ReadDir { inner, path }), - Err(source) => Err(Error::new(source, ErrorKind::ReadDir, path)), + Err(source) => Err(Error::build(source, ErrorKind::ReadDir, path)), } } @@ -32,7 +32,12 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option { - Some(self.inner.next()?.map(|inner| DirEntry { inner })) + Some( + self.inner + .next()? + .map_err(|source| Error::build(source, ErrorKind::ReadDir, &self.path)) + .map(|inner| DirEntry { inner }), + ) } } @@ -55,14 +60,14 @@ impl DirEntry { pub fn metadata(&self) -> io::Result { self.inner .metadata() - .map_err(|source| Error::new(source, ErrorKind::Metadata, self.path())) + .map_err(|source| Error::build(source, ErrorKind::Metadata, self.path())) } /// Wrapper for [`DirEntry::file_type`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.file_type). pub fn file_type(&self) -> io::Result { self.inner .file_type() - .map_err(|source| Error::new(source, ErrorKind::Metadata, self.path())) + .map_err(|source| Error::build(source, ErrorKind::Metadata, self.path())) } /// Wrapper for [`DirEntry::file_name`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.file_name). diff --git a/vendor/fs-err/src/errors.rs b/vendor/fs-err/src/errors.rs index 466d28f11..43bc4ba42 100644 --- a/vendor/fs-err/src/errors.rs +++ b/vendor/fs-err/src/errors.rs @@ -47,12 +47,15 @@ pub(crate) struct Error { } impl Error { - pub fn new(source: io::Error, kind: ErrorKind, path: impl Into) -> io::Error { - Self::_new(source, kind, path.into()) - } - - fn _new(source: io::Error, kind: ErrorKind, path: PathBuf) -> io::Error { - io::Error::new(source.kind(), Self { kind, source, path }) + pub fn build(source: io::Error, kind: ErrorKind, path: impl Into) -> io::Error { + io::Error::new( + source.kind(), + Self { + kind, + source, + path: path.into(), + }, + ) } } @@ -131,28 +134,19 @@ pub(crate) struct SourceDestError { } impl SourceDestError { - pub fn new( + pub fn build( source: io::Error, kind: SourceDestErrorKind, from_path: impl Into, to_path: impl Into, - ) -> io::Error { - Self::_new(source, kind, from_path.into(), to_path.into()) - } - - fn _new( - source: io::Error, - kind: SourceDestErrorKind, - from_path: PathBuf, - to_path: PathBuf, ) -> io::Error { io::Error::new( source.kind(), Self { kind, source, - from_path, - to_path, + from_path: from_path.into(), + to_path: to_path.into(), }, ) } diff --git a/vendor/fs-err/src/file.rs b/vendor/fs-err/src/file.rs index a9c8988e5..fcf54fe3c 100644 --- a/vendor/fs-err/src/file.rs +++ b/vendor/fs-err/src/file.rs @@ -17,12 +17,12 @@ pub struct File { // Opens a std File and returns it or an error generator which only needs the path to produce the error. // Exists for the `crate::read*` functions so they don't unconditionally build a PathBuf. pub(crate) fn open(path: &Path) -> Result io::Error> { - fs::File::open(&path).map_err(|err| |path| Error::new(err, ErrorKind::OpenFile, path)) + fs::File::open(&path).map_err(|err| |path| Error::build(err, ErrorKind::OpenFile, path)) } // like `open()` but for `crate::write` pub(crate) fn create(path: &Path) -> Result io::Error> { - fs::File::create(&path).map_err(|err| |path| Error::new(err, ErrorKind::CreateFile, path)) + fs::File::create(&path).map_err(|err| |path| Error::build(err, ErrorKind::CreateFile, path)) } /// Wrappers for methods from [`std::fs::File`][std::fs::File]. @@ -65,7 +65,7 @@ impl File { let path = path.into(); match options.open(&path) { Ok(file) => Ok(File::from_parts(file, path)), - Err(source) => Err(Error::new(source, ErrorKind::OpenFile, path)), + Err(source) => Err(Error::build(source, ErrorKind::OpenFile, path)), } } @@ -114,7 +114,13 @@ impl File { .set_permissions(perm) .map_err(|source| self.error(source, ErrorKind::SetPermissions)) } +} +/// Methods added by fs-err that are not available on +/// [`std::fs::File`][std::fs::File]. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +impl File { /// Creates a [`File`](struct.File.html) from a raw file and its path. pub fn from_parts

(file: fs::File, path: P) -> Self where @@ -125,13 +131,12 @@ impl File { path: path.into(), } } -} -/// Methods added by fs-err that are not available on -/// [`std::fs::File`][std::fs::File]. -/// -/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html -impl File { + /// Extract the raw file and its path from this [`File`](struct.File.html) + pub fn into_parts(self) -> (fs::File, PathBuf) { + (self.file, self.path) + } + /// Returns a reference to the underlying [`std::fs::File`][std::fs::File]. /// /// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html @@ -139,6 +144,13 @@ impl File { &self.file } + /// Returns a mutable reference to the underlying [`std::fs::File`][std::fs::File]. + /// + /// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html + pub fn file_mut(&mut self) -> &mut fs::File { + &mut self.file + } + /// Returns a reference to the path that this file was created with. pub fn path(&self) -> &Path { &self.path @@ -146,7 +158,7 @@ impl File { /// Wrap the error in information specific to this `File` object. fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error { - Error::new(source, kind, &self.path) + Error::build(source, kind, &self.path) } } @@ -178,6 +190,12 @@ impl<'a> Read for &'a File { } } +impl From for fs::File { + fn from(file: File) -> Self { + file.into_parts().0 + } +} + impl Seek for File { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { self.file @@ -266,6 +284,25 @@ mod unix { .map_err(|err| self.error(err, ErrorKind::WriteAt)) } } + + #[cfg(feature = "io_safety")] + mod io_safety { + use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; + + #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))] + impl AsFd for crate::File { + fn as_fd(&self) -> BorrowedFd<'_> { + self.file().as_fd() + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))] + impl From for OwnedFd { + fn from(file: crate::File) -> Self { + file.into_parts().0.into() + } + } + } } #[cfg(windows)] @@ -307,4 +344,23 @@ mod windows { self.file.into_raw_handle() } } + + #[cfg(feature = "io_safety")] + mod io_safety { + use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle}; + + #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))] + impl AsHandle for crate::File { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.file().as_handle() + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))] + impl From for OwnedHandle { + fn from(file: crate::File) -> Self { + file.into_parts().0.into() + } + } + } } diff --git a/vendor/fs-err/src/lib.rs b/vendor/fs-err/src/lib.rs index 3cc8a3b4d..777db9535 100644 --- a/vendor/fs-err/src/lib.rs +++ b/vendor/fs-err/src/lib.rs @@ -1,7 +1,7 @@ /*! fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more helpful messages on errors. Extra information includes which operations was -attmpted and any involved paths. +attempted and any involved paths. # Error Messages @@ -66,8 +66,9 @@ println!("Program config: {:?}", decoded); [serde_json]: https://crates.io/crates/serde_json */ -#![doc(html_root_url = "https://docs.rs/fs-err/2.5.0")] +#![doc(html_root_url = "https://docs.rs/fs-err/2.8.1")] #![deny(missing_debug_implementations, missing_docs)] +#![cfg_attr(docsrs, feature(doc_cfg))] mod dir; mod errors; @@ -90,20 +91,20 @@ pub use path::PathExt; /// Wrapper for [`fs::read`](https://doc.rust-lang.org/stable/std/fs/fn.read.html). pub fn read>(path: P) -> io::Result> { let path = path.as_ref(); - let mut file = file::open(path.as_ref()).map_err(|err_gen| err_gen(path.to_path_buf()))?; + let mut file = file::open(path).map_err(|err_gen| err_gen(path.to_path_buf()))?; let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); file.read_to_end(&mut bytes) - .map_err(|err| Error::new(err, ErrorKind::Read, path))?; + .map_err(|err| Error::build(err, ErrorKind::Read, path))?; Ok(bytes) } /// Wrapper for [`fs::read_to_string`](https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html). pub fn read_to_string>(path: P) -> io::Result { let path = path.as_ref(); - let mut file = file::open(path.as_ref()).map_err(|err_gen| err_gen(path.to_path_buf()))?; + let mut file = file::open(path).map_err(|err_gen| err_gen(path.to_path_buf()))?; let mut string = String::with_capacity(initial_buffer_size(&file)); file.read_to_string(&mut string) - .map_err(|err| Error::new(err, ErrorKind::Read, path))?; + .map_err(|err| Error::build(err, ErrorKind::Read, path))?; Ok(string) } @@ -113,7 +114,7 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result file::create(path) .map_err(|err_gen| err_gen(path.to_path_buf()))? .write_all(contents.as_ref()) - .map_err(|err| Error::new(err, ErrorKind::Write, path)) + .map_err(|err| Error::build(err, ErrorKind::Write, path)) } /// Wrapper for [`fs::copy`](https://doc.rust-lang.org/stable/std/fs/fn.copy.html). @@ -125,7 +126,7 @@ where let from = from.as_ref(); let to = to.as_ref(); fs::copy(from, to) - .map_err(|source| SourceDestError::new(source, SourceDestErrorKind::Copy, from, to)) + .map_err(|source| SourceDestError::build(source, SourceDestErrorKind::Copy, from, to)) } /// Wrapper for [`fs::create_dir`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir.html). @@ -134,7 +135,7 @@ where P: AsRef, { let path = path.as_ref(); - fs::create_dir(path).map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) + fs::create_dir(path).map_err(|source| Error::build(source, ErrorKind::CreateDir, path)) } /// Wrapper for [`fs::create_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir_all.html). @@ -143,7 +144,7 @@ where P: AsRef, { let path = path.as_ref(); - fs::create_dir_all(path).map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) + fs::create_dir_all(path).map_err(|source| Error::build(source, ErrorKind::CreateDir, path)) } /// Wrapper for [`fs::remove_dir`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir.html). @@ -152,7 +153,7 @@ where P: AsRef, { let path = path.as_ref(); - fs::remove_dir(path).map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) + fs::remove_dir(path).map_err(|source| Error::build(source, ErrorKind::RemoveDir, path)) } /// Wrapper for [`fs::remove_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html). @@ -161,7 +162,7 @@ where P: AsRef, { let path = path.as_ref(); - fs::remove_dir_all(path).map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) + fs::remove_dir_all(path).map_err(|source| Error::build(source, ErrorKind::RemoveDir, path)) } /// Wrapper for [`fs::remove_file`](https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html). @@ -170,19 +171,19 @@ where P: AsRef, { let path = path.as_ref(); - fs::remove_file(path).map_err(|source| Error::new(source, ErrorKind::RemoveFile, path)) + fs::remove_file(path).map_err(|source| Error::build(source, ErrorKind::RemoveFile, path)) } /// Wrapper for [`fs::metadata`](https://doc.rust-lang.org/stable/std/fs/fn.metadata.html). pub fn metadata>(path: P) -> io::Result { let path = path.as_ref(); - fs::metadata(path).map_err(|source| Error::new(source, ErrorKind::Metadata, path)) + fs::metadata(path).map_err(|source| Error::build(source, ErrorKind::Metadata, path)) } /// Wrapper for [`fs::canonicalize`](https://doc.rust-lang.org/stable/std/fs/fn.canonicalize.html). pub fn canonicalize>(path: P) -> io::Result { let path = path.as_ref(); - fs::canonicalize(path).map_err(|source| Error::new(source, ErrorKind::Canonicalize, path)) + fs::canonicalize(path).map_err(|source| Error::build(source, ErrorKind::Canonicalize, path)) } /// Wrapper for [`fs::hard_link`](https://doc.rust-lang.org/stable/std/fs/fn.hard_link.html). @@ -190,13 +191,13 @@ pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( let src = src.as_ref(); let dst = dst.as_ref(); fs::hard_link(src, dst) - .map_err(|source| SourceDestError::new(source, SourceDestErrorKind::HardLink, src, dst)) + .map_err(|source| SourceDestError::build(source, SourceDestErrorKind::HardLink, src, dst)) } /// Wrapper for [`fs::read_link`](https://doc.rust-lang.org/stable/std/fs/fn.read_link.html). pub fn read_link>(path: P) -> io::Result { let path = path.as_ref(); - fs::read_link(path).map_err(|source| Error::new(source, ErrorKind::ReadLink, path)) + fs::read_link(path).map_err(|source| Error::build(source, ErrorKind::ReadLink, path)) } /// Wrapper for [`fs::rename`](https://doc.rust-lang.org/stable/std/fs/fn.rename.html). @@ -204,7 +205,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> let from = from.as_ref(); let to = to.as_ref(); fs::rename(from, to) - .map_err(|source| SourceDestError::new(source, SourceDestErrorKind::Rename, from, to)) + .map_err(|source| SourceDestError::build(source, SourceDestErrorKind::Rename, from, to)) } /// Wrapper for [`fs::soft_link`](https://doc.rust-lang.org/stable/std/fs/fn.soft_link.html). @@ -215,21 +216,21 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( let dst = dst.as_ref(); #[allow(deprecated)] fs::soft_link(src, dst) - .map_err(|source| SourceDestError::new(source, SourceDestErrorKind::SoftLink, src, dst)) + .map_err(|source| SourceDestError::build(source, SourceDestErrorKind::SoftLink, src, dst)) } /// Wrapper for [`fs::symlink_metadata`](https://doc.rust-lang.org/stable/std/fs/fn.symlink_metadata.html). pub fn symlink_metadata>(path: P) -> io::Result { let path = path.as_ref(); fs::symlink_metadata(path) - .map_err(|source| Error::new(source, ErrorKind::SymlinkMetadata, path)) + .map_err(|source| Error::build(source, ErrorKind::SymlinkMetadata, path)) } /// Wrapper for [`fs::set_permissions`](https://doc.rust-lang.org/stable/std/fs/fn.set_permissions.html). pub fn set_permissions>(path: P, perm: fs::Permissions) -> io::Result<()> { let path = path.as_ref(); fs::set_permissions(path, perm) - .map_err(|source| Error::new(source, ErrorKind::SetPermissions, path)) + .map_err(|source| Error::build(source, ErrorKind::SetPermissions, path)) } fn initial_buffer_size(file: &std::fs::File) -> usize { diff --git a/vendor/fs-err/src/open_options.rs b/vendor/fs-err/src/open_options.rs index 2a11a3974..557fa7abe 100644 --- a/vendor/fs-err/src/open_options.rs +++ b/vendor/fs-err/src/open_options.rs @@ -5,6 +5,7 @@ pub struct OpenOptions(fs::OpenOptions); impl OpenOptions { /// Wrapper for [`std::fs::OpenOptions::new`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.new) + #[allow(clippy::new_without_default)] pub fn new() -> Self { OpenOptions(fs::OpenOptions::new()) } diff --git a/vendor/fs-err/src/os/unix.rs b/vendor/fs-err/src/os/unix.rs index 1c0bbc24d..ad7c488c4 100644 --- a/vendor/fs-err/src/os/unix.rs +++ b/vendor/fs-err/src/os/unix.rs @@ -11,7 +11,7 @@ pub mod fs { let src = src.as_ref(); let dst = dst.as_ref(); std::os::unix::fs::symlink(src, dst) - .map_err(|err| SourceDestError::new(err, SourceDestErrorKind::Symlink, src, dst)) + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::Symlink, src, dst)) } /// Wrapper for [`std::os::unix::fs::FileExt`](https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html). @@ -30,9 +30,9 @@ pub mod fs { /// The std traits might be extended in the future (See issue [#49961](https://github.com/rust-lang/rust/issues/49961#issuecomment-382751777)). /// This trait is sealed and can not be implemented by other crates. pub trait OpenOptionsExt: crate::Sealed { - /// Wapper for [`OpenOptionsExt::mode`](https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode) + /// Wrapper for [`OpenOptionsExt::mode`](https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode) fn mode(&mut self, mode: u32) -> &mut Self; - /// Wapper for [`OpenOptionsExt::custom_flags`](https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.custom_flags) + /// Wrapper for [`OpenOptionsExt::custom_flags`](https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.custom_flags) fn custom_flags(&mut self, flags: i32) -> &mut Self; } } diff --git a/vendor/fs-err/src/os/windows.rs b/vendor/fs-err/src/os/windows.rs index 3aaa4a2b8..f55985623 100644 --- a/vendor/fs-err/src/os/windows.rs +++ b/vendor/fs-err/src/os/windows.rs @@ -8,7 +8,7 @@ pub mod fs { let src = src.as_ref(); let dst = dst.as_ref(); std::os::windows::fs::symlink_dir(src, dst) - .map_err(|err| SourceDestError::new(err, SourceDestErrorKind::SymlinkDir, src, dst)) + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkDir, src, dst)) } /// Wrapper for [std::os::windows::fs::symlink_file](https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html) @@ -16,7 +16,7 @@ pub mod fs { let src = src.as_ref(); let dst = dst.as_ref(); std::os::windows::fs::symlink_file(src, dst) - .map_err(|err| SourceDestError::new(err, SourceDestErrorKind::SymlinkFile, src, dst)) + .map_err(|err| SourceDestError::build(err, SourceDestErrorKind::SymlinkFile, src, dst)) } /// Wrapper for [`std::os::windows::fs::FileExt`](https://doc.rust-lang.org/std/os/windows/fs/trait.FileExt.html). diff --git a/vendor/fs-err/src/path.rs b/vendor/fs-err/src/path.rs index ed6b9eaf1..28549a31c 100644 --- a/vendor/fs-err/src/path.rs +++ b/vendor/fs-err/src/path.rs @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf}; /// /// This trait is sealed and can not be implemented by other crates. // -// Because noone else can implement it, we can add methods backwards-compatibly. +// Because no one else can implement it, we can add methods backwards-compatibly. pub trait PathExt: crate::Sealed { /// Wrapper for [`crate::metadata`]. fn fs_err_metadata(&self) -> io::Result; diff --git a/vendor/fs-err/tests/version-numbers.rs b/vendor/fs-err/tests/version-numbers.rs deleted file mode 100644 index 41a5ea480..000000000 --- a/vendor/fs-err/tests/version-numbers.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[test] -fn test_readme_deps() { - version_sync::assert_markdown_deps_updated!("README.md"); -} - -#[test] -fn test_html_root_url() { - version_sync::assert_html_root_url_updated!("src/lib.rs"); -} diff --git a/vendor/generic-array-0.12.4/.cargo-checksum.json b/vendor/generic-array-0.12.4/.cargo-checksum.json deleted file mode 100644 index cfe4f79f6..000000000 --- a/vendor/generic-array-0.12.4/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"ae7c1d7fcd6dceb6472568994016862441606c444d0670d4e9dffab20c5eeea3","Cargo.toml":"122428b66e56c3287df569deba1e7de4b7c316cee39e1f9e1c3e7d80c793e427","LICENSE":"ad4fcfaf8d5b12b97409c137a03d4a4e4b21024c65c54f976cc3b609c1bd5b0f","README.md":"9a1a45416eac57050036b13df6ec84d21d555e820726af3c782896bd9d37d94b","rustfmt.toml":"2a298b4ce1fe6e16b8f281a0035567b8eb15042ed3062729fd28224f29c2f75a","src/arr.rs":"d866a89232279e5602cfe80b7f4e0db2b8b1153532ca72f61d65ba4d792fa603","src/functional.rs":"a0b12be07c1cc85549a80ddf1cfa1c7d5cbc09c3710bb635a5f95c35537005dc","src/hex.rs":"45e780bf385f99eec5058cfae87f97042679b1e8cbc130c009d4c074052016aa","src/impl_serde.rs":"5556e952fd351ab0af27bb562b1b6382e96a20afe51a04300264842e1fb33747","src/impls.rs":"d3046213d058b43b7b7360a2fa9ab6794e44970f1bc1847649c42c8f1c4f2d75","src/iter.rs":"b8b130ddd52461c435b873b9435f771d6535ae835055a73d79c0f3105f6b367e","src/lib.rs":"99a3fe3bc49cbfb9f00554d4860b24abe02e8075404fdb88343f2ee389f09110","src/sequence.rs":"bdf4d8920205bb85dee95897940373991b232e7b0614ae52c03c5f4bc4e8dccc","tests/arr.rs":"97258231dfeefc52ec785c2019611cc1a339c3a13f744a26727a591f7e46a7a8","tests/generics.rs":"8da33daacab14d0fd685e0ca6292a2d19be23fa6c6e128921b554a7e1d6181a1","tests/hex.rs":"143d783defedd6609995862f8aac46b8c843272a8f877f83d2f7242de8814c02","tests/import_name.rs":"1235729ecbde47fc9a38b3bf35c750a53ed55e3cf967c9d2b24fd759dc9e9e0c","tests/iter.rs":"3e5e6a1354709e8bfa76e52969c61f3d21cb960027bb91745049c0dcdfa52bfd","tests/mod.rs":"75694855127075e14ddef490fffee3dea5a052bcdda2912878bd9995f3f2956d"},"package":"ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"} \ No newline at end of file diff --git a/vendor/generic-array-0.12.4/CHANGELOG.md b/vendor/generic-array-0.12.4/CHANGELOG.md deleted file mode 100644 index d5e50e7b1..000000000 --- a/vendor/generic-array-0.12.4/CHANGELOG.md +++ /dev/null @@ -1,51 +0,0 @@ -* **`0.12.4`** - * Fix unsoundness in the `arr!` macro. - -* **`0.12.0`** - * Allow trailing commas in `arr!` macro. - * **BREAKING**: Serialize `GenericArray` using `serde` tuples, instead of variable-length sequences. This may not be compatible with old serialized data. - -* **`0.11.0`** - * **BREAKING** Redesign `GenericSequence` with an emphasis on use in generic type parameters. - * Add `MappedGenericSequence` and `FunctionalSequence` - * Implements optimized `map`, `zip` and `fold` for `GenericArray`, `&GenericArray` and `&mut GenericArray` - * **BREAKING** Remove `map_ref`, `zip_ref` and `map_slice` - * `map_slice` is now equivalent to `GenericArray::from_iter(slice.iter().map(...))` -* **`0.10.0`** - * Add `GenericSequence`, `Lengthen`, `Shorten`, `Split` and `Concat` traits. - * Redefine `transmute` to avert errors. -* **`0.9.0`** - * Rewrite construction methods to be well-defined in panic situations, correctly dropping elements. - * `NoDrop` crate replaced by `ManuallyDrop` as it became stable in Rust core. - * Add optimized `map`/`map_ref` and `zip`/`zip_ref` methods to `GenericArray` -* **`0.8.0`** - * Implement `AsRef`, `AsMut`, `Borrow`, `BorrowMut`, `Hash` for `GenericArray` - * Update `serde` to `1.0` - * Update `typenum` - * Make macro `arr!` non-cloning - * Implement `From<[T; N]>` up to `N=32` - * Fix #45 -* **`0.7.0`** - * Upgrade `serde` to `0.9` - * Make `serde` with `no_std` - * Implement `PartialOrd`/`Ord` for `GenericArray` -* **`0.6.0`** - * Fixed #30 - * Implement `Default` for `GenericArray` - * Implement `LowerHex` and `UpperHex` for `GenericArray` - * Use `precision` formatting field in hex representation - * Add `as_slice`, `as_mut_slice` - * Remove `GenericArray::new` in favor of `Default` trait - * Add `from_slice` and `from_mut_slice` - * `no_std` and `core` for crate. -* **`0.5.0`** - * Update `serde` - * remove `no_std` feature, fixed #19 -* **`0.4.0`** - * Re-export `typenum` -* **`0.3.0`** - * Implement `IntoIter` for `GenericArray` - * Add `map` method - * Add optional `serde` (de)serialization support feature. -* **`< 0.3.0`** - * Initial implementation in late 2015 diff --git a/vendor/generic-array-0.12.4/Cargo.toml b/vendor/generic-array-0.12.4/Cargo.toml deleted file mode 100644 index f4f4f4616..000000000 --- a/vendor/generic-array-0.12.4/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "generic-array" -version = "0.12.4" -authors = ["BartÅ‚omiej KamiÅ„ski ", "Aaron Trent "] -description = "Generic types implementing functionality of arrays" -documentation = "http://fizyk20.github.io/generic-array/generic_array/" -readme = "README.md" -keywords = ["generic", "array"] -categories = ["data-structures", "no-std"] -license = "MIT" -repository = "https://github.com/fizyk20/generic-array.git" - -[lib] -name = "generic_array" -[dependencies.serde] -version = "1.0" -optional = true -default-features = false - -[dependencies.typenum] -version = "1.10" -[dev-dependencies.bincode] -version = "1.0" - -[dev-dependencies.serde_json] -version = "1.0" -[badges.travis-ci] -repository = "fizyk20/generic-array" diff --git a/vendor/generic-array-0.12.4/LICENSE b/vendor/generic-array-0.12.4/LICENSE deleted file mode 100644 index 5968bcccc..000000000 --- a/vendor/generic-array-0.12.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 BartÅ‚omiej KamiÅ„ski - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/generic-array-0.12.4/README.md b/vendor/generic-array-0.12.4/README.md deleted file mode 100644 index 0864ed627..000000000 --- a/vendor/generic-array-0.12.4/README.md +++ /dev/null @@ -1,34 +0,0 @@ -[![Crates.io](https://img.shields.io/crates/v/generic-array.svg)](https://crates.io/crates/generic-array) -[![Build Status](https://travis-ci.org/fizyk20/generic-array.svg?branch=master)](https://travis-ci.org/fizyk20/generic-array) -# generic-array - -This crate implements generic array types for Rust. - -[Documentation](http://fizyk20.github.io/generic-array/generic_array/) - -## Usage - -The Rust arrays `[T; N]` are problematic in that they can't be used generically with respect to `N`, so for example this won't work: - -```rust -struct Foo { - data: [i32; N] -} -``` - -**generic-array** defines a new trait `ArrayLength` and a struct `GenericArray>`, which let the above be implemented as: - -```rust -struct Foo> { - data: GenericArray -} -``` - -To actually define a type implementing `ArrayLength`, you can use unsigned integer types defined in [typenum](https://github.com/paholg/typenum) crate - for example, `GenericArray` would work almost like `[T; 5]` :) - -In version 0.1.1 an `arr!` macro was introduced, allowing for creation of arrays as shown below: - -```rust -let array = arr![u32; 1, 2, 3]; -assert_eq!(array[2], 3); -``` diff --git a/vendor/generic-array-0.12.4/rustfmt.toml b/vendor/generic-array-0.12.4/rustfmt.toml deleted file mode 100644 index 3dc0db27b..000000000 --- a/vendor/generic-array-0.12.4/rustfmt.toml +++ /dev/null @@ -1,3 +0,0 @@ -reorder_imports = true -reorder_imported_names = true -use_try_shorthand = true diff --git a/vendor/generic-array-0.12.4/src/arr.rs b/vendor/generic-array-0.12.4/src/arr.rs deleted file mode 100644 index ebe687500..000000000 --- a/vendor/generic-array-0.12.4/src/arr.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! Implementation for `arr!` macro. - -use super::ArrayLength; -use core::ops::Add; -use typenum::U1; - -/// Helper trait for `arr!` macro -pub trait AddLength>: ArrayLength { - /// Resulting length - type Output: ArrayLength; -} - -impl AddLength for N1 -where - N1: ArrayLength + Add, - N2: ArrayLength, - >::Output: ArrayLength, -{ - type Output = >::Output; -} - -/// Helper type for `arr!` macro -pub type Inc = >::Output; - -#[doc(hidden)] -#[macro_export] -macro_rules! arr_impl { - (@replace_expr $e:expr)=>{ - 1 - }; - ($T:ty; $N:ty, [$($x:expr),*], []) => ({ - const __ARR_LENGTH:usize=0 $(+ $crate::arr_impl!(@replace_expr $x) )*; - fn __do_transmute<'a, T, N: $crate::ArrayLength>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { - unsafe { $crate::transmute(arr) } - } - - let _:[();<$N as $crate::typenum::Unsigned>::USIZE]=[();__ARR_LENGTH]; - - __do_transmute::<$T,$N>([$($x),*]) - }); - ($T:ty; $N:ty, [], [$x1:expr]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], []) - ); - ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+]) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], []) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+]) - ); -} - -/// Macro allowing for easy generation of Generic Arrays. -/// Example: `let test = arr![u32; 1, 2, 3];` -#[macro_export] -macro_rules! arr { - ($T:ty; $(,)*) => ({ - unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } - }); - ($T:ty; $($x:expr),* $(,)*) => ( - arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) - ); - ($($x:expr,)+) => (arr![$($x),*]); - () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") -} - - -mod doctests_only{ - /// - /// # With ellision - /// - /// Testing that lifetimes aren't transmuted when they're ellided. - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&A; a][0] - /// } - /// } - /// ``` - /// - /// ```rust - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { - /// arr![&A; a][0] - /// } - /// } - /// ``` - /// - /// # Without ellision - /// - /// Testing that lifetimes aren't transmuted when they're specified explicitly. - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&'a A; a][0] - /// } - /// } - /// ``` - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&'static A; a][0] - /// } - /// } - /// ``` - /// - /// ```rust - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { - /// arr![&'a A; a][0] - /// } - /// } - /// ``` - #[allow(dead_code)] - pub enum DocTests{} -} diff --git a/vendor/generic-array-0.12.4/src/functional.rs b/vendor/generic-array-0.12.4/src/functional.rs deleted file mode 100644 index 50f4a71b8..000000000 --- a/vendor/generic-array-0.12.4/src/functional.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! Functional programming with generic sequences -//! -//! Please see `tests/generics.rs` for examples of how to best use these in your generic functions. - -use super::ArrayLength; -use core::iter::FromIterator; -use sequence::*; - -/// Defines the relationship between one generic sequence and another, -/// for operations such as `map` and `zip`. -pub unsafe trait MappedGenericSequence: GenericSequence -where - Self::Length: ArrayLength, -{ - /// Mapped sequence type - type Mapped: GenericSequence; -} - -unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a S -where - &'a S: GenericSequence, - S: GenericSequence>::Length>, - >::Length: ArrayLength, -{ - type Mapped = >::Mapped; -} - -unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a mut S -where - &'a mut S: GenericSequence, - S: GenericSequence>::Length>, - >::Length: ArrayLength, -{ - type Mapped = >::Mapped; -} - -/// Accessor type for a mapped generic sequence -pub type MappedSequence = - <>::Mapped as GenericSequence>::Sequence; - -/// Defines functional programming methods for generic sequences -pub unsafe trait FunctionalSequence: GenericSequence { - /// Maps a `GenericSequence` to another `GenericSequence`. - /// - /// If the mapping function panics, any already initialized elements in the new sequence - /// will be dropped, AND any unused elements in the source sequence will also be dropped. - fn map(self, f: F) -> MappedSequence - where - Self: MappedGenericSequence, - Self::Length: ArrayLength, - F: FnMut(Self::Item) -> U, - { - FromIterator::from_iter(self.into_iter().map(f)) - } - - /// Combines two `GenericSequence` instances and iterates through both of them, - /// initializing a new `GenericSequence` with the result of the zipped mapping function. - /// - /// If the mapping function panics, any already initialized elements in the new sequence - /// will be dropped, AND any unused elements in the source sequences will also be dropped. - #[inline] - fn zip(self, rhs: Rhs, f: F) -> MappedSequence - where - Self: MappedGenericSequence, - Rhs: MappedGenericSequence>, - Self::Length: ArrayLength + ArrayLength, - Rhs: GenericSequence, - F: FnMut(Self::Item, Rhs::Item) -> U, - { - rhs.inverted_zip2(self, f) - } - - /// Folds (or reduces) a sequence of data into a single value. - /// - /// If the fold function panics, any unused elements will be dropped. - fn fold(self, init: U, f: F) -> U - where - F: FnMut(U, Self::Item) -> U, - { - self.into_iter().fold(init, f) - } -} - -unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a S -where - &'a S: GenericSequence, -{ -} - -unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a mut S -where - &'a mut S: GenericSequence, -{ -} diff --git a/vendor/generic-array-0.12.4/src/hex.rs b/vendor/generic-array-0.12.4/src/hex.rs deleted file mode 100644 index 3ef92b1b9..000000000 --- a/vendor/generic-array-0.12.4/src/hex.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Generic array are commonly used as a return value for hash digests, so -//! it's a good idea to allow to hexlify them easily. This module implements -//! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits. -//! -//! Example: -//! -//! ```rust -//! # #[macro_use] -//! # extern crate generic_array; -//! # extern crate typenum; -//! # fn main() { -//! let array = arr![u8; 10, 20, 30]; -//! assert_eq!(format!("{:x}", array), "0a141e"); -//! # } -//! ``` -//! - -use {ArrayLength, GenericArray}; -use core::cmp::min; -use core::fmt; -use core::ops::Add; -use core::str; -use typenum::*; - -static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; -static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; - -impl> fmt::LowerHex for GenericArray -where - T: Add, - >::Output: ArrayLength, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); - let max_hex = (max_digits >> 1) + (max_digits & 1); - - if T::to_usize() < 1024 { - // For small arrays use a stack allocated - // buffer of 2x number of bytes - let mut res = GenericArray::>::default(); - - for (i, c) in self.iter().take(max_hex).enumerate() { - res[i * 2] = LOWER_CHARS[(c >> 4) as usize]; - res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; - } - f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; - } else { - // For large array use chunks of up to 1024 bytes (2048 hex chars) - let mut buf = [0u8; 2048]; - let mut digits_left = max_digits; - - for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { - buf[i * 2] = LOWER_CHARS[(c >> 4) as usize]; - buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; - } - let n = min(chunk.len() * 2, digits_left); - f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; - digits_left -= n; - } - } - Ok(()) - } -} - -impl> fmt::UpperHex for GenericArray -where - T: Add, - >::Output: ArrayLength, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); - let max_hex = (max_digits >> 1) + (max_digits & 1); - - if T::to_usize() < 1024 { - // For small arrays use a stack allocated - // buffer of 2x number of bytes - let mut res = GenericArray::>::default(); - - for (i, c) in self.iter().take(max_hex).enumerate() { - res[i * 2] = UPPER_CHARS[(c >> 4) as usize]; - res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; - } - f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; - } else { - // For large array use chunks of up to 1024 bytes (2048 hex chars) - let mut buf = [0u8; 2048]; - let mut digits_left = max_digits; - - for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { - buf[i * 2] = UPPER_CHARS[(c >> 4) as usize]; - buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; - } - let n = min(chunk.len() * 2, digits_left); - f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; - digits_left -= n; - } - } - Ok(()) - } -} diff --git a/vendor/generic-array-0.12.4/src/impl_serde.rs b/vendor/generic-array-0.12.4/src/impl_serde.rs deleted file mode 100644 index da1df2fc0..000000000 --- a/vendor/generic-array-0.12.4/src/impl_serde.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Serde serialization/deserialization implementation - -use core::fmt; -use core::marker::PhantomData; -use serde::de::{self, SeqAccess, Visitor}; -use serde::{ser::SerializeTuple, Deserialize, Deserializer, Serialize, Serializer}; -use {ArrayLength, GenericArray}; - -impl Serialize for GenericArray -where - T: Serialize, - N: ArrayLength, -{ - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tup = serializer.serialize_tuple(N::to_usize())?; - for el in self { - tup.serialize_element(el)?; - } - - tup.end() - } -} - -struct GAVisitor { - _t: PhantomData, - _n: PhantomData, -} - -impl<'de, T, N> Visitor<'de> for GAVisitor -where - T: Deserialize<'de> + Default, - N: ArrayLength, -{ - type Value = GenericArray; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct GenericArray") - } - - fn visit_seq(self, mut seq: A) -> Result, A::Error> - where - A: SeqAccess<'de>, - { - let mut result = GenericArray::default(); - for i in 0..N::to_usize() { - result[i] = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(i, &self))?; - } - Ok(result) - } -} - -impl<'de, T, N> Deserialize<'de> for GenericArray -where - T: Deserialize<'de> + Default, - N: ArrayLength, -{ - fn deserialize(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let visitor = GAVisitor { - _t: PhantomData, - _n: PhantomData, - }; - deserializer.deserialize_tuple(N::to_usize(), visitor) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use bincode; - use typenum; - - #[test] - fn test_serialize() { - let array = GenericArray::::default(); - let serialized = bincode::serialize(&array); - assert!(serialized.is_ok()); - } - - #[test] - fn test_deserialize() { - let mut array = GenericArray::::default(); - array[0] = 1; - array[1] = 2; - let serialized = bincode::serialize(&array).unwrap(); - let deserialized = bincode::deserialize::>(&array); - assert!(deserialized.is_ok()); - let array = deserialized.unwrap(); - assert_eq!(array[0], 1); - assert_eq!(array[1], 2); - } - - #[test] - fn test_serialized_size() { - let array = GenericArray::::default(); - let size = bincode::serialized_size(&array).unwrap(); - assert_eq!(size, 1); - } - -} diff --git a/vendor/generic-array-0.12.4/src/impls.rs b/vendor/generic-array-0.12.4/src/impls.rs deleted file mode 100644 index ea5a3c4c9..000000000 --- a/vendor/generic-array-0.12.4/src/impls.rs +++ /dev/null @@ -1,182 +0,0 @@ -use super::{ArrayLength, GenericArray}; -use core::borrow::{Borrow, BorrowMut}; -use core::cmp::Ordering; -use core::fmt::{self, Debug}; -use core::hash::{Hash, Hasher}; -use functional::*; -use sequence::*; - -impl Default for GenericArray -where - N: ArrayLength, -{ - #[inline] - fn default() -> Self { - Self::generate(|_| T::default()) - } -} - -impl Clone for GenericArray -where - N: ArrayLength, -{ - fn clone(&self) -> GenericArray { - self.map(Clone::clone) - } -} - -impl Copy for GenericArray -where - N: ArrayLength, - N::ArrayType: Copy, -{ -} - -impl PartialEq for GenericArray -where - N: ArrayLength, -{ - fn eq(&self, other: &Self) -> bool { - **self == **other - } -} -impl Eq for GenericArray -where - N: ArrayLength, -{ -} - -impl PartialOrd for GenericArray -where - N: ArrayLength, -{ - fn partial_cmp(&self, other: &GenericArray) -> Option { - PartialOrd::partial_cmp(self.as_slice(), other.as_slice()) - } -} - -impl Ord for GenericArray -where - N: ArrayLength, -{ - fn cmp(&self, other: &GenericArray) -> Ordering { - Ord::cmp(self.as_slice(), other.as_slice()) - } -} - -impl Debug for GenericArray -where - N: ArrayLength, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self[..].fmt(fmt) - } -} - -impl Borrow<[T]> for GenericArray -where - N: ArrayLength, -{ - #[inline(always)] - fn borrow(&self) -> &[T] { - &self[..] - } -} - -impl BorrowMut<[T]> for GenericArray -where - N: ArrayLength, -{ - #[inline(always)] - fn borrow_mut(&mut self) -> &mut [T] { - &mut self[..] - } -} - -impl AsRef<[T]> for GenericArray -where - N: ArrayLength, -{ - #[inline(always)] - fn as_ref(&self) -> &[T] { - &self[..] - } -} - -impl AsMut<[T]> for GenericArray -where - N: ArrayLength, -{ - #[inline(always)] - fn as_mut(&mut self) -> &mut [T] { - &mut self[..] - } -} - -impl Hash for GenericArray -where - N: ArrayLength, -{ - fn hash(&self, state: &mut H) - where - H: Hasher, - { - Hash::hash(&self[..], state) - } -} - -macro_rules! impl_from { - ($($n: expr => $ty: ty),*) => { - $( - impl From<[T; $n]> for GenericArray { - #[inline(always)] - fn from(arr: [T; $n]) -> Self { - unsafe { $crate::transmute(arr) } - } - } - - impl Into<[T; $n]> for GenericArray { - #[inline(always)] - fn into(self) -> [T; $n] { - unsafe { $crate::transmute(self) } - } - } - )* - - } -} - -impl_from! { - 1 => ::typenum::U1, - 2 => ::typenum::U2, - 3 => ::typenum::U3, - 4 => ::typenum::U4, - 5 => ::typenum::U5, - 6 => ::typenum::U6, - 7 => ::typenum::U7, - 8 => ::typenum::U8, - 9 => ::typenum::U9, - 10 => ::typenum::U10, - 11 => ::typenum::U11, - 12 => ::typenum::U12, - 13 => ::typenum::U13, - 14 => ::typenum::U14, - 15 => ::typenum::U15, - 16 => ::typenum::U16, - 17 => ::typenum::U17, - 18 => ::typenum::U18, - 19 => ::typenum::U19, - 20 => ::typenum::U20, - 21 => ::typenum::U21, - 22 => ::typenum::U22, - 23 => ::typenum::U23, - 24 => ::typenum::U24, - 25 => ::typenum::U25, - 26 => ::typenum::U26, - 27 => ::typenum::U27, - 28 => ::typenum::U28, - 29 => ::typenum::U29, - 30 => ::typenum::U30, - 31 => ::typenum::U31, - 32 => ::typenum::U32 -} diff --git a/vendor/generic-array-0.12.4/src/iter.rs b/vendor/generic-array-0.12.4/src/iter.rs deleted file mode 100644 index a2d67fc67..000000000 --- a/vendor/generic-array-0.12.4/src/iter.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! `GenericArray` iterator implementation. - -use super::{ArrayLength, GenericArray}; -use core::{cmp, ptr, fmt, mem}; -use core::mem::ManuallyDrop; - -/// An iterator that moves out of a `GenericArray` -pub struct GenericArrayIter> { - // Invariants: index <= index_back <= N - // Only values in array[index..index_back] are alive at any given time. - // Values from array[..index] and array[index_back..] are already moved/dropped. - array: ManuallyDrop>, - index: usize, - index_back: usize, -} - -#[cfg(test)] -mod test { - use super::*; - - fn send(_iter: I) {} - - #[test] - fn test_send_iter() { - send(GenericArray::from([1, 2, 3, 4]).into_iter()); - } -} - -impl GenericArrayIter -where - N: ArrayLength, -{ - /// Returns the remaining items of this iterator as a slice - #[inline] - pub fn as_slice(&self) -> &[T] { - &self.array.as_slice()[self.index..self.index_back] - } - - /// Returns the remaining items of this iterator as a mutable slice - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [T] { - &mut self.array.as_mut_slice()[self.index..self.index_back] - } -} - -impl IntoIterator for GenericArray -where - N: ArrayLength, -{ - type Item = T; - type IntoIter = GenericArrayIter; - - fn into_iter(self) -> Self::IntoIter { - GenericArrayIter { - array: ManuallyDrop::new(self), - index: 0, - index_back: N::to_usize(), - } - } -} - -// Based on work in rust-lang/rust#49000 -impl fmt::Debug for GenericArrayIter -where - N: ArrayLength, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("GenericArrayIter") - .field(&self.as_slice()) - .finish() - } -} - -impl Drop for GenericArrayIter -where - N: ArrayLength, -{ - #[inline] - fn drop(&mut self) { - // Drop values that are still alive. - for p in self.as_mut_slice() { - unsafe { - ptr::drop_in_place(p); - } - } - } -} - -// Based on work in rust-lang/rust#49000 -impl Clone for GenericArrayIter -where - N: ArrayLength, -{ - fn clone(&self) -> Self { - // This places all cloned elements at the start of the new array iterator, - // not at their original indices. - unsafe { - let mut iter = GenericArrayIter { - array: ManuallyDrop::new(mem::uninitialized()), - index: 0, - index_back: 0, - }; - - for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) { - ptr::write(dst, src.clone()); - - iter.index_back += 1; - } - - iter - } - } -} - -impl Iterator for GenericArrayIter -where - N: ArrayLength, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - if self.index < self.index_back { - let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) }; - - self.index += 1; - - p - } else { - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - fn nth(&mut self, n: usize) -> Option { - // First consume values prior to the nth. - let ndrop = cmp::min(n, self.len()); - - for p in &mut self.array[self.index..self.index + ndrop] { - self.index += 1; - - unsafe { - ptr::drop_in_place(p); - } - } - - self.next() - } - - fn last(mut self) -> Option { - // Note, everything else will correctly drop first as `self` leaves scope. - self.next_back() - } -} - -impl DoubleEndedIterator for GenericArrayIter -where - N: ArrayLength, -{ - fn next_back(&mut self) -> Option { - if self.index < self.index_back { - self.index_back -= 1; - - unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) } - } else { - None - } - } -} - -impl ExactSizeIterator for GenericArrayIter -where - N: ArrayLength, -{ - fn len(&self) -> usize { - self.index_back - self.index - } -} - -// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized \ No newline at end of file diff --git a/vendor/generic-array-0.12.4/src/lib.rs b/vendor/generic-array-0.12.4/src/lib.rs deleted file mode 100644 index e98e8fd58..000000000 --- a/vendor/generic-array-0.12.4/src/lib.rs +++ /dev/null @@ -1,632 +0,0 @@ -//! This crate implements a structure that can be used as a generic array type.use -//! Core Rust array types `[T; N]` can't be used generically with -//! respect to `N`, so for example this: -//! -//! ```{should_fail} -//! struct Foo { -//! data: [T; N] -//! } -//! ``` -//! -//! won't work. -//! -//! **generic-array** exports a `GenericArray` type, which lets -//! the above be implemented as: -//! -//! ``` -//! # use generic_array::{ArrayLength, GenericArray}; -//! struct Foo> { -//! data: GenericArray -//! } -//! ``` -//! -//! The `ArrayLength` trait is implemented by default for -//! [unsigned integer types](../typenum/uint/index.html) from -//! [typenum](../typenum/index.html). -//! -//! For ease of use, an `arr!` macro is provided - example below: -//! -//! ``` -//! # #[macro_use] -//! # extern crate generic_array; -//! # extern crate typenum; -//! # fn main() { -//! let array = arr![u32; 1, 2, 3]; -//! assert_eq!(array[2], 3); -//! # } -//! ``` - -#![deny(missing_docs)] -#![no_std] - -#[cfg(feature = "serde")] -extern crate serde; - -#[cfg(test)] -extern crate bincode; - -pub extern crate typenum; - -mod hex; -mod impls; - -#[cfg(feature = "serde")] -pub mod impl_serde; - -use core::iter::FromIterator; -use core::marker::PhantomData; -use core::mem::ManuallyDrop; -use core::ops::{Deref, DerefMut}; -use core::{mem, ptr, slice}; -use typenum::bit::{B0, B1}; -use typenum::uint::{UInt, UTerm, Unsigned}; - -#[cfg_attr(test, macro_use)] -pub mod arr; -pub mod functional; -pub mod iter; -pub mod sequence; - -use functional::*; -pub use iter::GenericArrayIter; -use sequence::*; - -/// Trait making `GenericArray` work, marking types to be used as length of an array -pub unsafe trait ArrayLength: Unsigned { - /// Associated type representing the array type for the number - type ArrayType; -} - -unsafe impl ArrayLength for UTerm { - #[doc(hidden)] - type ArrayType = (); -} - -/// Internal type used to generate a struct of appropriate size -#[allow(dead_code)] -#[repr(C)] -#[doc(hidden)] -pub struct GenericArrayImplEven { - parent1: U, - parent2: U, - _marker: PhantomData, -} - -impl Clone for GenericArrayImplEven { - fn clone(&self) -> GenericArrayImplEven { - GenericArrayImplEven { - parent1: self.parent1.clone(), - parent2: self.parent2.clone(), - _marker: PhantomData, - } - } -} - -impl Copy for GenericArrayImplEven {} - -/// Internal type used to generate a struct of appropriate size -#[allow(dead_code)] -#[repr(C)] -#[doc(hidden)] -pub struct GenericArrayImplOdd { - parent1: U, - parent2: U, - data: T, -} - -impl Clone for GenericArrayImplOdd { - fn clone(&self) -> GenericArrayImplOdd { - GenericArrayImplOdd { - parent1: self.parent1.clone(), - parent2: self.parent2.clone(), - data: self.data.clone(), - } - } -} - -impl Copy for GenericArrayImplOdd {} - -unsafe impl> ArrayLength for UInt { - #[doc(hidden)] - type ArrayType = GenericArrayImplEven; -} - -unsafe impl> ArrayLength for UInt { - #[doc(hidden)] - type ArrayType = GenericArrayImplOdd; -} - -/// Struct representing a generic array - `GenericArray` works like [T; N] -#[allow(dead_code)] -pub struct GenericArray> { - data: U::ArrayType, -} - -unsafe impl> Send for GenericArray {} -unsafe impl> Sync for GenericArray {} - -impl Deref for GenericArray -where - N: ArrayLength, -{ - type Target = [T]; - - #[inline(always)] - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self as *const Self as *const T, N::to_usize()) } - } -} - -impl DerefMut for GenericArray -where - N: ArrayLength, -{ - #[inline(always)] - fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::to_usize()) } - } -} - -/// Creates an array one element at a time using a mutable iterator -/// you can write to with `ptr::write`. -/// -/// Incremenent the position while iterating to mark off created elements, -/// which will be dropped if `into_inner` is not called. -#[doc(hidden)] -pub struct ArrayBuilder> { - array: ManuallyDrop>, - position: usize, -} - -impl> ArrayBuilder { - #[doc(hidden)] - #[inline] - pub unsafe fn new() -> ArrayBuilder { - ArrayBuilder { - array: ManuallyDrop::new(mem::uninitialized()), - position: 0, - } - } - - /// Creates a mutable iterator for writing to the array using `ptr::write`. - /// - /// Increment the position value given as a mutable reference as you iterate - /// to mark how many elements have been created. - #[doc(hidden)] - #[inline] - pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { - (self.array.iter_mut(), &mut self.position) - } - - /// When done writing (assuming all elements have been written to), - /// get the inner array. - #[doc(hidden)] - #[inline] - pub unsafe fn into_inner(self) -> GenericArray { - let array = ptr::read(&self.array); - - mem::forget(self); - - ManuallyDrop::into_inner(array) - } -} - -impl> Drop for ArrayBuilder { - fn drop(&mut self) { - for value in &mut self.array[..self.position] { - unsafe { - ptr::drop_in_place(value); - } - } - } -} - -/// Consumes an array. -/// -/// Increment the position while iterating and any leftover elements -/// will be dropped if position does not go to N -#[doc(hidden)] -pub struct ArrayConsumer> { - array: ManuallyDrop>, - position: usize, -} - -impl> ArrayConsumer { - #[doc(hidden)] - #[inline] - pub unsafe fn new(array: GenericArray) -> ArrayConsumer { - ArrayConsumer { - array: ManuallyDrop::new(array), - position: 0, - } - } - - /// Creates an iterator and mutable reference to the internal position - /// to keep track of consumed elements. - /// - /// Increment the position as you iterate to mark off consumed elements - #[doc(hidden)] - #[inline] - pub unsafe fn iter_position(&mut self) -> (slice::Iter, &mut usize) { - (self.array.iter(), &mut self.position) - } -} - -impl> Drop for ArrayConsumer { - fn drop(&mut self) { - for value in &mut self.array[self.position..N::to_usize()] { - unsafe { - ptr::drop_in_place(value); - } - } - } -} - -impl<'a, T: 'a, N> IntoIterator for &'a GenericArray -where - N: ArrayLength, -{ - type IntoIter = slice::Iter<'a, T>; - type Item = &'a T; - - fn into_iter(self: &'a GenericArray) -> Self::IntoIter { - self.as_slice().iter() - } -} - -impl<'a, T: 'a, N> IntoIterator for &'a mut GenericArray -where - N: ArrayLength, -{ - type IntoIter = slice::IterMut<'a, T>; - type Item = &'a mut T; - - fn into_iter(self: &'a mut GenericArray) -> Self::IntoIter { - self.as_mut_slice().iter_mut() - } -} - -impl FromIterator for GenericArray -where - N: ArrayLength, -{ - fn from_iter(iter: I) -> GenericArray - where - I: IntoIterator, - { - unsafe { - let mut destination = ArrayBuilder::new(); - - { - let (destination_iter, position) = destination.iter_position(); - - for (src, dst) in iter.into_iter().zip(destination_iter) { - ptr::write(dst, src); - - *position += 1; - } - } - - if destination.position < N::to_usize() { - from_iter_length_fail(destination.position, N::to_usize()); - } - - destination.into_inner() - } - } -} - -#[inline(never)] -#[cold] -fn from_iter_length_fail(length: usize, expected: usize) -> ! { - panic!( - "GenericArray::from_iter received {} elements but expected {}", - length, expected - ); -} - -unsafe impl GenericSequence for GenericArray -where - N: ArrayLength, - Self: IntoIterator, -{ - type Length = N; - type Sequence = Self; - - fn generate(mut f: F) -> GenericArray - where - F: FnMut(usize) -> T, - { - unsafe { - let mut destination = ArrayBuilder::new(); - - { - let (destination_iter, position) = destination.iter_position(); - - for (i, dst) in destination_iter.enumerate() { - ptr::write(dst, f(i)); - - *position += 1; - } - } - - destination.into_inner() - } - } - - #[doc(hidden)] - fn inverted_zip( - self, - lhs: GenericArray, - mut f: F, - ) -> MappedSequence, B, U> - where - GenericArray: - GenericSequence + MappedGenericSequence, - Self: MappedGenericSequence, - Self::Length: ArrayLength + ArrayLength, - F: FnMut(B, Self::Item) -> U, - { - unsafe { - let mut left = ArrayConsumer::new(lhs); - let mut right = ArrayConsumer::new(self); - - let (left_array_iter, left_position) = left.iter_position(); - let (right_array_iter, right_position) = right.iter_position(); - - FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| { - let left_value = ptr::read(l); - let right_value = ptr::read(r); - - *left_position += 1; - *right_position += 1; - - f(left_value, right_value) - })) - } - } - - #[doc(hidden)] - fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence - where - Lhs: GenericSequence + MappedGenericSequence, - Self: MappedGenericSequence, - Self::Length: ArrayLength + ArrayLength, - F: FnMut(Lhs::Item, Self::Item) -> U, - { - unsafe { - let mut right = ArrayConsumer::new(self); - - let (right_array_iter, right_position) = right.iter_position(); - - FromIterator::from_iter( - lhs.into_iter() - .zip(right_array_iter) - .map(|(left_value, r)| { - let right_value = ptr::read(r); - - *right_position += 1; - - f(left_value, right_value) - }), - ) - } - } -} - -unsafe impl MappedGenericSequence for GenericArray -where - N: ArrayLength + ArrayLength, - GenericArray: GenericSequence, -{ - type Mapped = GenericArray; -} - -unsafe impl FunctionalSequence for GenericArray -where - N: ArrayLength, - Self: GenericSequence, -{ - fn map(self, mut f: F) -> MappedSequence - where - Self::Length: ArrayLength, - Self: MappedGenericSequence, - F: FnMut(T) -> U, - { - unsafe { - let mut source = ArrayConsumer::new(self); - - let (array_iter, position) = source.iter_position(); - - FromIterator::from_iter(array_iter.map(|src| { - let value = ptr::read(src); - - *position += 1; - - f(value) - })) - } - } - - #[inline] - fn zip(self, rhs: Rhs, f: F) -> MappedSequence - where - Self: MappedGenericSequence, - Rhs: MappedGenericSequence>, - Self::Length: ArrayLength + ArrayLength, - Rhs: GenericSequence, - F: FnMut(T, Rhs::Item) -> U, - { - rhs.inverted_zip(self, f) - } - - fn fold(self, init: U, mut f: F) -> U - where - F: FnMut(U, T) -> U, - { - unsafe { - let mut source = ArrayConsumer::new(self); - - let (array_iter, position) = source.iter_position(); - - array_iter.fold(init, |acc, src| { - let value = ptr::read(src); - - *position += 1; - - f(acc, value) - }) - } - } -} - -impl GenericArray -where - N: ArrayLength, -{ - /// Extracts a slice containing the entire array. - #[inline] - pub fn as_slice(&self) -> &[T] { - self.deref() - } - - /// Extracts a mutable slice containing the entire array. - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [T] { - self.deref_mut() - } - - /// Converts slice to a generic array reference with inferred length; - /// - /// Length of the slice must be equal to the length of the array. - #[inline] - pub fn from_slice(slice: &[T]) -> &GenericArray { - slice.into() - } - - /// Converts mutable slice to a mutable generic array reference - /// - /// Length of the slice must be equal to the length of the array. - #[inline] - pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray { - slice.into() - } -} - -impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { - /// Converts slice to a generic array reference with inferred length; - /// - /// Length of the slice must be equal to the length of the array. - #[inline] - fn from(slice: &[T]) -> &GenericArray { - assert_eq!(slice.len(), N::to_usize()); - - unsafe { &*(slice.as_ptr() as *const GenericArray) } - } -} - -impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray { - /// Converts mutable slice to a mutable generic array reference - /// - /// Length of the slice must be equal to the length of the array. - #[inline] - fn from(slice: &mut [T]) -> &mut GenericArray { - assert_eq!(slice.len(), N::to_usize()); - - unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } - } -} - -impl GenericArray -where - N: ArrayLength, -{ - /// Construct a `GenericArray` from a slice by cloning its content - /// - /// Length of the slice must be equal to the length of the array - #[inline] - pub fn clone_from_slice(list: &[T]) -> GenericArray { - Self::from_exact_iter(list.iter().cloned()) - .expect("Slice must be the same length as the array") - } -} - -impl GenericArray -where - N: ArrayLength, -{ - /// Creates a new `GenericArray` instance from an iterator with a known exact size. - /// - /// Returns `None` if the size is not equal to the number of elements in the `GenericArray`. - pub fn from_exact_iter(iter: I) -> Option - where - I: IntoIterator, - ::IntoIter: ExactSizeIterator, - { - let iter = iter.into_iter(); - - if iter.len() == N::to_usize() { - unsafe { - let mut destination = ArrayBuilder::new(); - - { - let (destination_iter, position) = destination.iter_position(); - - for (dst, src) in destination_iter.zip(iter.into_iter()) { - ptr::write(dst, src); - - *position += 1; - } - } - - Some(destination.into_inner()) - } - } else { - None - } - } -} - -/// A reimplementation of the `transmute` function, avoiding problems -/// when the compiler can't prove equal sizes. -#[inline] -#[doc(hidden)] -pub unsafe fn transmute(a: A) -> B { - let b = ::core::ptr::read(&a as *const A as *const B); - ::core::mem::forget(a); - b -} - -#[cfg(test)] -mod test { - // Compile with: - // cargo rustc --lib --profile test --release -- - // -C target-cpu=native -C opt-level=3 --emit asm - // and view the assembly to make sure test_assembly generates - // SIMD instructions instead of a niave loop. - - #[inline(never)] - pub fn black_box(val: T) -> T { - use core::{mem, ptr}; - - let ret = unsafe { ptr::read_volatile(&val) }; - mem::forget(val); - ret - } - - #[test] - fn test_assembly() { - use functional::*; - - let a = black_box(arr![i32; 1, 3, 5, 7]); - let b = black_box(arr![i32; 2, 4, 6, 8]); - - let c = (&a).zip(b, |l, r| l + r); - - let d = a.fold(0, |a, x| a + x); - - assert_eq!(c, arr![i32; 3, 7, 11, 15]); - - assert_eq!(d, 16); - } -} diff --git a/vendor/generic-array-0.12.4/src/sequence.rs b/vendor/generic-array-0.12.4/src/sequence.rs deleted file mode 100644 index 7b928abda..000000000 --- a/vendor/generic-array-0.12.4/src/sequence.rs +++ /dev/null @@ -1,320 +0,0 @@ -//! Useful traits for manipulating sequences of data stored in `GenericArray`s - -use super::*; -use core::{mem, ptr}; -use core::ops::{Add, Sub}; -use typenum::operator_aliases::*; - -/// Defines some sequence with an associated length and iteration capabilities. -/// -/// This is useful for passing N-length generic arrays as generics. -pub unsafe trait GenericSequence: Sized + IntoIterator { - /// `GenericArray` associated length - type Length: ArrayLength; - - /// Concrete sequence type used in conjuction with reference implementations of `GenericSequence` - type Sequence: GenericSequence + FromIterator; - - /// Initializes a new sequence instance using the given function. - /// - /// If the generator function panics while initializing the sequence, - /// any already initialized elements will be dropped. - fn generate(f: F) -> Self::Sequence - where - F: FnMut(usize) -> T; - - #[doc(hidden)] - fn inverted_zip( - self, - lhs: GenericArray, - mut f: F, - ) -> MappedSequence, B, U> - where - GenericArray: GenericSequence - + MappedGenericSequence, - Self: MappedGenericSequence, - Self::Length: ArrayLength + ArrayLength, - F: FnMut(B, Self::Item) -> U, - { - unsafe { - let mut left = ArrayConsumer::new(lhs); - - let (left_array_iter, left_position) = left.iter_position(); - - FromIterator::from_iter( - left_array_iter - .zip(self.into_iter()) - .map(|(l, right_value)| { - let left_value = ptr::read(l); - - *left_position += 1; - - f(left_value, right_value) - }) - ) - } - } - - #[doc(hidden)] - fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence - where - Lhs: GenericSequence + MappedGenericSequence, - Self: MappedGenericSequence, - Self::Length: ArrayLength + ArrayLength, - F: FnMut(Lhs::Item, Self::Item) -> U, - { - FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r))) - } -} - -/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item` -/// -/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`, -/// this can be useful for keeping things organized. -pub type SequenceItem = ::Item; - -unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a S -where - &'a S: IntoIterator, -{ - type Length = S::Length; - type Sequence = S::Sequence; - - #[inline] - fn generate(f: F) -> Self::Sequence - where - F: FnMut(usize) -> T, - { - S::generate(f) - } -} - -unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a mut S -where - &'a mut S: IntoIterator, -{ - type Length = S::Length; - type Sequence = S::Sequence; - - #[inline] - fn generate(f: F) -> Self::Sequence - where - F: FnMut(usize) -> T, - { - S::generate(f) - } -} - -/// Defines any `GenericSequence` which can be lengthened or extended by appending -/// or prepending an element to it. -/// -/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back` -pub unsafe trait Lengthen: Sized + GenericSequence { - /// `GenericSequence` that has one more element than `Self` - type Longer: Shorten; - - /// Returns a new array with the given element appended to the end of it. - /// - /// Example: - /// - /// ```ignore - /// let a = arr![i32; 1, 2, 3]; - /// - /// let b = a.append(4); - /// - /// assert_eq!(b, arr![i32; 1, 2, 3, 4]); - /// ``` - fn append(self, last: T) -> Self::Longer; - - /// Returns a new array with the given element prepended to the front of it. - /// - /// Example: - /// - /// ```ignore - /// let a = arr![i32; 1, 2, 3]; - /// - /// let b = a.prepend(4); - /// - /// assert_eq!(b, arr![i32; 4, 1, 2, 3]); - /// ``` - fn prepend(self, first: T) -> Self::Longer; -} - -/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it. -/// -/// Additionally, any shortened sequence can be lengthened by -/// appending or prepending an element to it. -pub unsafe trait Shorten: Sized + GenericSequence { - /// `GenericSequence` that has one less element than `Self` - type Shorter: Lengthen; - - /// Returns a new array without the last element, and the last element. - /// - /// Example: - /// - /// ```ignore - /// let a = arr![i32; 1, 2, 3, 4]; - /// - /// let (init, last) = a.pop_back(); - /// - /// assert_eq!(init, arr![i32; 1, 2, 3]); - /// assert_eq!(last, 4); - /// ``` - fn pop_back(self) -> (Self::Shorter, T); - - /// Returns a new array without the first element, and the first element. - /// Example: - /// - /// ```ignore - /// let a = arr![i32; 1, 2, 3, 4]; - /// - /// let (head, tail) = a.pop_front(); - /// - /// assert_eq!(head, 1); - /// assert_eq!(tail, arr![i32; 2, 3, 4]); - /// ``` - fn pop_front(self) -> (T, Self::Shorter); -} - -unsafe impl> Lengthen for GenericArray -where - N: Add, - Add1: ArrayLength, - Add1: Sub, - Sub1>: ArrayLength, -{ - type Longer = GenericArray>; - - fn append(self, last: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; - - unsafe { - ptr::write(longer.as_mut_ptr() as *mut _, self); - ptr::write(&mut longer[N::to_usize()], last); - } - - longer - } - - fn prepend(self, first: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; - - let longer_ptr = longer.as_mut_ptr(); - - unsafe { - ptr::write(longer_ptr as *mut _, first); - ptr::write(longer_ptr.offset(1) as *mut _, self); - } - - longer - } -} - -unsafe impl> Shorten for GenericArray -where - N: Sub, - Sub1: ArrayLength, - Sub1: Add, - Add1>: ArrayLength, -{ - type Shorter = GenericArray>; - - fn pop_back(self) -> (Self::Shorter, T) { - let init_ptr = self.as_ptr(); - let last_ptr = unsafe { init_ptr.offset(Sub1::::to_usize() as isize) }; - - let init = unsafe { ptr::read(init_ptr as _) }; - let last = unsafe { ptr::read(last_ptr as _) }; - - mem::forget(self); - - (init, last) - } - - fn pop_front(self) -> (T, Self::Shorter) { - let head_ptr = self.as_ptr(); - let tail_ptr = unsafe { head_ptr.offset(1) }; - - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; - - mem::forget(self); - - (head, tail) - } -} - -/// Defines a `GenericSequence` that can be split into two parts at a given pivot index. -pub unsafe trait Split: GenericSequence -where - K: ArrayLength, -{ - /// First part of the resulting split array - type First: GenericSequence; - /// Second part of the resulting split array - type Second: GenericSequence; - - /// Splits an array at the given index, returning the separate parts of the array. - fn split(self) -> (Self::First, Self::Second); -} - -unsafe impl Split for GenericArray -where - N: ArrayLength, - K: ArrayLength, - N: Sub, - Diff: ArrayLength, -{ - type First = GenericArray; - type Second = GenericArray>; - - fn split(self) -> (Self::First, Self::Second) { - let head_ptr = self.as_ptr(); - let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) }; - - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; - - mem::forget(self); - - (head, tail) - } -} - -/// Defines `GenericSequence`s which can be joined together, forming a larger array. -pub unsafe trait Concat: GenericSequence -where - M: ArrayLength, -{ - /// Sequence to be concatenated with `self` - type Rest: GenericSequence; - - /// Resulting sequence formed by the concatenation. - type Output: GenericSequence; - - /// Concatenate, or join, two sequences. - fn concat(self, rest: Self::Rest) -> Self::Output; -} - -unsafe impl Concat for GenericArray -where - N: ArrayLength + Add, - M: ArrayLength, - Sum: ArrayLength, -{ - type Rest = GenericArray; - type Output = GenericArray>; - - fn concat(self, rest: Self::Rest) -> Self::Output { - let mut output: Self::Output = unsafe { mem::uninitialized() }; - - let output_ptr = output.as_mut_ptr(); - - unsafe { - ptr::write(output_ptr as *mut _, self); - ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest); - } - - output - } -} diff --git a/vendor/generic-array-0.12.4/tests/arr.rs b/vendor/generic-array-0.12.4/tests/arr.rs deleted file mode 100644 index c37b5d50f..000000000 --- a/vendor/generic-array-0.12.4/tests/arr.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[macro_use] -extern crate generic_array; -extern crate typenum; - -#[test] -fn empty_without_trailing_comma() { - let ar = arr![u8; ]; - assert_eq!(format!("{:x}", ar), ""); -} - -#[test] -fn empty_with_trailing_comma() { - let ar = arr![u8; , ]; - assert_eq!(format!("{:x}", ar), ""); -} - -#[test] -fn without_trailing_comma() { - let ar = arr![u8; 10, 20, 30]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} - -#[test] -fn with_trailing_comma() { - let ar = arr![u8; 10, 20, 30, ]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} diff --git a/vendor/generic-array-0.12.4/tests/generics.rs b/vendor/generic-array-0.12.4/tests/generics.rs deleted file mode 100644 index d48fe08c0..000000000 --- a/vendor/generic-array-0.12.4/tests/generics.rs +++ /dev/null @@ -1,98 +0,0 @@ -#![recursion_limit = "128"] - -#[macro_use] -extern crate generic_array; - -use generic_array::typenum::consts::U4; - -use std::fmt::Debug; -use std::ops::Add; - -use generic_array::{GenericArray, ArrayLength}; -use generic_array::sequence::*; -use generic_array::functional::*; - -/// Example function using generics to pass N-length sequences and map them -pub fn generic_map(s: S) -where - S: FunctionalSequence, // `.map` - S::Item: Add, // `x + 1` - S: MappedGenericSequence, // `i32` -> `i32` - MappedSequence: Debug, // println! -{ - let a = s.map(|x| x + 1); - - println!("{:?}", a); -} - -/// Complex example function using generics to pass N-length sequences, zip them, and then map that result. -/// -/// If used with `GenericArray` specifically this isn't necessary -pub fn generic_sequence_zip_sum(a: A, b: B) -> i32 -where - A: FunctionalSequence, // `.zip` - B: FunctionalSequence, // `.zip` - A: MappedGenericSequence, // `i32` -> `i32` - B: MappedGenericSequence>, // `i32` -> `i32`, prove A and B can map to the same output - A::Item: Add, // `l + r` - MappedSequence: MappedGenericSequence + FunctionalSequence, // `.map` - SequenceItem>: Add, // `x + 1` - MappedSequence, i32, i32>: Debug, // `println!` - MappedSequence, i32, i32>: FunctionalSequence, // `.fold` - SequenceItem, i32, i32>>: Add // `x + a`, note the order -{ - let c = a.zip(b, |l, r| l + r).map(|x| x + 1); - - println!("{:?}", c); - - c.fold(0, |a, x| x + a) -} - -/// Super-simple fixed-length i32 `GenericArray`s -pub fn generic_array_plain_zip_sum(a: GenericArray, b: GenericArray) -> i32 { - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -pub fn generic_array_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -pub fn generic_array_same_type_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength + ArrayLength<>::Output>, - T: Add, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -/// Complex example using fully generic `GenericArray`s with the same length. -/// -/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway. -pub fn generic_array_zip_sum + ArrayLength>(a: GenericArray, b: GenericArray) -> i32 -where - A: Add, - N: ArrayLength<>::Output> + - ArrayLength<<>::Output as Add>::Output>, - >::Output: Add, - <>::Output as Add>::Output: Add, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -#[test] -fn test_generics() { - generic_map(arr![i32; 1, 2, 3, 4]); - - assert_eq!(generic_sequence_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_plain_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_same_type_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); -} \ No newline at end of file diff --git a/vendor/generic-array-0.12.4/tests/hex.rs b/vendor/generic-array-0.12.4/tests/hex.rs deleted file mode 100644 index 0882e9bb3..000000000 --- a/vendor/generic-array-0.12.4/tests/hex.rs +++ /dev/null @@ -1,61 +0,0 @@ -#[macro_use] -extern crate generic_array; -extern crate typenum; - -use generic_array::GenericArray; -use std::str::from_utf8; -use typenum::U2048; - -#[test] -fn short_lower_hex() { - let ar = arr![u8; 10, 20, 30]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} - -#[test] -fn short_upper_hex() { - let ar = arr![u8; 30, 20, 10]; - assert_eq!(format!("{:X}", ar), "1E140A"); -} - -#[test] -fn long_lower_hex() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:x}", ar), from_utf8(&[b'0'; 4096]).unwrap()); -} - -#[test] -fn long_lower_hex_truncated() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:.3001x}", ar), from_utf8(&[b'0'; 3001]).unwrap()); -} - -#[test] -fn long_upper_hex() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:X}", ar), from_utf8(&[b'0'; 4096]).unwrap()); -} - -#[test] -fn long_upper_hex_truncated() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:.2777X}", ar), from_utf8(&[b'0'; 2777]).unwrap()); -} - -#[test] -fn truncated_lower_hex() { - let ar = arr![u8; 10, 20, 30, 40, 50]; - assert_eq!(format!("{:.2x}", ar), "0a"); - assert_eq!(format!("{:.3x}", ar), "0a1"); - assert_eq!(format!("{:.4x}", ar), "0a14"); -} - -#[test] -fn truncated_upper_hex() { - let ar = arr![u8; 30, 20, 10, 17, 0]; - assert_eq!(format!("{:.4X}", ar), "1E14"); - assert_eq!(format!("{:.5X}", ar), "1E140"); - assert_eq!(format!("{:.6X}", ar), "1E140A"); - assert_eq!(format!("{:.7X}", ar), "1E140A1"); - assert_eq!(format!("{:.8X}", ar), "1E140A11"); -} diff --git a/vendor/generic-array-0.12.4/tests/import_name.rs b/vendor/generic-array-0.12.4/tests/import_name.rs deleted file mode 100644 index 27653c9a8..000000000 --- a/vendor/generic-array-0.12.4/tests/import_name.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[macro_use] -extern crate generic_array as gen_arr; - -use gen_arr::typenum; - -#[test] -fn test_different_crate_name() { - let _: gen_arr::GenericArray = arr![u32; 0, 1, 2, 3]; - let _: gen_arr::GenericArray = arr![u32;]; -} diff --git a/vendor/generic-array-0.12.4/tests/iter.rs b/vendor/generic-array-0.12.4/tests/iter.rs deleted file mode 100644 index 47860d728..000000000 --- a/vendor/generic-array-0.12.4/tests/iter.rs +++ /dev/null @@ -1,164 +0,0 @@ -#[macro_use] -extern crate generic_array; - -use std::cell::Cell; -use std::ops::Drop; - -use generic_array::GenericArray; -use generic_array::typenum::consts::U5; - -#[test] -fn test_into_iter_as_slice() { - let array = arr![char; 'a', 'b', 'c']; - let mut into_iter = array.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &['b', 'c']); - let _ = into_iter.next().unwrap(); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &[]); -} - -#[test] -fn test_into_iter_as_mut_slice() { - let array = arr![char; 'a', 'b', 'c']; - let mut into_iter = array.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - into_iter.as_mut_slice()[0] = 'x'; - into_iter.as_mut_slice()[1] = 'y'; - assert_eq!(into_iter.next().unwrap(), 'x'); - assert_eq!(into_iter.as_slice(), &['y', 'c']); -} - -#[test] -fn test_into_iter_debug() { - let array = arr![char; 'a', 'b', 'c']; - let into_iter = array.into_iter(); - let debug = format!("{:?}", into_iter); - assert_eq!(debug, "GenericArrayIter(['a', 'b', 'c'])"); -} - -#[test] -fn test_into_iter_clone() { - fn iter_equal>(it: I, slice: &[i32]) { - let v: Vec = it.collect(); - assert_eq!(&v[..], slice); - } - let mut it = arr![i32; 1, 2, 3].into_iter(); - iter_equal(it.clone(), &[1, 2, 3]); - assert_eq!(it.next(), Some(1)); - let mut it = it.rev(); - iter_equal(it.clone(), &[3, 2]); - assert_eq!(it.next(), Some(3)); - iter_equal(it.clone(), &[2]); - assert_eq!(it.next(), Some(2)); - iter_equal(it.clone(), &[]); - assert_eq!(it.next(), None); -} - -#[test] -fn test_into_iter_nth() { - let v = arr![i32; 0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]); - } - assert_eq!(v.clone().into_iter().nth(v.len()), None); - - let mut iter = v.into_iter(); - assert_eq!(iter.nth(2).unwrap(), v[2]); - assert_eq!(iter.nth(1).unwrap(), v[4]); -} - -#[test] -fn test_into_iter_last() { - let v = arr![i32; 0, 1, 2, 3, 4]; - assert_eq!(v.into_iter().last().unwrap(), 4); - assert_eq!(arr![i32; 0].into_iter().last().unwrap(), 0); -} - -#[test] -fn test_into_iter_count() { - let v = arr![i32; 0, 1, 2, 3, 4]; - assert_eq!(v.clone().into_iter().count(), 5); - - let mut iter2 = v.into_iter(); - iter2.next(); - iter2.next(); - assert_eq!(iter2.count(), 3); -} - -#[test] -fn test_into_iter_flat_map() { - assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10)); -} - -#[test] -fn test_into_iter_drops() { - struct R<'a> { - i: &'a Cell, - } - - impl<'a> Drop for R<'a> { - fn drop(&mut self) { - self.i.set(self.i.get() + 1); - } - } - - fn r(i: &Cell) -> R { - R { - i: i - } - } - - fn v(i: &Cell) -> GenericArray { - arr![R; r(i), r(i), r(i), r(i), r(i)] - } - - let i = Cell::new(0); - { - v(&i).into_iter(); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - { - let mut iter = v(&i).into_iter(); - let _x = iter.next(); - assert_eq!(i.get(), 0); - assert_eq!(iter.count(), 4); - assert_eq!(i.get(), 4); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - { - let mut iter = v(&i).into_iter(); - let _x = iter.nth(2); - assert_eq!(i.get(), 2); - let _y = iter.last(); - assert_eq!(i.get(), 3); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - for (index, _x) in v(&i).into_iter().enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - for (index, _x) in v(&i).into_iter().rev().enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); -} - -/* -//TODO: Cover this -#[allow(dead_code)] -fn assert_covariance() { - fn into_iter<'new>(i: GenericArrayIter<&'static str, U10>) -> GenericArrayIter<&'new str, U10> { - i - } -} -*/ \ No newline at end of file diff --git a/vendor/generic-array-0.12.4/tests/mod.rs b/vendor/generic-array-0.12.4/tests/mod.rs deleted file mode 100644 index 6c6d9eb49..000000000 --- a/vendor/generic-array-0.12.4/tests/mod.rs +++ /dev/null @@ -1,287 +0,0 @@ -#![recursion_limit = "128"] -#![no_std] -#[macro_use] -extern crate generic_array; -use core::cell::Cell; -use core::ops::{Add, Drop}; -use generic_array::GenericArray; -use generic_array::functional::*; -use generic_array::sequence::*; -use generic_array::typenum::{U1, U3, U4, U97}; - -#[test] -fn test() { - let mut list97 = [0; 97]; - for i in 0..97 { - list97[i] = i as i32; - } - let l: GenericArray = GenericArray::clone_from_slice(&list97); - assert_eq!(l[0], 0); - assert_eq!(l[1], 1); - assert_eq!(l[32], 32); - assert_eq!(l[56], 56); -} - -#[test] -fn test_drop() { - #[derive(Clone)] - struct TestDrop<'a>(&'a Cell); - - impl<'a> Drop for TestDrop<'a> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let drop_counter = Cell::new(0); - { - let _: GenericArray = arr![TestDrop; TestDrop(&drop_counter), - TestDrop(&drop_counter), - TestDrop(&drop_counter)]; - } - assert_eq!(drop_counter.get(), 3); -} - -#[test] -fn test_arr() { - let test: GenericArray = arr![u32; 1, 2, 3]; - assert_eq!(test[1], 2); -} - -#[test] -fn test_copy() { - let test = arr![u32; 1, 2, 3]; - let test2 = test; - // if GenericArray is not copy, this should fail as a use of a moved value - assert_eq!(test[1], 2); - assert_eq!(test2[0], 1); -} - -#[derive(Debug, PartialEq, Eq)] -struct NoClone(T); - -#[test] -fn test_from_slice() { - let arr = [1, 2, 3, 4]; - let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); - assert_eq!(&arr[..3], gen_arr.as_slice()); - let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; - let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); - assert_eq!(&arr[..3], gen_arr.as_slice()); -} - -#[test] -fn test_from_mut_slice() { - let mut arr = [1, 2, 3, 4]; - { - let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); - gen_arr[2] = 10; - } - assert_eq!(arr, [1, 2, 10, 4]); - let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; - { - let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); - gen_arr[2] = NoClone(10); - } - assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]); -} - -#[test] -fn test_default() { - let arr = GenericArray::::default(); - assert_eq!(arr[0], 0); -} - -#[test] -fn test_from() { - let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]; - let garray: GenericArray<(usize, usize, usize), U3> = data.into(); - assert_eq!(&data, garray.as_slice()); -} - -#[test] -fn test_unit_macro() { - let arr = arr![f32; 3.14]; - assert_eq!(arr[0], 3.14); -} - -#[test] -fn test_empty_macro() { - let _arr = arr![f32;]; -} - -#[test] -fn test_cmp() { - arr![u8; 0x00].cmp(&arr![u8; 0x00]); -} - -/// This test should cause a helpful compile error if uncommented. -// #[test] -// fn test_empty_macro2(){ -// let arr = arr![]; -// } -#[cfg(feature = "serde")] -mod impl_serde { - extern crate serde_json; - - use generic_array::GenericArray; - use generic_array::typenum::U6; - - #[test] - fn test_serde_implementation() { - let array: GenericArray = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0]; - let string = serde_json::to_string(&array).unwrap(); - assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]"); - - let test_array: GenericArray = serde_json::from_str(&string).unwrap(); - assert_eq!(test_array, array); - } -} - -#[test] -fn test_map() { - let b: GenericArray = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3); - - assert_eq!(b, arr![i32; -3, 1, 5, 9]); -} - -#[test] -fn test_zip() { - let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1); - let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4); - - // Uses reference and non-reference arguments - let c = (&a).zip(b, |r, l| *r as i32 + l); - - assert_eq!(c, arr![i32; 1, 6, 11, 16]); -} - -#[test] -#[should_panic] -fn test_from_iter_short() { - use core::iter::repeat; - - let a: GenericArray<_, U4> = repeat(11).take(3).collect(); - - assert_eq!(a, arr![i32; 11, 11, 11, 0]); -} - -#[test] -fn test_from_iter() { - use core::iter::{once, repeat}; - - let a: GenericArray<_, U4> = repeat(11).take(3).chain(once(0)).collect(); - - assert_eq!(a, arr![i32; 11, 11, 11, 0]); -} - -#[test] -fn test_sizes() { - #![allow(dead_code)] - use core::mem::{size_of, size_of_val}; - - #[derive(Debug, Copy, Clone)] - #[repr(C)] - #[repr(packed)] - struct Test { - t: u16, - s: u32, - r: u16, - f: u16, - o: u32, - } - - assert_eq!(size_of::(), 14); - - assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::() * 3); - assert_eq!(size_of_val(&arr![u32; 1]), size_of::() * 1); - assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::() * 4); - - assert_eq!(size_of::>(), size_of::() * 97); -} - -#[test] -fn test_append() { - let a = arr![i32; 1, 2, 3]; - - let b = a.append(4); - - assert_eq!(b, arr![i32; 1, 2, 3, 4]); -} - -#[test] -fn test_prepend() { - let a = arr![i32; 1, 2, 3]; - - let b = a.prepend(4); - - assert_eq!(b, arr![i32; 4, 1, 2, 3]); -} - -#[test] -fn test_pop() { - let a = arr![i32; 1, 2, 3, 4]; - - let (init, last) = a.pop_back(); - - assert_eq!(init, arr![i32; 1, 2, 3]); - assert_eq!(last, 4); - - let (head, tail) = a.pop_front(); - - assert_eq!(head, 1); - assert_eq!(tail, arr![i32; 2, 3, 4]); -} - -#[test] -fn test_split() { - let a = arr![i32; 1, 2, 3, 4]; - - let (b, c) = a.split(); - - assert_eq!(b, arr![i32; 1]); - assert_eq!(c, arr![i32; 2, 3, 4]); - - let (e, f) = a.split(); - - assert_eq!(e, arr![i32; 1, 2]); - assert_eq!(f, arr![i32; 3, 4]); -} - -#[test] -fn test_concat() { - let a = arr![i32; 1, 2]; - let b = arr![i32; 3, 4]; - - let c = a.concat(b); - - assert_eq!(c, arr![i32; 1, 2, 3, 4]); - - let (d, e) = c.split(); - - assert_eq!(d, arr![i32; 1]); - assert_eq!(e, arr![i32; 2, 3, 4]); -} - -#[test] -fn test_fold() { - let a = arr![i32; 1, 2, 3, 4]; - - assert_eq!(10, a.fold(0, |a, x| a + x)); -} - -fn sum_generic(s: S) -> i32 -where - S: FunctionalSequence, - S::Item: Add, // `+` - i32: Add, // reflexive -{ - s.fold(0, |a, x| a + x) -} - -#[test] -fn test_sum() { - let a = sum_generic(arr![i32; 1, 2, 3, 4]); - - assert_eq!(a, 10); -} diff --git a/vendor/getrandom/.cargo-checksum.json b/vendor/getrandom/.cargo-checksum.json index 7bdcc1bc4..adfe6c9e5 100644 --- a/vendor/getrandom/.cargo-checksum.json +++ b/vendor/getrandom/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"e972a70c9a4729acbd6bd81ca0c3e03944cab242743b308d124d64b3552f8e63","Cargo.toml":"66283df4cc6406f65b46dded3469d23f9d1c6372a0385af8cdcde9da1b6cf5d9","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"7ae74633326a22fd6298d7f209fb14884277bd98049795f444945acbb2b0dfbd","benches/mod.rs":"5495735ff210a50cab23c2cc84191ed910af7c30395a3d9d6095b722765b3864","src/3ds.rs":"0f48fc15f89b518fb92e06aaa4838b62dc073598e8f288df56ad1e5a9251af1e","src/bsd_arandom.rs":"d2ee195acd80c7d1364a369ad0d2dad46f5f9f973f9d3960367413fd87acfcd6","src/custom.rs":"b363ee77664203d141985402433afd6808b72cc50bff586b3034d303eccfc281","src/dragonfly.rs":"28f3f7ac4f093dfb6cd2c8e7e0714f16d0f03f8c658e56caa8fe9bd03b1ff39b","src/error.rs":"110ffe8a2c6b0fa46a4e317e837efe617b343f250fedac61bcabc3c5250e7432","src/error_impls.rs":"9c34832ebb99cd5e31bc5c8ffc5beb5b3fa6f7ff0226aaa1cdf8e10e6d64b324","src/espidf.rs":"19f101486584fde6dad962f4d9792de168658047312106641a5caf6866a5bbcf","src/fuchsia.rs":"470d8509deb5b06fa6417f294c0a49e0e35a580249a5d8944c3be5aa746f64ea","src/ios.rs":"4bad4f5c096a50338b86aeac91a937c18bc55b9555e6f34806ad13732e64523d","src/js.rs":"04c750491ba3bcdad3609265938410ee09928c5d6dfd0d33d826a9884d13ac4c","src/lib.rs":"674af2d277b66ecf2e49e1059638abd58db089df095b8b65d9e347782e4bb1e0","src/linux_android.rs":"39cb80999c8534145240a350976d261b8924436bf9a4563960c7bd8c2c83c773","src/macos.rs":"b692f2fcc2319a5195f47751d5bd7dd87c7c24a61d14fa4e3dbc992ae66212b7","src/openbsd.rs":"066b2dd395c190444a658bb0b52a052eabbd68ea5a534fb729c7e5373abc0a6a","src/rdrand.rs":"79d23183b1905d61bd9df9729dc798505a2ed750d3339e342ab144e1709827e4","src/solaris_illumos.rs":"9c7004446fabe5a7a21c73d5a65d7e2115b5bd1d1dbb735c984cab3dba239785","src/solid.rs":"997035d54c9762d22a5a14f54e7fbed4dd266cdeacbdf6aab7d8aee05537e8ba","src/use_file.rs":"16e42eb0a56e375c330c1ca8eb58c444e82ef3ad35230b961fdba96a02a68804","src/util.rs":"da6964dc1523f1cb8d26365fa6a8ece46360587e6974931624b271f0c72cda8b","src/util_libc.rs":"9fd636b23121a86630f0c7891a310444f5b1bb29b0013290e130b79ed1e1f79e","src/vxworks.rs":"a5aa0e40f890e0f35626458bb656a3340b8af3111e4bacd2e12505a8d50a3505","src/wasi.rs":"02b3a75613dc80444847675ecfea59f390c2597ce1d3334612a8dba71f6082de","src/windows.rs":"e3c8f033d5d2a6b8abc5c92b005232f5aca8ce941bd94964a0f58f2436af9990","tests/common/mod.rs":"b6beee8f535d2d094a65711fe0af91a6fc220aa09729ed7269fe33cafdc9177f","tests/custom.rs":"9f2c0193193f6bcf641116ca0b3653b33d2015e0e98ce107ee1d1f60c5eeae3a","tests/normal.rs":"9e1c4b1e468a09ed0225370dfb6608f8b8135e0fabb09bbc1a718105164aade6","tests/rdrand.rs":"4474ccebf9d33c89288862a7e367018405968dddc55c7c6f97e21b5fe2264601"},"package":"9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"} \ No newline at end of file +{"files":{"CHANGELOG.md":"1289f7318d266dca92eceb373c5ff6ee81fa867a6f180ad57759d37df9fcad91","Cargo.toml":"2b0b1b62739f57c58e5069f90b70003f56f3242517d14ac1f875b9f36d227e6e","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"7ae74633326a22fd6298d7f209fb14884277bd98049795f444945acbb2b0dfbd","benches/mod.rs":"5495735ff210a50cab23c2cc84191ed910af7c30395a3d9d6095b722765b3864","src/3ds.rs":"0f48fc15f89b518fb92e06aaa4838b62dc073598e8f288df56ad1e5a9251af1e","src/bsd_arandom.rs":"d90c419d4def20f83e7535cd3f5ec07035045011a50c3652951d196a120c5d3e","src/custom.rs":"b363ee77664203d141985402433afd6808b72cc50bff586b3034d303eccfc281","src/dragonfly.rs":"47f933eac189f6ea48ecf021efd0747ebce1b43d1bece6bbf72a951bab705987","src/error.rs":"f87ce17f9299f9b59b47306dab25ed01d720a0ba53363f52b46b50e2f5e49e36","src/error_impls.rs":"9c34832ebb99cd5e31bc5c8ffc5beb5b3fa6f7ff0226aaa1cdf8e10e6d64b324","src/espidf.rs":"19f101486584fde6dad962f4d9792de168658047312106641a5caf6866a5bbcf","src/fuchsia.rs":"470d8509deb5b06fa6417f294c0a49e0e35a580249a5d8944c3be5aa746f64ea","src/ios.rs":"4bad4f5c096a50338b86aeac91a937c18bc55b9555e6f34806ad13732e64523d","src/js.rs":"04c750491ba3bcdad3609265938410ee09928c5d6dfd0d33d826a9884d13ac4c","src/lib.rs":"6f61a660fe35864a2fc8ed2fe29b1c2ddf5d29854a2871daade66f0059f65b8e","src/linux_android.rs":"ec24575aa4ae71b6991290dadfdea931b05397c3faababf24bd794f1a9624835","src/macos.rs":"6c09827ad5292cd022e063efa79523bfdb50ed08b9867ebaa007cd321b8d218e","src/openbsd.rs":"450a23ead462d4a840fee4aa0bfdab1e3d88c8f48e4bb608d457429ddeca69c0","src/rdrand.rs":"79d23183b1905d61bd9df9729dc798505a2ed750d3339e342ab144e1709827e4","src/solaris_illumos.rs":"d52fee9dd7d661f960c01894edd563c1ff8a512c111f7803092d9aa2ff98718e","src/solid.rs":"997035d54c9762d22a5a14f54e7fbed4dd266cdeacbdf6aab7d8aee05537e8ba","src/use_file.rs":"16e42eb0a56e375c330c1ca8eb58c444e82ef3ad35230b961fdba96a02a68804","src/util.rs":"da6964dc1523f1cb8d26365fa6a8ece46360587e6974931624b271f0c72cda8b","src/util_libc.rs":"2a63ac0e6dab16b85c4728b79a16e0640301e8b876f151b0a1db0b4394fa219f","src/vxworks.rs":"a5aa0e40f890e0f35626458bb656a3340b8af3111e4bacd2e12505a8d50a3505","src/wasi.rs":"dfdd0a870581948bd03abe64d49ca4295d9cfa26e09b97a526fd5e17148ad9ca","src/windows.rs":"d0b4f2afd1959660aa9abcd9477764bd7dc0b7d7048aee748804b37963c77c6f","tests/common/mod.rs":"b6beee8f535d2d094a65711fe0af91a6fc220aa09729ed7269fe33cafdc9177f","tests/custom.rs":"9f2c0193193f6bcf641116ca0b3653b33d2015e0e98ce107ee1d1f60c5eeae3a","tests/normal.rs":"9e1c4b1e468a09ed0225370dfb6608f8b8135e0fabb09bbc1a718105164aade6","tests/rdrand.rs":"4474ccebf9d33c89288862a7e367018405968dddc55c7c6f97e21b5fe2264601"},"package":"4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"} \ No newline at end of file diff --git a/vendor/getrandom/CHANGELOG.md b/vendor/getrandom/CHANGELOG.md index 4ab267ae0..b25704947 100644 --- a/vendor/getrandom/CHANGELOG.md +++ b/vendor/getrandom/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.7] - 2022-06-14 +### Changed +- Update `wasi` dependency to `0.11` [#253] + +### Fixed +- Use `AtomicPtr` instead of `AtomicUsize` for Strict Provenance compatibility. [#263] + +### Documentation +- Add comments explaining use of fallback mechanisms [#257] [#260] + +[#263]: https://github.com/rust-random/getrandom/pull/263 +[#260]: https://github.com/rust-random/getrandom/pull/260 +[#253]: https://github.com/rust-random/getrandom/pull/253 +[#257]: https://github.com/rust-random/getrandom/pull/257 + ## [0.2.6] - 2022-03-28 ### Added - Nintendo 3DS (`armv6k-nintendo-3ds`) support [#248] @@ -291,7 +306,8 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. -[0.2.5]: https://github.com/rust-random/getrandom/compare/v0.2.5...v0.2.6 +[0.2.7]: https://github.com/rust-random/getrandom/compare/v0.2.6...v0.2.7 +[0.2.6]: https://github.com/rust-random/getrandom/compare/v0.2.5...v0.2.6 [0.2.5]: https://github.com/rust-random/getrandom/compare/v0.2.4...v0.2.5 [0.2.4]: https://github.com/rust-random/getrandom/compare/v0.2.3...v0.2.4 [0.2.3]: https://github.com/rust-random/getrandom/compare/v0.2.2...v0.2.3 diff --git a/vendor/getrandom/Cargo.toml b/vendor/getrandom/Cargo.toml index 0a664244e..9b9c0880a 100644 --- a/vendor/getrandom/Cargo.toml +++ b/vendor/getrandom/Cargo.toml @@ -12,17 +12,29 @@ [package] edition = "2018" name = "getrandom" -version = "0.2.6" +version = "0.2.7" authors = ["The Rand Project Developers"] exclude = [".*"] description = "A small cross-platform library for retrieving random data from system source" documentation = "https://docs.rs/getrandom" -categories = ["os", "no-std"] +readme = "README.md" +categories = [ + "os", + "no-std", +] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-random/getrandom" + [package.metadata.docs.rs] -features = ["std", "custom"] -rustdoc-args = ["--cfg", "docsrs"] +features = [ + "std", + "custom", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] + [dependencies.cfg-if] version = "1" @@ -37,11 +49,20 @@ package = "rustc-std-workspace-core" [features] custom = [] -js = ["wasm-bindgen", "js-sys"] +js = [ + "wasm-bindgen", + "js-sys", +] rdrand = [] -rustc-dep-of-std = ["compiler_builtins", "core", "libc/rustc-dep-of-std", "wasi/rustc-dep-of-std"] +rustc-dep-of-std = [ + "compiler_builtins", + "core", + "libc/rustc-dep-of-std", + "wasi/rustc-dep-of-std", +] std = [] test-in-browser = [] + [target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.js-sys] version = "0.3" optional = true @@ -50,10 +71,13 @@ optional = true version = "0.2.62" optional = true default-features = false + [target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test] version = "0.3.18" + [target."cfg(target_os = \"wasi\")".dependencies.wasi] -version = "0.10" +version = "0.11" + [target."cfg(unix)".dependencies.libc] version = "0.2.120" default-features = false diff --git a/vendor/getrandom/src/bsd_arandom.rs b/vendor/getrandom/src/bsd_arandom.rs index f26f2609c..d44121254 100644 --- a/vendor/getrandom/src/bsd_arandom.rs +++ b/vendor/getrandom/src/bsd_arandom.rs @@ -31,6 +31,7 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t { } pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // getrandom(2) was introduced in FreeBSD 12.0 and NetBSD 10.0 #[cfg(target_os = "freebsd")] { use crate::util_libc::Weak; diff --git a/vendor/getrandom/src/dragonfly.rs b/vendor/getrandom/src/dragonfly.rs index f27e90690..8daaa4048 100644 --- a/vendor/getrandom/src/dragonfly.rs +++ b/vendor/getrandom/src/dragonfly.rs @@ -17,6 +17,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; + // getrandom(2) was introduced in DragonflyBSD 5.7 if let Some(fptr) = GETRANDOM.ptr() { let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) }); diff --git a/vendor/getrandom/src/error.rs b/vendor/getrandom/src/error.rs index 661575376..b5ab2bb18 100644 --- a/vendor/getrandom/src/error.rs +++ b/vendor/getrandom/src/error.rs @@ -109,10 +109,6 @@ cfg_if! { let idx = buf.iter().position(|&b| b == 0).unwrap_or(n); core::str::from_utf8(&buf[..idx]).ok() } - } else if #[cfg(target_os = "wasi")] { - fn os_err(errno: i32, _buf: &mut [u8]) -> Option { - wasi::Error::from_raw_error(errno as _) - } } else { fn os_err(_errno: i32, _buf: &mut [u8]) -> Option<&str> { None diff --git a/vendor/getrandom/src/lib.rs b/vendor/getrandom/src/lib.rs index 888b9a510..c62056e55 100644 --- a/vendor/getrandom/src/lib.rs +++ b/vendor/getrandom/src/lib.rs @@ -149,7 +149,7 @@ #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://docs.rs/getrandom/0.2.6" + html_root_url = "https://docs.rs/getrandom/0.2.7" )] #![no_std] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] diff --git a/vendor/getrandom/src/linux_android.rs b/vendor/getrandom/src/linux_android.rs index 5508fdd06..4270b67c6 100644 --- a/vendor/getrandom/src/linux_android.rs +++ b/vendor/getrandom/src/linux_android.rs @@ -14,6 +14,7 @@ use crate::{ }; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // getrandom(2) was introduced in Linux 3.17 static HAS_GETRANDOM: LazyBool = LazyBool::new(); if HAS_GETRANDOM.unsync_init(is_getrandom_available) { sys_fill_exact(dest, |buf| unsafe { diff --git a/vendor/getrandom/src/macos.rs b/vendor/getrandom/src/macos.rs index 585a35abd..671a053bf 100644 --- a/vendor/getrandom/src/macos.rs +++ b/vendor/getrandom/src/macos.rs @@ -17,6 +17,7 @@ use core::mem; type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // getentropy(2) was added in 10.12, Rust supports 10.7+ static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") }; if let Some(fptr) = GETENTROPY.ptr() { let func: GetEntropyFn = unsafe { mem::transmute(fptr) }; diff --git a/vendor/getrandom/src/openbsd.rs b/vendor/getrandom/src/openbsd.rs index c8d28b3d8..41371736f 100644 --- a/vendor/getrandom/src/openbsd.rs +++ b/vendor/getrandom/src/openbsd.rs @@ -10,6 +10,7 @@ use crate::{util_libc::last_os_error, Error}; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // getentropy(2) was added in OpenBSD 5.6, so we can use it unconditionally. for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; if ret == -1 { diff --git a/vendor/getrandom/src/solaris_illumos.rs b/vendor/getrandom/src/solaris_illumos.rs index 2d1b767bb..cf3067d6d 100644 --- a/vendor/getrandom/src/solaris_illumos.rs +++ b/vendor/getrandom/src/solaris_illumos.rs @@ -30,6 +30,7 @@ type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // getrandom(2) was introduced in Solaris 11.3 for Illumos in 2015. static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; if let Some(fptr) = GETRANDOM.ptr() { let func: GetRandomFn = unsafe { mem::transmute(fptr) }; diff --git a/vendor/getrandom/src/util_libc.rs b/vendor/getrandom/src/util_libc.rs index 6df1cd7da..d057071a7 100644 --- a/vendor/getrandom/src/util_libc.rs +++ b/vendor/getrandom/src/util_libc.rs @@ -6,8 +6,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] -use crate::{util::LazyUsize, Error}; -use core::{num::NonZeroU32, ptr::NonNull}; +use crate::Error; +use core::{ + num::NonZeroU32, + ptr::NonNull, + sync::atomic::{fence, AtomicPtr, Ordering}, +}; +use libc::c_void; cfg_if! { if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { @@ -76,29 +81,57 @@ pub fn sys_fill_exact( // A "weak" binding to a C function that may or may not be present at runtime. // Used for supporting newer OS features while still building on older systems. -// F must be a function pointer of type `unsafe extern "C" fn`. Based off of the -// weak! macro in libstd. +// Based off of the DlsymWeak struct in libstd: +// https://github.com/rust-lang/rust/blob/1.61.0/library/std/src/sys/unix/weak.rs#L84 +// except that the caller must manually cast self.ptr() to a function pointer. pub struct Weak { name: &'static str, - addr: LazyUsize, + addr: AtomicPtr, } impl Weak { + // A non-null pointer value which indicates we are uninitialized. This + // constant should ideally not be a valid address of a function pointer. + // However, if by chance libc::dlsym does return UNINIT, there will not + // be undefined behavior. libc::dlsym will just be called each time ptr() + // is called. This would be inefficient, but correct. + // TODO: Replace with core::ptr::invalid_mut(1) when that is stable. + const UNINIT: *mut c_void = 1 as *mut c_void; + // Construct a binding to a C function with a given name. This function is // unsafe because `name` _must_ be null terminated. pub const unsafe fn new(name: &'static str) -> Self { Self { name, - addr: LazyUsize::new(), + addr: AtomicPtr::new(Self::UNINIT), } } - // Return a function pointer if present at runtime. Otherwise, return null. - pub fn ptr(&self) -> Option> { - let addr = self.addr.unsync_init(|| unsafe { - libc::dlsym(libc::RTLD_DEFAULT, self.name.as_ptr() as *const _) as usize - }); - NonNull::new(addr as *mut _) + // Return the address of a function if present at runtime. Otherwise, + // return None. Multiple callers can call ptr() concurrently. It will + // always return _some_ value returned by libc::dlsym. However, the + // dlsym function may be called multiple times. + pub fn ptr(&self) -> Option> { + // Despite having only a single atomic variable (self.addr), we still + // cannot always use Ordering::Relaxed, as we need to make sure a + // successful call to dlsym() is "ordered before" any data read through + // the returned pointer (which occurs when the function is called). + // Our implementation mirrors that of the one in libstd, meaning that + // the use of non-Relaxed operations is probably unnecessary. + match self.addr.load(Ordering::Relaxed) { + Self::UNINIT => { + let symbol = self.name.as_ptr() as *const _; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, symbol) }; + // Synchronizes with the Acquire fence below + self.addr.store(addr, Ordering::Release); + NonNull::new(addr) + } + addr => { + let func = NonNull::new(addr)?; + fence(Ordering::Acquire); + Some(func) + } + } } } diff --git a/vendor/getrandom/src/wasi.rs b/vendor/getrandom/src/wasi.rs index 2d413e020..c5121824a 100644 --- a/vendor/getrandom/src/wasi.rs +++ b/vendor/getrandom/src/wasi.rs @@ -9,15 +9,11 @@ //! Implementation for WASI use crate::Error; use core::num::NonZeroU32; -use wasi::random_get; +use wasi::wasi_snapshot_preview1::random_get; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - unsafe { - random_get(dest.as_mut_ptr(), dest.len()).map_err(|e: wasi::Error| { - // convert wasi's Error into getrandom's NonZeroU32 error - // SAFETY: `wasi::Error` is `NonZeroU16` internally, so `e.raw_error()` - // will never return 0 - NonZeroU32::new_unchecked(e.raw_error() as u32).into() - }) + match unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) } { + 0 => Ok(()), + err => Err(unsafe { NonZeroU32::new_unchecked(err as u32) }.into()), } } diff --git a/vendor/getrandom/src/windows.rs b/vendor/getrandom/src/windows.rs index 643badd07..41dc37a5c 100644 --- a/vendor/getrandom/src/windows.rs +++ b/vendor/getrandom/src/windows.rs @@ -24,6 +24,7 @@ extern "system" { pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { // Prevent overflow of u32 for chunk in dest.chunks_mut(u32::max_value() as usize) { + // BCryptGenRandom was introduced in Windows Vista let ret = unsafe { BCryptGenRandom( ptr::null_mut(), diff --git a/vendor/gimli/.cargo-checksum.json b/vendor/gimli/.cargo-checksum.json index 5b855e30c..759ec93de 100644 --- a/vendor/gimli/.cargo-checksum.json +++ b/vendor/gimli/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"13bb20c4d7f171cdaf835093237311af52dd979091cbe2c46a6f978c9d783721","CONTRIBUTING.md":"5f513ec06013e4f6f097e9c9492da5a47b9f25c94c6ecadfb655a77405fe912c","Cargo.lock":"9961bcba2db19ce16584ca5cb089568de7ffcbc9668cba37fc3dd851b2e58e56","Cargo.toml":"d607f683bfe0d69d932c331701d54bdf429dbe5280b7cd3b1a5478d9dd9cdc79","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"03ac1a78a14682d70da4d485d3fa01d0ad819b65b6aed50359ee72af43158ca9","benches/bench.rs":"e0045b989683794951563aa91b37069b2f6ae55f95e288d23f5c984b46e3a7eb","examples/dwarf-validate.rs":"8a322dc48a04bff33a759030f399ca9972ddb103e63851cbb9b8c9672095f645","examples/dwarfdump.rs":"3ef93684d0b417da7dc89751e2f5d1c297b3574b478848cb79b550d4ecd83222","examples/simple.rs":"684dc9785f4aa0714fcb91a3ae1bb7c8612c9b12969be47fe1327447a2101d1c","examples/simple_line.rs":"ec5fa47c1ab019c6cd9d525223f947533f6d65d6add3131a0c40ac18fc1297db","fixtures/self/README.md":"557cd710240a14fdaa5842b216de57f2ed481151b640af09d6877984b3b2389f","fixtures/self/debug_abbrev":"7c0faa940d9c68d196d03ad55a20e5c746040fa428ff323277fa381deff82bba","fixtures/self/debug_aranges":"8c2aeb2335f61d04ecb7b747070d24f83a6517cbee79dc5c96d97fb6c53d6b6d","fixtures/self/debug_info":"42028a5983006e0703f9ca9515cd27d891ae4af70279fae5011d547f581e2661","fixtures/self/debug_inlined":"89d9516f06ff835621936037f5884fc56712bf304c1dcde52251ddd510fe8710","fixtures/self/debug_line":"b29aebcca3b38bb2bb8aa708cbe74a0dce5a3b0c18916b63d6d17282c017bec7","fixtures/self/debug_loc":"8906ccb9c204f233eb74c1d069dee97a19d18c2051f9147795d7b5364a9266aa","fixtures/self/debug_pubnames":"cf58e237f89c68afba724597fa7e260448636b45f2e69dc6f1bfe34006e27c48","fixtures/self/debug_pubtypes":"d43c1bed71c9d14d1683294cdc1833f069cf131d6e95ee808547919b4f352d81","fixtures/self/debug_ranges":"6d765ac18d33accd89186d077eeb505cbdf97d990c9201d63d9463cd7787ce7a","fixtures/self/debug_str":"9ed904b68eee77b8558b80b3b7ca03e8527f6c64483e9d6d845f40270eb21183","fixtures/self/eh_frame":"6dc3d84351cac42cf73d03452fbb532470dd94d08715154c48417e3f62095f17","fixtures/self/eh_frame_hdr":"afba7a0aa233c9a8c81c986495bd2505164844adb93272d6bc0c9e592e684716","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/arch.rs":"1c4cb3e2a322f3f42fe0b82875c9d0ce060d9af2388990139bdce9a4487c32da","src/common.rs":"392f52a58db6101187ca5525bbeafca9bda2342debd058cabca37350cd9db619","src/constants.rs":"ca3169f7a45ff1b6a504966c5627ad5c99193e2d0ec06dc9edfdf37617198093","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"996d5c79d027f97c010ca487bc4ff5f8265f4b9e63d62b4e4fa291383c259ee9","src/lib.rs":"427d747b0af62894e3c5ea20aecad33e5f458bec0b50fbe584e1e6aa1e5eb4f8","src/read/abbrev.rs":"c49c47ff607435c9d0b702faf366068cd1e95d175be79358b1e21244151eeab6","src/read/addr.rs":"f63f289edf889e87107bb2090fb1c50b48af7015f31b7c39c3d6ea09630a38e9","src/read/aranges.rs":"dee9500e0428bc34fca58b2dda85aef6bf0293785c4077c1a4c144109e9d87c9","src/read/cfi.rs":"e4dacfb576ecbe9248cbea3c3c682b6fd835d3843bca68bb3e18dbda55728643","src/read/dwarf.rs":"a39c24429b437ae3a1cd17bae2f01c973c9ce39f7b5f2b3435982d6860944e0e","src/read/endian_reader.rs":"320983a859c2bb0dd44a3e6fae55ff0a84dba3fa80c2edbc64aa8135c44eddf0","src/read/endian_slice.rs":"ae1c52499728f6a85648f1bf87c02dcf43bebecb5ad4e835a1246938ba4338bf","src/read/index.rs":"e79b8d591b8e2007a37f5ea85a6d71b69d56ca3739a85cf7bf361724c5b829fa","src/read/line.rs":"47ca5ebb8bd19000045954686d3320b838e9404cba917ec60525f11ea0d87095","src/read/lists.rs":"e473ff419feed9756289e245b7879bd89e7f19098a53162fe6773fac496ae5bc","src/read/loclists.rs":"2a5655c53fb2bf5cfe2df373210217edaa06e4d3addf27df0f724100cbfbe43b","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"7ea1d01906db92a31a0915b8d2a84776b2a1b2a6587aac8a4acf5ecc48c019b6","src/read/op.rs":"2de049cdcff6c0a324c5737d3fc93431c729554b3bf38e09777b855d7058b29f","src/read/pubnames.rs":"701c1279aef596ed8eff13f19a5803f9e1070afa20c9bafbf29659d4c294edd4","src/read/pubtypes.rs":"6250112d63120ed283698cb42189b127f624fb453abb1222dfa75fe103ad077e","src/read/reader.rs":"b10ff3e77b54347e96b1f3cff30da104dfdd0c4d7a55b672950788f1f1ae3478","src/read/rnglists.rs":"e7426fa1564cbd7e84871ddd741d6a7f016596633f1ffa097885b6e685fc8da2","src/read/str.rs":"932971a6f6f3453685dbd33ff3c2d31a10820b989a209bdfeca3e8c5012cc4b8","src/read/unit.rs":"305e834d7c14e6855beab411076cb7db2615373fd761396ec253250bb0381a59","src/read/util.rs":"480acb9a1fbae7ce935dd1d1307e6a0ab222e009b63ae7817b4bcdcccb9a9ec4","src/read/value.rs":"9a961a49c43bd05061fce1765bda0da049f26420d1be2ed0584de7d1597ab836","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"5d36c6978d2bda09921f5b71b764a75a58e819551471fb44db23ce5db7c4a8e3","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"df7d2082c71b5e523cd52745700aae3dcfa5800f0b280e831ef5d8eb8035d6a7","src/write/loc.rs":"bb5b750c04f6603e18225db72652ea00239234ba674a8a8627c99d4ab07b47a9","src/write/mod.rs":"d8aa1da854cdee629d470d00d87e00dc6998e4bec1ca951f8d2f277730ab9d69","src/write/op.rs":"fb99e95631e24e46eaddef393281ed4f4c56ebc0713a8cbe1683893f7bdde8c6","src/write/range.rs":"5bac01e372c08e3cc19e1e07e40492d8214cdfa8881737920cb792f4aa2ba80b","src/write/section.rs":"3ce781d5e82ba365ff54fdd36e0ef58c58a2215b09a8861eb0b038efac82b77f","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"213c881736f8c87fcb2f921e379791eaba2915e8d077139965a9c6211001fe44","src/write/writer.rs":"304181287f90445bbfb33349c26b34bd87002d6844fc5686bfc0756fd0a1ecd8","tests/convert_self.rs":"8fba3599ac892a704cbcd5aed53eaef51b040043da04f85f002c597ee7549046","tests/parse_self.rs":"f2da1c7daef7139545c9367c2f26199e8b4623b31d4ec6480ddd851e6980f2dc"},"package":"78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"} \ No newline at end of file +{"files":{"CHANGELOG.md":"789a696803d3f1bed3ff3566cac8e7cf15c4bf9428242d637d0ce7f3a0ad57a3","CONTRIBUTING.md":"5f513ec06013e4f6f097e9c9492da5a47b9f25c94c6ecadfb655a77405fe912c","Cargo.lock":"284bff6b09ef0fd214c34492417778d6d5b9f75dc54557015af01a95696c752a","Cargo.toml":"92dccbeaa61bc8c65da53917fbf32900b3cb2549f90b67b67e1c67672bac205e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"57e36d344dabe1c52a9c81eafb28787c309b86c47437abf8589ef17bf383fc5f","benches/bench.rs":"e0045b989683794951563aa91b37069b2f6ae55f95e288d23f5c984b46e3a7eb","examples/dwarf-validate.rs":"4aac1045e3c08bf00878eeff75c0cfc30c06171c5eab2e71d757505786729687","examples/dwarfdump.rs":"d74323c037689b32825efa9bf69614ee26a444513b266e819ecf486956ee3299","examples/simple.rs":"4c3425e8bd1880d9522f5ed2581fb5ccd452d4be678eebc0e147c48722a7be1d","examples/simple_line.rs":"ac795f859a17650dde466b5b23b8c161b2e3b8eb57e32f5b6718a3072f6bfad0","fixtures/self/README.md":"7cfd76031ec5a4b38cc4eb56ccbfe1bb590fb54c333d037550bdeaaeacfc20cb","fixtures/self/debug_abbrev":"7c0faa940d9c68d196d03ad55a20e5c746040fa428ff323277fa381deff82bba","fixtures/self/debug_aranges":"8c2aeb2335f61d04ecb7b747070d24f83a6517cbee79dc5c96d97fb6c53d6b6d","fixtures/self/debug_info":"42028a5983006e0703f9ca9515cd27d891ae4af70279fae5011d547f581e2661","fixtures/self/debug_inlined":"89d9516f06ff835621936037f5884fc56712bf304c1dcde52251ddd510fe8710","fixtures/self/debug_line":"b29aebcca3b38bb2bb8aa708cbe74a0dce5a3b0c18916b63d6d17282c017bec7","fixtures/self/debug_loc":"8906ccb9c204f233eb74c1d069dee97a19d18c2051f9147795d7b5364a9266aa","fixtures/self/debug_pubnames":"cf58e237f89c68afba724597fa7e260448636b45f2e69dc6f1bfe34006e27c48","fixtures/self/debug_pubtypes":"d43c1bed71c9d14d1683294cdc1833f069cf131d6e95ee808547919b4f352d81","fixtures/self/debug_ranges":"6d765ac18d33accd89186d077eeb505cbdf97d990c9201d63d9463cd7787ce7a","fixtures/self/debug_str":"9ed904b68eee77b8558b80b3b7ca03e8527f6c64483e9d6d845f40270eb21183","fixtures/self/eh_frame":"6dc3d84351cac42cf73d03452fbb532470dd94d08715154c48417e3f62095f17","fixtures/self/eh_frame_hdr":"afba7a0aa233c9a8c81c986495bd2505164844adb93272d6bc0c9e592e684716","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/arch.rs":"1c4cb3e2a322f3f42fe0b82875c9d0ce060d9af2388990139bdce9a4487c32da","src/common.rs":"392f52a58db6101187ca5525bbeafca9bda2342debd058cabca37350cd9db619","src/constants.rs":"358cf7924c79bc72de59d23d1fa02b2047d6c763c8fbd8be263ab8cd3e3ba7ec","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"996d5c79d027f97c010ca487bc4ff5f8265f4b9e63d62b4e4fa291383c259ee9","src/lib.rs":"6863b9a9d1eddf34b4095dfe60318aae56914fbf515ba5601b29024cc963f27c","src/read/abbrev.rs":"a3f550c32f1eb880d82bdb5257d35e10d32cfd039050e8131cbeedac346cc1d9","src/read/addr.rs":"f63f289edf889e87107bb2090fb1c50b48af7015f31b7c39c3d6ea09630a38e9","src/read/aranges.rs":"ba3302f87cffb7ee15f48b0530ebd707f45ad056934223078d25ae2a1b034f1c","src/read/cfi.rs":"b1064ed9b4b87169a148cc86adc7443c5a771dc2d1799129f7883f1ef6adc165","src/read/dwarf.rs":"a39c24429b437ae3a1cd17bae2f01c973c9ce39f7b5f2b3435982d6860944e0e","src/read/endian_reader.rs":"320983a859c2bb0dd44a3e6fae55ff0a84dba3fa80c2edbc64aa8135c44eddf0","src/read/endian_slice.rs":"ae1c52499728f6a85648f1bf87c02dcf43bebecb5ad4e835a1246938ba4338bf","src/read/index.rs":"e79b8d591b8e2007a37f5ea85a6d71b69d56ca3739a85cf7bf361724c5b829fa","src/read/line.rs":"af7a1520777e56632970fc5fe7377fdcd12d078eb88eeb2b0f2cc95b73ff68a7","src/read/lists.rs":"67ca9e1a36a91feb4996d035211de845205212bfda02163685d217818567ff93","src/read/loclists.rs":"1b4ea85c0dd8c6eae492a60cb70810185d56ba579df7986cb8a36385031b10fd","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"3bafc747c31a575bcc92d3e7d5ea5a15f5acc01918a4377cec1dced0f85b5d2b","src/read/op.rs":"e5dce6520dfc90ec74c3b070ca374b89fcf55ff23101471591458175a72c79e6","src/read/pubnames.rs":"ed752ee1a7017e6d3be42d81e4ddaaac960ef08081463a19106c9f041526d4a3","src/read/pubtypes.rs":"5e75b32c0923e827aff0bb2db456797a0e8d38ba46be992558a7990b3196bcf5","src/read/reader.rs":"b10ff3e77b54347e96b1f3cff30da104dfdd0c4d7a55b672950788f1f1ae3478","src/read/rnglists.rs":"af637d283d76514382ee0556463cccab4e6f0ea4d061db9a44a594b5d57d1fd7","src/read/str.rs":"4c2f50014451621fea45969cd313f6840fcd3a99d7a2d081bfa1f8e0e434133a","src/read/unit.rs":"6ed00ba004c329008bf295d9c7d724afe961750f0c7b08430fc213fd5d998003","src/read/util.rs":"0b7d0d2225a98618070dc472ccba49a5411aa8beed5ff6696da079d06156d363","src/read/value.rs":"5a91e03ad3d41f679b264753498434b91948c6b89955e4beb4522498386d9b1d","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"3b04b0ebd82363738199cc673f64e0ceb60506a67c4f18b435a109caa62840f3","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"df7d2082c71b5e523cd52745700aae3dcfa5800f0b280e831ef5d8eb8035d6a7","src/write/loc.rs":"bb5b750c04f6603e18225db72652ea00239234ba674a8a8627c99d4ab07b47a9","src/write/mod.rs":"d8aa1da854cdee629d470d00d87e00dc6998e4bec1ca951f8d2f277730ab9d69","src/write/op.rs":"7b1d49b10c8c92b2d5b259e83119ff7dc95bc552535bb7b1a82ca9556a35c589","src/write/range.rs":"5bac01e372c08e3cc19e1e07e40492d8214cdfa8881737920cb792f4aa2ba80b","src/write/section.rs":"3ce781d5e82ba365ff54fdd36e0ef58c58a2215b09a8861eb0b038efac82b77f","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"213c881736f8c87fcb2f921e379791eaba2915e8d077139965a9c6211001fe44","src/write/writer.rs":"304181287f90445bbfb33349c26b34bd87002d6844fc5686bfc0756fd0a1ecd8","tests/convert_self.rs":"180909b562969e1691b64628ded8654e6e0b10b3357f39917bd8ac288c5826dd","tests/parse_self.rs":"f2da1c7daef7139545c9367c2f26199e8b4623b31d4ec6480ddd851e6980f2dc"},"package":"22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"} \ No newline at end of file diff --git a/vendor/gimli/CHANGELOG.md b/vendor/gimli/CHANGELOG.md index da2ab0fe7..9ca6d70a8 100644 --- a/vendor/gimli/CHANGELOG.md +++ b/vendor/gimli/CHANGELOG.md @@ -2,6 +2,28 @@ -------------------------------------------------------------------------------- +## 0.26.2 + +Released 2022/07/16. + +### Changed + +* Fixed CFI personality encoding when writing. + [#609](https://github.com/gimli-rs/gimli/pull/609) + +* Fixed use of raw pointer for mutation, detected by Miri. + [#614](https://github.com/gimli-rs/gimli/pull/614) + +* Fixed `DW_OP_GNU_implicit_pointer` handling for DWARF version 2. + [#618](https://github.com/gimli-rs/gimli/pull/618) + +### Added + +* Added `read::EhHdrTable::iter`. + [#619](https://github.com/gimli-rs/gimli/pull/619) + +-------------------------------------------------------------------------------- + ## 0.26.1 Released 2021/11/02. diff --git a/vendor/gimli/Cargo.lock b/vendor/gimli/Cargo.lock index d55f428d0..b4a719a0c 100644 --- a/vendor/gimli/Cargo.lock +++ b/vendor/gimli/Cargo.lock @@ -153,14 +153,14 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" dependencies = [ "compiler_builtins", "crossbeam", "fallible-iterator", "getopts", "indexmap", - "memmap", + "memmap2", "num_cpus", "object", "rayon", @@ -216,13 +216,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] -name = "memmap" -version = "0.7.0" +name = "memmap2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" dependencies = [ "libc", - "winapi", ] [[package]] @@ -256,9 +255,9 @@ dependencies = [ [[package]] name = "object" -version = "0.27.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "flate2", "memchr", @@ -357,25 +356,3 @@ name = "wasmparser" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/gimli/Cargo.toml b/vendor/gimli/Cargo.toml index d5f283c80..f36ccd936 100644 --- a/vendor/gimli/Cargo.toml +++ b/vendor/gimli/Cargo.toml @@ -3,25 +3,37 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "gimli" -version = "0.26.1" -exclude = ["/ci/*", "/releases/*", "/.github"] +version = "0.26.2" +exclude = [ + "/releases/*", + "/.github", +] description = "A library for reading and writing the DWARF debugging format." documentation = "https://docs.rs/gimli" readme = "./README.md" -keywords = ["DWARF", "debug", "ELF", "eh_frame"] -categories = ["development-tools::debugging", "development-tools::profiling", "parser-implementations"] -license = "Apache-2.0/MIT" +keywords = [ + "DWARF", + "debug", + "ELF", + "eh_frame", +] +categories = [ + "development-tools::debugging", + "development-tools::profiling", + "parser-implementations", +] +license = "MIT OR Apache-2.0" repository = "https://github.com/gimli-rs/gimli" + [profile.bench] codegen-units = 1 debug = true @@ -40,11 +52,18 @@ required-features = ["read"] [[example]] name = "dwarfdump" -required-features = ["read", "std"] +required-features = [ + "read", + "std", +] [[example]] name = "dwarf-validate" -required-features = ["read", "std"] +required-features = [ + "read", + "std", +] + [dependencies.alloc] version = "1.0.0" optional = true @@ -72,20 +91,21 @@ optional = true version = "1.1.0" optional = true default-features = false + [dev-dependencies.crossbeam] version = "0.8" [dev-dependencies.getopts] version = "0.2" -[dev-dependencies.memmap] -version = "0.7" +[dev-dependencies.memmap2] +version = "0.5.5" [dev-dependencies.num_cpus] version = "1" [dev-dependencies.object] -version = "0.27.1" +version = "0.29.0" features = ["wasm"] [dev-dependencies.rayon] @@ -101,15 +121,26 @@ version = "0.1.3" version = "2" [features] -default = ["read", "write", "std", "fallible-iterator", "endian-reader"] -endian-reader = ["read", "stable_deref_trait"] +default = [ + "read", + "write", + "std", + "fallible-iterator", + "endian-reader", +] +endian-reader = [ + "read", + "stable_deref_trait", +] read = ["read-core"] read-core = [] -rustc-dep-of-std = ["core", "alloc", "compiler_builtins"] -std = ["fallible-iterator/std", "stable_deref_trait/std"] +rustc-dep-of-std = [ + "core", + "alloc", + "compiler_builtins", +] +std = [ + "fallible-iterator/std", + "stable_deref_trait/std", +] write = ["indexmap"] -[badges.coveralls] -repository = "gimli-rs/gimli" - -[badges.travis-ci] -repository = "gimli-rs/gimli" diff --git a/vendor/gimli/README.md b/vendor/gimli/README.md index 56cee2531..19e7bbd0e 100644 --- a/vendor/gimli/README.md +++ b/vendor/gimli/README.md @@ -6,7 +6,7 @@ [![Coverage Status](https://coveralls.io/repos/github/gimli-rs/gimli/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/gimli?branch=master) `gimli` is a blazing fast library for consuming the -[DWARF debugging format](http://dwarfstd.org/). +[DWARF debugging format](https://dwarfstd.org/). * **Zero copy:** everything is just a reference to the original input buffer. No copies of the input data get made. @@ -30,7 +30,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -gimli = "0.26.1" +gimli = "0.26.2" ``` The minimum supported Rust version is 1.42.0. @@ -49,7 +49,7 @@ The minimum supported Rust version is 1.42.0. * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) - * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into + * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into code generation by making debugging information readable. * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the diff --git a/vendor/gimli/examples/dwarf-validate.rs b/vendor/gimli/examples/dwarf-validate.rs index 1eabccc11..54d8f3a1d 100644 --- a/vendor/gimli/examples/dwarf-validate.rs +++ b/vendor/gimli/examples/dwarf-validate.rs @@ -52,7 +52,7 @@ fn main() { continue; } }; - let file = match unsafe { memmap::Mmap::map(&file) } { + let file = match unsafe { memmap2::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { eprintln!("Failed to map file '{}': {}", path.display(), &err); diff --git a/vendor/gimli/examples/dwarfdump.rs b/vendor/gimli/examples/dwarfdump.rs index 64b233305..4b61fd572 100644 --- a/vendor/gimli/examples/dwarfdump.rs +++ b/vendor/gimli/examples/dwarfdump.rs @@ -490,7 +490,7 @@ fn main() { process::exit(1); } }; - let mmap = match unsafe { memmap::Mmap::map(&file) } { + let mmap = match unsafe { memmap2::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { eprintln!("Failed to map file '{}': {}", path, err); @@ -531,7 +531,7 @@ fn main() { continue; } }; - let file = match unsafe { memmap::Mmap::map(&file) } { + let file = match unsafe { memmap2::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { eprintln!("Failed to map file '{}': {}", file_path, err); @@ -786,17 +786,36 @@ fn dump_eh_frame( // TODO: augmentation writeln!(w, " code_align: {}", cie.code_alignment_factor())?; writeln!(w, " data_align: {}", cie.data_alignment_factor())?; - writeln!(w, " ra_register: {:#x}", cie.return_address_register().0)?; + writeln!( + w, + " ra_register: {}", + register_name(cie.return_address_register()) + )?; if let Some(encoding) = cie.lsda_encoding() { - writeln!(w, " lsda_encoding: {:#02x}", encoding.0)?; + writeln!( + w, + " lsda_encoding: {}/{}", + encoding.application(), + encoding.format() + )?; } if let Some((encoding, personality)) = cie.personality_with_encoding() { - write!(w, " personality: {:#02x} ", encoding.0)?; + write!( + w, + " personality: {}/{} ", + encoding.application(), + encoding.format() + )?; dump_pointer(w, personality)?; writeln!(w)?; } if let Some(encoding) = cie.fde_address_encoding() { - writeln!(w, " fde_encoding: {:#02x}", encoding.0)?; + writeln!( + w, + " fde_encoding: {}/{}", + encoding.application(), + encoding.format() + )?; } let instructions = cie.instructions(&eh_frame, &bases); dump_cfi_instructions(w, instructions, true, register_name)?; @@ -1585,21 +1604,21 @@ fn dump_type_signature(w: &mut W, signature: gimli::DebugTypeSignature fn dump_file_index( w: &mut W, - file: u64, + file_index: u64, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { - if file == 0 { + if file_index == 0 && unit.header.version() <= 4 { return Ok(()); } let header = match unit.line_program { Some(ref program) => program.header(), None => return Ok(()), }; - let file = match header.file(file) { - Some(header) => header, + let file = match header.file(file_index) { + Some(file) => file, None => { - writeln!(w, "Unable to get header for file {}", file)?; + writeln!(w, "Unable to get header for file {}", file_index)?; return Ok(()); } }; @@ -1607,7 +1626,7 @@ fn dump_file_index( if let Some(directory) = file.directory(header) { let directory = dwarf.attr_string(unit, directory)?; let directory = directory.to_string_lossy()?; - if !directory.starts_with('/') { + if file.directory_index() != 0 && !directory.starts_with('/') { if let Some(ref comp_dir) = unit.comp_dir { write!(w, "{}/", comp_dir.to_string_lossy()?,)?; } @@ -2238,7 +2257,7 @@ fn dump_line_program( writeln!(w, " [lno,col]")?; } let mut rows = program.rows(); - let mut file_index = 0; + let mut file_index = std::u64::MAX; while let Some((header, row)) = rows.next_row()? { let line = match row.line() { Some(line) => line.get(), diff --git a/vendor/gimli/examples/simple.rs b/vendor/gimli/examples/simple.rs index b73ab7552..7c958d45c 100644 --- a/vendor/gimli/examples/simple.rs +++ b/vendor/gimli/examples/simple.rs @@ -6,7 +6,7 @@ use std::{borrow, env, fs}; fn main() { for path in env::args().skip(1) { let file = fs::File::open(&path).unwrap(); - let mmap = unsafe { memmap::Mmap::map(&file).unwrap() }; + let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() }; let object = object::File::parse(&*mmap).unwrap(); let endian = if object.is_little_endian() { gimli::RunTimeEndian::Little diff --git a/vendor/gimli/examples/simple_line.rs b/vendor/gimli/examples/simple_line.rs index bf1114f90..87b224cda 100644 --- a/vendor/gimli/examples/simple_line.rs +++ b/vendor/gimli/examples/simple_line.rs @@ -6,7 +6,7 @@ use std::{borrow, env, fs, path}; fn main() { for path in env::args().skip(1) { let file = fs::File::open(&path).unwrap(); - let mmap = unsafe { memmap::Mmap::map(&file).unwrap() }; + let mmap = unsafe { memmap2::Mmap::map(&file).unwrap() }; let object = object::File::parse(&*mmap).unwrap(); let endian = if object.is_little_endian() { gimli::RunTimeEndian::Little @@ -68,9 +68,16 @@ fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), let mut path = path::PathBuf::new(); if let Some(file) = row.file(header) { path = comp_dir.clone(); - if let Some(dir) = file.directory(header) { - path.push(dwarf.attr_string(&unit, dir)?.to_string_lossy().as_ref()); + + // The directory index 0 is defined to correspond to the compilation unit directory. + if file.directory_index() != 0 { + if let Some(dir) = file.directory(header) { + path.push( + dwarf.attr_string(&unit, dir)?.to_string_lossy().as_ref(), + ); + } } + path.push( dwarf .attr_string(&unit, file.path_name())? diff --git a/vendor/gimli/fixtures/self/README.md b/vendor/gimli/fixtures/self/README.md index 3847c3852..91053d9b4 100644 --- a/vendor/gimli/fixtures/self/README.md +++ b/vendor/gimli/fixtures/self/README.md @@ -7,7 +7,7 @@ about cross platform and cross object file format issues when running examples. # Updating and adding new sections -## OSX +## macOS Use `otool` to list the sections of a binary: diff --git a/vendor/gimli/src/constants.rs b/vendor/gimli/src/constants.rs index c8d6a1662..c617f4e2e 100644 --- a/vendor/gimli/src/constants.rs +++ b/vendor/gimli/src/constants.rs @@ -1315,7 +1315,7 @@ DwEhPe(u8) { // pointer result itself. // // This isn't defined in the DWARF or the `.eh_frame` standards, but is -// generated by both GNU/Linux and OSX tooling. +// generated by both GNU/Linux and macOS tooling. DW_EH_PE_indirect = 0x80, // These constants apply to both the lower and upper bits. diff --git a/vendor/gimli/src/lib.rs b/vendor/gimli/src/lib.rs index 7ac1820e3..ed1af9cbd 100644 --- a/vendor/gimli/src/lib.rs +++ b/vendor/gimli/src/lib.rs @@ -1,5 +1,5 @@ //! `gimli` is a library for reading and writing the -//! [DWARF debugging format](http://dwarfstd.org/). +//! [DWARF debugging format](https://dwarfstd.org/). //! //! See the [read](./read/index.html) and [write](./write/index.html) modules //! for examples and API documentation. diff --git a/vendor/gimli/src/read/abbrev.rs b/vendor/gimli/src/read/abbrev.rs index 5f0e7bed7..1a24835a7 100644 --- a/vendor/gimli/src/read/abbrev.rs +++ b/vendor/gimli/src/read/abbrev.rs @@ -29,7 +29,7 @@ where /// /// It is the caller's responsibility to read the `.debug_abbrev` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugAbbrev, LittleEndian}; diff --git a/vendor/gimli/src/read/aranges.rs b/vendor/gimli/src/read/aranges.rs index c2d22850c..83159b69b 100644 --- a/vendor/gimli/src/read/aranges.rs +++ b/vendor/gimli/src/read/aranges.rs @@ -18,7 +18,7 @@ where /// /// It is the caller's responsibility to read the `.debug_aranges` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugAranges, LittleEndian}; diff --git a/vendor/gimli/src/read/cfi.rs b/vendor/gimli/src/read/cfi.rs index b6a81f3f4..2e5167349 100644 --- a/vendor/gimli/src/read/cfi.rs +++ b/vendor/gimli/src/read/cfi.rs @@ -63,7 +63,7 @@ where /// /// It is the caller's responsibility to read the section and present it as /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O - /// loader on OSX, etc. + /// loader on macOS, etc. /// /// ``` /// use gimli::{DebugFrame, NativeEndian}; @@ -218,6 +218,81 @@ impl ParsedEhFrameHdr { } } +/// An iterator for `.eh_frame_hdr` section's binary search table. +/// +/// Each table entry consists of a tuple containing an `initial_location` and `address`. +/// The `initial location` represents the first address that the targeted FDE +/// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. +/// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. +#[derive(Debug)] +pub struct EhHdrTableIter<'a, 'bases, R: Reader> { + hdr: &'a ParsedEhFrameHdr, + table: R, + bases: &'bases BaseAddresses, + remain: u64, +} + +impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { + /// Yield the next entry in the `EhHdrTableIter`. + pub fn next(&mut self) -> Result> { + if self.remain == 0 { + return Ok(None); + } + + let parameters = PointerEncodingParameters { + bases: &self.bases.eh_frame_hdr, + func_base: None, + address_size: self.hdr.address_size, + section: &self.hdr.section, + }; + + self.remain -= 1; + let from = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; + let to = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; + Ok(Some((from, to))) + } + /// Yield the nth entry in the `EhHdrTableIter` + pub fn nth(&mut self, n: usize) -> Result> { + use core::convert::TryFrom; + let size = match self.hdr.table_enc.format() { + constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { + return Err(Error::VariableLengthSearchTable); + } + constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, + constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, + constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, + _ => return Err(Error::UnknownPointerEncoding), + }; + + let row_size = size * 2; + let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?; + self.remain = self.remain.saturating_sub(n); + self.table.skip(R::Offset::from_u64(n * row_size)?)?; + self.next() + } +} + +#[cfg(feature = "fallible-iterator")] +impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> { + type Item = (Pointer, Pointer); + type Error = Error; + fn next(&mut self) -> Result> { + EhHdrTableIter::next(self) + } + + fn size_hint(&self) -> (usize, Option) { + use core::convert::TryInto; + ( + self.remain.try_into().unwrap_or(0), + self.remain.try_into().ok(), + ) + } + + fn nth(&mut self, n: usize) -> Result> { + EhHdrTableIter::nth(self, n) + } +} + /// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section. #[derive(Debug, Clone)] pub struct EhHdrTable<'a, R: Reader> { @@ -225,6 +300,20 @@ pub struct EhHdrTable<'a, R: Reader> { } impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { + /// Return an iterator that can walk the `.eh_frame_hdr` table. + /// + /// Each table entry consists of a tuple containing an `initial_location` and `address`. + /// The `initial location` represents the first address that the targeted FDE + /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. + /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. + pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> { + EhHdrTableIter { + hdr: self.hdr, + bases, + remain: self.hdr.fde_count, + table: self.hdr.table.clone(), + } + } /// *Probably* returns a pointer to the FDE for the given address. /// /// This performs a binary search, so if there is no FDE for the given address, @@ -423,19 +512,19 @@ where Endian: Endianity, { /// Construct a new `EhFrame` instance from the data in the - /// `.debug_frame` section. + /// `.eh_frame` section. /// /// It is the caller's responsibility to read the section and present it as /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O - /// loader on OSX, etc. + /// loader on macOS, etc. /// /// ``` /// use gimli::{EhFrame, EndianSlice, NativeEndian}; /// - /// // Use with `.debug_frame` + /// // Use with `.eh_frame` /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_frame_section_somehow = || &buf; - /// let debug_frame = EhFrame::new(read_debug_frame_section_somehow(), NativeEndian); + /// # let read_eh_frame_section_somehow = || &buf; + /// let eh_frame = EhFrame::new(read_eh_frame_section_somehow(), NativeEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) @@ -6211,6 +6300,39 @@ mod tests { let table = table.unwrap(); let bases = Default::default(); + let mut iter = table.iter(&bases); + assert_eq!( + iter.next(), + Ok(Some(( + Pointer::Direct(10), + Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64) + ))) + ); + assert_eq!( + iter.next(), + Ok(Some(( + Pointer::Direct(20), + Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64) + ))) + ); + assert_eq!(iter.next(), Ok(None)); + + assert_eq!( + table.iter(&bases).nth(0), + Ok(Some(( + Pointer::Direct(10), + Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64) + ))) + ); + + assert_eq!( + table.iter(&bases).nth(1), + Ok(Some(( + Pointer::Direct(20), + Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64) + ))) + ); + assert_eq!(table.iter(&bases).nth(2), Ok(None)); let f = |_: &_, _: &_, o: EhFrameOffset| { assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); diff --git a/vendor/gimli/src/read/line.rs b/vendor/gimli/src/read/line.rs index 096ddf07b..0e7380bb9 100644 --- a/vendor/gimli/src/read/line.rs +++ b/vendor/gimli/src/read/line.rs @@ -27,7 +27,7 @@ where /// /// It is the caller's responsibility to read the `.debug_line` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugLine, LittleEndian}; diff --git a/vendor/gimli/src/read/lists.rs b/vendor/gimli/src/read/lists.rs index b63c5c126..898a757d3 100644 --- a/vendor/gimli/src/read/lists.rs +++ b/vendor/gimli/src/read/lists.rs @@ -4,6 +4,7 @@ use crate::read::{Error, Reader, Result}; #[derive(Debug, Clone, Copy)] pub(crate) struct ListsHeader { encoding: Encoding, + #[allow(dead_code)] offset_entry_count: u32, } diff --git a/vendor/gimli/src/read/loclists.rs b/vendor/gimli/src/read/loclists.rs index 3c4da127d..3902c181b 100644 --- a/vendor/gimli/src/read/loclists.rs +++ b/vendor/gimli/src/read/loclists.rs @@ -24,7 +24,7 @@ where /// /// It is the caller's responsibility to read the `.debug_loc` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugLoc, LittleEndian}; @@ -70,7 +70,7 @@ where /// /// It is the caller's responsibility to read the `.debug_loclists` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugLocLists, LittleEndian}; diff --git a/vendor/gimli/src/read/mod.rs b/vendor/gimli/src/read/mod.rs index 7291f3b96..3110957c2 100644 --- a/vendor/gimli/src/read/mod.rs +++ b/vendor/gimli/src/read/mod.rs @@ -48,7 +48,7 @@ //! //! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) //! -//! * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into +//! * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into //! code generation by making debugging information readable //! //! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the diff --git a/vendor/gimli/src/read/op.rs b/vendor/gimli/src/read/op.rs index 2ca6247bc..88ea20297 100644 --- a/vendor/gimli/src/read/op.rs +++ b/vendor/gimli/src/read/op.rs @@ -707,7 +707,13 @@ where } constants::DW_OP_stack_value => Ok(Operation::StackValue), constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => { - let value = bytes.read_offset(encoding.format)?; + let value = if encoding.version == 2 { + bytes + .read_address(encoding.address_size) + .and_then(Offset::from_u64)? + } else { + bytes.read_offset(encoding.format)? + }; let byte_offset = bytes.read_sleb128()?; Ok(Operation::ImplicitPointer { value: DebugInfoOffset(value), @@ -2738,6 +2744,19 @@ mod tests { }, encoding8(), ); + + check_op_parse( + |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), + &Operation::ImplicitPointer { + value: DebugInfoOffset(0x1234_5678), + byte_offset: 0x123, + }, + Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }, + ) } } diff --git a/vendor/gimli/src/read/pubnames.rs b/vendor/gimli/src/read/pubnames.rs index f05861f70..e8b7e5528 100644 --- a/vendor/gimli/src/read/pubnames.rs +++ b/vendor/gimli/src/read/pubnames.rs @@ -58,7 +58,7 @@ where /// /// It is the caller's responsibility to read the `.debug_pubnames` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugPubNames, LittleEndian}; diff --git a/vendor/gimli/src/read/pubtypes.rs b/vendor/gimli/src/read/pubtypes.rs index 0226e84d4..6723b4222 100644 --- a/vendor/gimli/src/read/pubtypes.rs +++ b/vendor/gimli/src/read/pubtypes.rs @@ -58,7 +58,7 @@ where /// /// It is the caller's responsibility to read the `.debug_pubtypes` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugPubTypes, LittleEndian}; diff --git a/vendor/gimli/src/read/rnglists.rs b/vendor/gimli/src/read/rnglists.rs index dd68083ac..d8d49042f 100644 --- a/vendor/gimli/src/read/rnglists.rs +++ b/vendor/gimli/src/read/rnglists.rs @@ -24,7 +24,7 @@ where /// /// It is the caller's responsibility to read the `.debug_ranges` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugRanges, LittleEndian}; @@ -70,7 +70,7 @@ where /// /// It is the caller's responsibility to read the `.debug_rnglists` /// section and present it as a `&[u8]` slice. That means using some ELF - /// loader on Linux, a Mach-O loader on OSX, etc. + /// loader on Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugRngLists, LittleEndian}; diff --git a/vendor/gimli/src/read/str.rs b/vendor/gimli/src/read/str.rs index dce8016af..c6b87d8f9 100644 --- a/vendor/gimli/src/read/str.rs +++ b/vendor/gimli/src/read/str.rs @@ -22,7 +22,7 @@ where /// /// It is the caller's responsibility to read the `.debug_str` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugStr, LittleEndian}; @@ -214,7 +214,7 @@ where /// /// It is the caller's responsibility to read the `.debug_line_str` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugLineStr, LittleEndian}; diff --git a/vendor/gimli/src/read/unit.rs b/vendor/gimli/src/read/unit.rs index 4766b2e84..670e55efd 100644 --- a/vendor/gimli/src/read/unit.rs +++ b/vendor/gimli/src/read/unit.rs @@ -93,7 +93,7 @@ where /// /// It is the caller's responsibility to read the `.debug_info` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugInfo, LittleEndian}; @@ -3086,7 +3086,7 @@ where /// /// It is the caller's responsibility to read the `.debug_types` section and /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. + /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugTypes, LittleEndian}; diff --git a/vendor/gimli/src/read/util.rs b/vendor/gimli/src/read/util.rs index dd2af8181..16eafdde4 100644 --- a/vendor/gimli/src/read/util.rs +++ b/vendor/gimli/src/read/util.rs @@ -180,7 +180,7 @@ impl ArrayVec> { let slice = Box::leak(storage); debug_assert!(len <= slice.len()); // SAFETY: valid elements. - unsafe { Vec::from_raw_parts(slice.as_ptr() as _, len, slice.len()) } + unsafe { Vec::from_raw_parts(slice.as_mut_ptr() as *mut T, len, slice.len()) } } } diff --git a/vendor/gimli/src/read/value.rs b/vendor/gimli/src/read/value.rs index fc8c355a9..6f43ebb26 100644 --- a/vendor/gimli/src/read/value.rs +++ b/vendor/gimli/src/read/value.rs @@ -1,7 +1,5 @@ //! Definitions for values used in DWARF expressions. -use core::mem; - use crate::constants; #[cfg(feature = "read")] use crate::read::{AttributeValue, DebuggingInformationEntry}; diff --git a/vendor/gimli/src/write/cfi.rs b/vendor/gimli/src/write/cfi.rs index c58eb1b1d..718cb69ad 100644 --- a/vendor/gimli/src/write/cfi.rs +++ b/vendor/gimli/src/write/cfi.rs @@ -239,7 +239,7 @@ impl CommonInformationEntry { } if let Some((eh_pe, address)) = self.personality { w.write_u8(eh_pe.0)?; - w.write_eh_pointer(address, constants::DW_EH_PE_absptr, encoding.address_size)?; + w.write_eh_pointer(address, eh_pe, encoding.address_size)?; } if self.fde_address_encoding != constants::DW_EH_PE_absptr { w.write_u8(self.fde_address_encoding.0)?; @@ -888,6 +888,19 @@ mod tests { fde4.lsda = Some(Address::Constant(0x4400)); frames.add_fde(cie2_id, fde4.clone()); + let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); + cie3.fde_address_encoding = constants::DW_EH_PE_pcrel; + cie3.lsda_encoding = Some(constants::DW_EH_PE_pcrel); + cie3.personality = Some((constants::DW_EH_PE_pcrel, Address::Constant(0x1235))); + cie3.signal_trampoline = true; + let cie3_id = frames.add_cie(cie3.clone()); + assert_ne!(cie2_id, cie3_id); + assert_eq!(cie3_id, frames.add_cie(cie3.clone())); + + let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50); + fde5.lsda = Some(Address::Constant(0x5500)); + frames.add_fde(cie3_id, fde5.clone()); + // Test writing `.debug_frame`. let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); frames.write_debug_frame(&mut debug_frame).unwrap(); diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs index d1cacb356..c70eec2dd 100644 --- a/vendor/gimli/src/write/op.rs +++ b/vendor/gimli/src/write/op.rs @@ -778,7 +778,11 @@ impl Operation { } else { w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?; } - let size = encoding.format.word_size(); + let size = if encoding.version == 2 { + encoding.address_size + } else { + encoding.format.word_size() + }; match entry { Reference::Symbol(symbol) => { w.write_reference(symbol, size)?; diff --git a/vendor/gimli/tests/convert_self.rs b/vendor/gimli/tests/convert_self.rs index ec8b592d3..7c069ebd6 100644 --- a/vendor/gimli/tests/convert_self.rs +++ b/vendor/gimli/tests/convert_self.rs @@ -146,7 +146,7 @@ fn test_convert_eh_frame() { .write_eh_frame(&mut write_eh_frame) .expect("Should write eh_frame information"); let eh_frame = write_eh_frame.slice(); - assert_eq!(eh_frame.len(), 147152); + assert_eq!(eh_frame.len(), 147144); // Convert new section let mut eh_frame = read::EhFrame::new(&eh_frame, LittleEndian); diff --git a/vendor/handlebars/.cargo-checksum.json b/vendor/handlebars/.cargo-checksum.json index d41808a41..b1031c230 100644 --- a/vendor/handlebars/.cargo-checksum.json +++ b/vendor/handlebars/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"ab776bc63c83489640577a611f7df181de9a3191bf6e5fb449012fd5f6b5e770","Cargo.lock":"fb81e47543e26596ba74d5c165e26f70ec1532911dd638dc6bee65e572b09182","Cargo.toml":"5c6beb2539b6d5e038a5beeead3ed4c044b9be7fdcd4fab60b5a16ce31121bdf","LICENSE":"63b308fad3db82dc12067a8d7ff4b672fae97d12d0b4b3bb59179e27d640b3a4","README.md":"e9dfd89edf514c3613b5b2f47c05f2ba48bf1c9afee8eca1ba395887c8a85c9d","benches/bench.rs":"276ac8c581db35dbdc00e9e4cc1e2e1940fe95522a8f5a19ab088a2c68da61ed","build-wasm.sh":"9f7226d7d0768fe0fba97f698642a4c13a600468ba7d57abcfad9285efd9f4ce","examples/decorator.rs":"010762d337c64a8ade120c66ccb97ac176653d2fc1265c6f77c35d2a7693176f","examples/decorator/template.hbs":"76fd24f08b28b469529f4727321c7cc940198abb5c1aa24d7a6dd2ab42bdda66","examples/dev_mode.rs":"8e28b0f354e14006481faba76f32401a18476472b2e4c9faeea54f222980a9ba","examples/dev_mode/template.hbs":"4a5e1b81565572e26986d890e4a431953b81893a99ce07cef303e366dd84243c","examples/error.rs":"85219ee57a7bc739185862d04c7eff203743ddf730b940f92492894e3ebb5746","examples/error/error.hbs":"4e8fac806d444a5bc41436fe0a51b4d7850c7645f8996db7a99a821c88622eef","examples/error/template.hbs":"48313b522ddb0dd4285874b96d1b705b841dc141514f440790e904a262955951","examples/partials.rs":"e102f0bdacb80a08ac9ae3c92c415991095a1a2142d55420457706823a67fba0","examples/partials/base0.hbs":"6674275ef68faaeab8a4128da0983c9d732d7552f1791c2e3563fa8c5c66fb5a","examples/partials/base1.hbs":"97b1089705f5a21a6f344190e26133d920d56d4a7fdc1fa2fb7359a720bfe182","examples/partials/template2.hbs":"6f83bc48b774a3b83f9ce5a54bf014fb03514720f9e32834dc68000d06a17618","examples/quick.rs":"96df03fc1742504afae34c6da9da05206adc41f771406da2825b41725329cb2d","examples/render.rs":"eadc1aff65d96c7f95c948fbccfb79981276075f83e19a22214fe0772ef17496","examples/render/template.hbs":"2512ef3362379633790985fe2c40e7efab3ad0f431b7cbec5b7cc644dbbef8f5","examples/render_cli/simple.hbs":"a2e0df51e7c1a25c4e9e1bbe0f4911c7c86200d358fc6c9195b61e89adddc970","examples/render_file.rs":"f5b8e788ac6a71a170c5b315120e8779896df8d9b290fb3d785f51307f5d3c45","examples/render_file/template.hbs":"8ec8d0b61a996391ad7f8b6a914f84d0ac06c62e6d7c9c5fa054ca5e2c64a52e","examples/script.rs":"df869a15d6cd8c478f74582018c54e20545b9451e84cdec2f8bb71c31a618da0","examples/script/goals.rhai":"d756fd7d39f11fae148a6e11d23160da0cdac91c29f716dcb854c07a7db09c80","examples/script/template.hbs":"1f39785157a112bc5c4e94db1361c45a73b024bc8bd0fea0a9d5da8102afb310","profile.sh":"b8e80c59bc12fca93daa67c09001c1c045e594e532831cc957c9ac313f8b2390","release.toml":"968ff7e0a0f8b99d0b91a06cb007fcee55427ccbd05012b46202829336287151","rustfmt.toml":"8e99dabd6aadb112f9f9ed8709e7388b57bf43d19cd08342c093c870534a3f97","src/block.rs":"da38a572a95c3858685e4af82a7e1920c6b3311acf8c118c53c8531b091de391","src/cli.rs":"63aed9a8fb2135ee03bd2b49330be20d2018fe3c36265c14dbdc0da9b73cb6d0","src/context.rs":"5007324a0655daa994e1b64f0eed160e67e4a4d8fb02d21eca4c549d5dcea7c2","src/decorators/inline.rs":"73b8ba6ed98dbf8b3bca228796f47c9139d49f1a1c8d5b4603cc6354098b56c2","src/decorators/mod.rs":"322d4d692331a1e3a2806780cbe1e7a3a82b343486f1182d2e8a017a8bf11085","src/error.rs":"7da2635fdb0005437d8c4a7cb889336d0039665d7627544f600d473f5b90eab8","src/grammar.pest":"aed7ff83953551d48e4e94edc25d51f7e418ec79b62df1ca8f7e728444430d0b","src/grammar.rs":"848d1b56bc1d887e8c42836c37d41b2a634ec6eb9e3880be7dde31d84a38460d","src/helpers/block_util.rs":"11a295215f9c0d14b89f97161468425405386214f050bad07683669a162f9aa1","src/helpers/helper_each.rs":"75b536114f954287936e9f02a54b0c182144e2e6a4ad0970e66cc644cc8f3a0f","src/helpers/helper_extras.rs":"0575a1518eba51cafe91ec2b09666e1c987c9a9bc98cb00193d1e0d203a8b681","src/helpers/helper_if.rs":"37c81b7000948f601398b7163b37397020d191642021077bd7eb15c181632d32","src/helpers/helper_log.rs":"272f7c1f873b97974cce156c04281f2bd8c44ccc885b4c59dd2b43e8d7cc6ef6","src/helpers/helper_lookup.rs":"a9f000e36d0e9339930b3d94dabd4f123cdbdaa85e8d77d15e4a772a99ffe9d4","src/helpers/helper_raw.rs":"6b0b5b3774a1d5c3ebf30b1e0b8cac825f6ffb8a18cb9e08bd40786258e4b597","src/helpers/helper_with.rs":"9964ec02b56ad8fb6f3aa9abb535c0d3f6f2cf3eaeba59a5afd8687ea6df2209","src/helpers/mod.rs":"31eefbd1f302b852e43a3aa8432ce4faad04db37eba7fc1bfa8cf9c25967b899","src/helpers/scripting.rs":"6b9e7e08bdbf3e2716bb82b69e0f10efd4de1174842742215aba18fb2cc507e2","src/json/mod.rs":"ef2fc8fe98e9761e2e2a4b2d2293bb29cdb689db2f44f939fc61c48c6b52f0a7","src/json/path.rs":"818bc5f002839a529ffe5d5f8eddd815ac3808a5f9ce3bac79f1f71f5702599b","src/json/value.rs":"390ea4fa8b5131a3d00ff1c80d06359220f16d851a5e836192026ea32acbb02e","src/lib.rs":"ecbb4099b2c0cc77e746083181a8ed32b7f76671aa8e54d079eb4196b24d167c","src/local_vars.rs":"91d3a16bbfabe2eccecaa9a0dd866ebe88d70ce438d2f18581d1b7d231ba0644","src/macros.rs":"86eed922319644176e8464023455b78440b8e5d0d9b13a0ce61b2edf0f10984e","src/output.rs":"10c28874f78cddba70b24eb984a849c7750b207ac605f2aa46f2abe02846b3a2","src/partial.rs":"ddcd49436b6c653b3e5db44a997c5cd9006755dd1e6c07aa5996fa495aecd382","src/registry.rs":"56d613a72ca9e4ad15953cf5b74bf6df912e81f8f008780bebe93375fb1569ed","src/render.rs":"cec805cd1396bc87f1c2bcd9d45b8c6236a65cb99c6d45f14199fab99b94d38d","src/sources.rs":"46989eb76f36edff9dcb5d27488e8bd9c7ff1749f368a70e855f4808c58d7bcf","src/support.rs":"b3d1d99440182548ff9bfcffbd9a7e08507f740ed68382f9c74ab0a92a79eab7","src/template.rs":"61625e52f43c9df92fce25f626db6c61b31a42310c06a8158b13b9f960339e12","src/util.rs":"2ebc845de5ca47455442a1b6bd664565a52e29928e82c526fbfe56ed5196410f","tests/block_context.rs":"4dce11312d2b6c0c5c2f3104516e5567e5a370611e08f4055fa3653293580385","tests/data_helper.rs":"a7f9d1d42d5415ba1dba459840067acc1294f6f6057d9a5a13d9f7e19469e850","tests/escape.rs":"a4bd25c4268a306dc09dc17806f86895c4932753a585219902f0dd85c7e65cba","tests/helper_function_lifetime.rs":"635cbd0b44742539bdf36e803a19c6a1a698399f8b765415d53f28df1acfbc2b","tests/helper_macro.rs":"4660cfb782c03e70f536bedbb2ed5afed5e8fe841d77c1812e4b2ef55d81a6a6","tests/helper_with_space.rs":"c64952ea031f964e558cb323df1bf731bb7c0bf7b226142cea61afa2fd4efbfd","tests/root_var.rs":"fda5b30bac1e692fb010f9f98e052d5a525420fece9dcc3821a4e5aeee3a8841","tests/subexpression.rs":"b36ab31adf45272ca984c0c5ed9497820ca072a8805444d69bd089b766786bb5","tests/template_names.rs":"4bbe6b48c974ae7ea1e61806794d846e2f0e8505e1568c5305fa2364dceef68a","wasm/LICENSE":"63b308fad3db82dc12067a8d7ff4b672fae97d12d0b4b3bb59179e27d640b3a4","wasm/README.md":"d67bad452550d34e9317fb8f4884b8bc07939fbb0dfdcf1be6bfce52a6851fa6","wasm/wapm.toml":"bdb286ccaa18c5c8aa0d2db25755aba9b0e3e83a59fc4d2334c1854933000ea1"},"package":"72a0ffab8c36d0436114310c7e10b59b3307e650ddfabf6d006028e29a70c6e6"} \ No newline at end of file +{"files":{"CHANGELOG.md":"1c33d57ecdf48bcc7011c1e7306d05359a3fca61f3c48324e5cb5b378d406ef6","Cargo.lock":"81ba21eaf5647124881eacf240b9c34ae15c4f3b56072d7ff3ec665f269c3843","Cargo.toml":"afbdf3fe79ae8e5a434f6cb126f3441e8750a499f2b159226cd86e48e4d5424e","LICENSE":"63b308fad3db82dc12067a8d7ff4b672fae97d12d0b4b3bb59179e27d640b3a4","README.md":"ae8924a77607ab2439ef2cb87a93c49b51a4da228ea144bc847ec6d2a4acffba","benches/bench.rs":"276ac8c581db35dbdc00e9e4cc1e2e1940fe95522a8f5a19ab088a2c68da61ed","build-wasm.sh":"9f7226d7d0768fe0fba97f698642a4c13a600468ba7d57abcfad9285efd9f4ce","examples/decorator.rs":"010762d337c64a8ade120c66ccb97ac176653d2fc1265c6f77c35d2a7693176f","examples/decorator/template.hbs":"76fd24f08b28b469529f4727321c7cc940198abb5c1aa24d7a6dd2ab42bdda66","examples/dev_mode.rs":"7c8cebbc56da3e834688719f5c10df1c372c059259e40df8534c79a0dda01aab","examples/dev_mode/template.hbs":"4a5e1b81565572e26986d890e4a431953b81893a99ce07cef303e366dd84243c","examples/error.rs":"6f3d4dc945628778d3ef63dccdc7abbf367e214a5ff62a5dcbeb11d8f34317d7","examples/error/error.hbs":"4e8fac806d444a5bc41436fe0a51b4d7850c7645f8996db7a99a821c88622eef","examples/error/template.hbs":"48313b522ddb0dd4285874b96d1b705b841dc141514f440790e904a262955951","examples/helper_macro.rs":"ca0c7b7a45e8f3f8c7fe25d59a5bb3189b067189dab642bfb02dda416f20774d","examples/partials.rs":"0b3ee03668338b9900705b1162ac1f602255d4b691d1827cb603efff318d3166","examples/partials/base0.hbs":"6674275ef68faaeab8a4128da0983c9d732d7552f1791c2e3563fa8c5c66fb5a","examples/partials/base1.hbs":"97b1089705f5a21a6f344190e26133d920d56d4a7fdc1fa2fb7359a720bfe182","examples/partials/template2.hbs":"6f83bc48b774a3b83f9ce5a54bf014fb03514720f9e32834dc68000d06a17618","examples/quick.rs":"96df03fc1742504afae34c6da9da05206adc41f771406da2825b41725329cb2d","examples/render.rs":"eadc1aff65d96c7f95c948fbccfb79981276075f83e19a22214fe0772ef17496","examples/render/template.hbs":"2512ef3362379633790985fe2c40e7efab3ad0f431b7cbec5b7cc644dbbef8f5","examples/render_cli/simple.hbs":"a2e0df51e7c1a25c4e9e1bbe0f4911c7c86200d358fc6c9195b61e89adddc970","examples/render_file.rs":"f5b8e788ac6a71a170c5b315120e8779896df8d9b290fb3d785f51307f5d3c45","examples/render_file/template.hbs":"8ec8d0b61a996391ad7f8b6a914f84d0ac06c62e6d7c9c5fa054ca5e2c64a52e","examples/script.rs":"5e16423dc4c8ae0e383f0d8b9e1a652850fa5e48dbc57cca3757661c3e0476bb","examples/script/goals.rhai":"d756fd7d39f11fae148a6e11d23160da0cdac91c29f716dcb854c07a7db09c80","examples/script/template.hbs":"1f39785157a112bc5c4e94db1361c45a73b024bc8bd0fea0a9d5da8102afb310","profile.sh":"b8e80c59bc12fca93daa67c09001c1c045e594e532831cc957c9ac313f8b2390","release.toml":"d1c1f8e31be9268666c07a2c3f244e73c3db7474a2a64218fac71f7ad1f20b5d","rustfmt.toml":"8e99dabd6aadb112f9f9ed8709e7388b57bf43d19cd08342c093c870534a3f97","src/block.rs":"da38a572a95c3858685e4af82a7e1920c6b3311acf8c118c53c8531b091de391","src/cli.rs":"63aed9a8fb2135ee03bd2b49330be20d2018fe3c36265c14dbdc0da9b73cb6d0","src/context.rs":"6d594b5c93cdc1e8ee08c3858f50dddc312eaa20b9ea3f4c14906bc6ebee318f","src/decorators/inline.rs":"73b8ba6ed98dbf8b3bca228796f47c9139d49f1a1c8d5b4603cc6354098b56c2","src/decorators/mod.rs":"a9189648fd11609fc6681d6df4af0deb1a1958e12c447485a0455d7e67f70fa3","src/error.rs":"a101458e111478fd6c3749910ca7af8afa973d51eb9a4bd13569e66d0aa8ae8f","src/grammar.pest":"a6754e1b61ba282f325af30f907e9e175ad21f0bec322d42e6f975a6f3bf2c7e","src/grammar.rs":"d572c6507f673c1e5c7c018f485672e6c10671d6749d0d9182f26d62e2e1537e","src/helpers/block_util.rs":"11a295215f9c0d14b89f97161468425405386214f050bad07683669a162f9aa1","src/helpers/helper_each.rs":"827de9ba0224cdd361ce52f02a9f301e879d738d6837672798517b83db68b331","src/helpers/helper_extras.rs":"0575a1518eba51cafe91ec2b09666e1c987c9a9bc98cb00193d1e0d203a8b681","src/helpers/helper_if.rs":"2fe6cc5f3b44a42611d02137e5a11466850d44b6a41a803e7a9268f3a545e487","src/helpers/helper_log.rs":"272f7c1f873b97974cce156c04281f2bd8c44ccc885b4c59dd2b43e8d7cc6ef6","src/helpers/helper_lookup.rs":"34e57dbe6a4c65afa8978d32db1b9adfb783990ec951b4833a9986a86cb38ff1","src/helpers/helper_raw.rs":"6b0b5b3774a1d5c3ebf30b1e0b8cac825f6ffb8a18cb9e08bd40786258e4b597","src/helpers/helper_with.rs":"554373544f1aff16799cde954e37a945e26b452414436f612e12b538ec8e1893","src/helpers/mod.rs":"f8c24abb40739935225acdfad97f4bc808eb1fec77d09fda1ff5779b632b7650","src/helpers/scripting.rs":"3716d77e6e11993741885a15dcddaedc11e076f0b5e9a0b844416d3fbb0a834c","src/json/mod.rs":"ef2fc8fe98e9761e2e2a4b2d2293bb29cdb689db2f44f939fc61c48c6b52f0a7","src/json/path.rs":"49b821765da4aa305e51478527898ad4038c3952c7f07c639e8b71a59732e34a","src/json/value.rs":"390ea4fa8b5131a3d00ff1c80d06359220f16d851a5e836192026ea32acbb02e","src/lib.rs":"9374528d680b4cefdfcef945529a5f9c6b03b22ba09503135cc18914ff621d56","src/local_vars.rs":"91d3a16bbfabe2eccecaa9a0dd866ebe88d70ce438d2f18581d1b7d231ba0644","src/macros.rs":"0e2d174bb155da5df279ba15ef65b92519ca890949acc8231c72196bc8364a7c","src/output.rs":"f85acedeb124a1d344c5f73b309bd32d925de5dbed701b5fdebcadbd42f3c7ad","src/partial.rs":"6362967d77d29eea5ba7000ec741774288f08afe7c685e9d28b801b603599401","src/registry.rs":"388ebf2e28734963cd04f6622109e009ab22f7377236f6042aa5441875b22cef","src/render.rs":"17594a82a37295d4887945f18dc12eebe261094078e699b53ff6b7e193fcf986","src/sources.rs":"46989eb76f36edff9dcb5d27488e8bd9c7ff1749f368a70e855f4808c58d7bcf","src/support.rs":"f9328a0674984fcc3c6e93e8a43ec63bf9b502176283f60a2d6ceb15ca34840a","src/template.rs":"5e275cd2adb00e4238607e5e6d7e7db209a1233b813df77e30ccc5df1991bc01","src/util.rs":"2ebc845de5ca47455442a1b6bd664565a52e29928e82c526fbfe56ed5196410f","tests/block_context.rs":"4dce11312d2b6c0c5c2f3104516e5567e5a370611e08f4055fa3653293580385","tests/data_helper.rs":"a7f9d1d42d5415ba1dba459840067acc1294f6f6057d9a5a13d9f7e19469e850","tests/embed.rs":"de85f16a7a0372cc0e150abe3487ae8180598532e4d73b05b4b107e7e4a0b05e","tests/escape.rs":"7b643675b7884a497d7008cda6e51809efea94a79d25996564b7771cfdbf1709","tests/helper_function_lifetime.rs":"635cbd0b44742539bdf36e803a19c6a1a698399f8b765415d53f28df1acfbc2b","tests/helper_macro.rs":"959cc218fa47c8b30835412c5b6b4f76c8387de49e9e2c73baa9a788f9564361","tests/helper_with_space.rs":"0aee174428b799998a9994b008485373a1b084bf4ea49ed455c890eb627f1ac1","tests/root_var.rs":"fda5b30bac1e692fb010f9f98e052d5a525420fece9dcc3821a4e5aeee3a8841","tests/subexpression.rs":"b36ab31adf45272ca984c0c5ed9497820ca072a8805444d69bd089b766786bb5","tests/template_names.rs":"4bbe6b48c974ae7ea1e61806794d846e2f0e8505e1568c5305fa2364dceef68a","tests/templates/hello.hbs":"4aca52692d2247a22c46856dbfd439a5c4edc47237e488ece5d01e9d8030e882","tests/whitespace.rs":"1cadfbe9cd8e2dd4ca7759fdcaf7fd05116b5e9ec59ca67722c41732fe89dfa3","wasm/LICENSE":"63b308fad3db82dc12067a8d7ff4b672fae97d12d0b4b3bb59179e27d640b3a4","wasm/README.md":"d67bad452550d34e9317fb8f4884b8bc07939fbb0dfdcf1be6bfce52a6851fa6","wasm/wapm.toml":"bdb286ccaa18c5c8aa0d2db25755aba9b0e3e83a59fc4d2334c1854933000ea1"},"package":"360d9740069b2f6cbb63ce2dbaa71a20d3185350cbb990d7bebeb9318415eb17"} \ No newline at end of file diff --git a/vendor/handlebars/CHANGELOG.md b/vendor/handlebars/CHANGELOG.md index 62045f53e..c3b79a657 100644 --- a/vendor/handlebars/CHANGELOG.md +++ b/vendor/handlebars/CHANGELOG.md @@ -1,5 +1,80 @@ # Change Log +## [4.3.3](https://github.com/sunng87/handlebars-rust/compare/4.3.2...4.3.3) - 2022-07-20 + +* [Fixed] Disable partial expression indentation with `{{~> partial}}` to + bring behavior closer in line with original javascript version. [#518] +* [Fixed] Support for using partial context together with partial parameters + [#520] + +## [4.3.2](https://github.com/sunng87/handlebars-rust/compare/4.3.1...4.3.2) - 2022-07-14 + +* [Added] Render functions that reuse `Context` for custom `std::io::Write`: + `render_with_context_to_write` and `render_template_with_context_to_write` + +## [4.3.1](https://github.com/sunng87/handlebars-rust/compare/4.3.0...4.3.1) - 2022-06-09 + +* [Added] Added support for `{{~{variable}~}}` syntax [#509] + +## [4.3.0](https://github.com/sunng87/handlebars-rust/compare/4.2.2...4.3.0) - 2022-05-18 + +* [Changed] update MSRV to 1.57 as rhai requires +* [Fixed] Reimplemented indent support for partial expression `{{> + partial}}`, which is introduced in 4.2.0. The new implementation is + aligned with original javascript version, that every text line + generated from partial are indented as `{{> partial}}` + does. `prevent_indent` will turn-off this feature. [#505] +* [Changed] changed error support library from quick_error to + thiserror + +## [4.2.2](https://github.com/sunng87/handlebars-rust/compare/4.2.1...4.2.2) - 2022-03-09 + +* [Fixed] Block param scope leaked into partials [#496] +* [Changed] Use Rust 2021 edition and update MSRV to 1.56 + +## [4.2.1](https://github.com/sunng87/handlebars-rust/compare/4.2.0...4.2.1) - 2022-01-17 + +* [Fixed] Nested partial `@partial-block` referencing issue [#488] +* [Fixed] Docs generation on docs.rs for `rust-embed` feature + +## [4.2.0](https://github.com/sunng87/handlebars-rust/compare/4.1.6...4.2.0) - 2022-01-05 + +* [Added] RustEmbed support for loading templates from [#484] +* [Fixed] Parser support for variables begins with digit [#479] +* [Changed] Keep indent whitespaces for partial expression `{{> + partial}}` as default in handlebarsjs. A new option `prevent_indent` + is provided on `Handlebars` to turn off this behaviour. [#486] +* [Changed] Update MSRV to 1.51 due to dependency changes + +## [4.1.6](https://github.com/sunng87/handlebars-rust/compare/4.1.5...4.1.6) - 2021-12-03 + +* [Added] Create `Context` from owned `serde_json::Value` [#477] + +## [4.1.5](https://github.com/sunng87/handlebars-rust/compare/4.1.4...4.1.5) - 2021-11-17 + +* [Fixed] Single-quote string literal is supported, again [#475] + +## [4.1.4](https://github.com/sunng87/handlebars-rust/compare/4.1.3...4.1.4) - 2021-11-06 + +* [Fixed] Corrected empty line stripping strategy [#473] + +## [4.1.3](https://github.com/sunng87/handlebars-rust/compare/4.1.2...4.1.3) - 2021-09-10 + +* [Added] `@last` variable for `each` block with object [#466] +* [Fixed] Missing whitespaces behind expression [#468] + +## [4.1.2](https://github.com/sunng87/handlebars-rust/compare/4.1.1...4.1.2) - 2021-08-11 + +* [Added] Support for generic types in `handlebars_helper!`. +* [Added] Getter and setter for rhai `Engine` from registry. +* [Fixed] Improve doc for `dev_mode` that it has to be enabled before + adding templates. + +## [4.1.1](https://github.com/sunng87/handlebars-rust/compare/4.1.0...4.1.1) - 2021-07-31 + +* [Changed] Update rhai to 1.0 [#455] +* [Fixed] Empty line stripping for partial include statement, and other corner cases [#458] + ## [4.1.0](https://github.com/sunng87/handlebars-rust/compare/4.0.1...4.1.0) - 2021-07-05 * [Added] export `StringOutput` as requested in #442 diff --git a/vendor/handlebars/Cargo.lock b/vendor/handlebars/Cargo.lock index 8fc6db06f..27cc86f9b 100644 --- a/vendor/handlebars/Cargo.lock +++ b/vendor/handlebars/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.15.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] @@ -19,22 +19,11 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" -dependencies = [ - "getrandom 0.2.3", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom", "once_cell", "version_check", ] @@ -50,9 +39,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.41" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arrayvec" @@ -63,6 +52,12 @@ dependencies = [ "nodrop", ] +[[package]] +name = "ascii" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109" + [[package]] name = "atty" version = "0.2.14" @@ -76,36 +71,30 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.60" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" @@ -125,7 +114,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", ] [[package]] @@ -139,9 +128,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -149,21 +138,11 @@ dependencies = [ "serde", ] -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byte-tools" @@ -173,9 +152,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.7.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9966d2ab714d0f785dbac0a0396251a35280aeb42413281617d0209ab4898435" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" [[package]] name = "byteorder" @@ -185,85 +164,87 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cast" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ "rustc_version", ] [[package]] name = "cc" -version = "1.0.68" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "chunked_transfer" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", "textwrap", "unicode-width", ] +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "cpp_demangle" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" dependencies = [ - "cfg-if 1.0.0", - "glob", + "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] [[package]] name = "criterion" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", - "itertools 0.10.1", + "itertools", "lazy_static", "num-traits", "oorandom", @@ -280,42 +261,43 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" dependencies = [ "cast", - "itertools 0.9.0", + "itertools", ] [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ - "cfg-if 1.0.0", + "autocfg", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -324,11 +306,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -340,7 +322,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -356,9 +338,9 @@ dependencies = [ [[package]] name = "debugid" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91cf5a8c2f2097e2a32627123508635d47ce10563d999ec1a95addf08b502ba" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "uuid", ] @@ -378,7 +360,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.5", ] [[package]] @@ -389,9 +371,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -407,88 +389,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.15" +name = "fastrand" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "instant", ] [[package]] -name = "futures-channel" -version = "0.3.15" +name = "findshlibs" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" dependencies = [ - "futures-core", - "futures-sink", + "cc", + "lazy_static", + "libc", + "winapi", ] [[package]] -name = "futures-core" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" - -[[package]] -name = "futures-io" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" - -[[package]] -name = "futures-sink" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" - -[[package]] -name = "futures-task" -version = "0.3.15" +name = "fixedbitset" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" [[package]] -name = "futures-util" -version = "0.3.15" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ - "autocfg", - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", - "slab", + "matches", + "percent-encoding", ] [[package]] @@ -502,9 +436,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -512,198 +446,76 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "h2" -version = "0.3.3" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" -dependencies = [ - "bytes 1.0.1", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "half" -version = "1.7.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.1.0" +version = "4.3.3" dependencies = [ "criterion", "env_logger", "log", - "maplit", "pest", "pest_derive", "pprof", - "quick-error 2.0.1", "rhai", + "rust-embed", "serde", "serde_derive", "serde_json", "tempfile", - "tokio", + "thiserror", + "time", + "tiny_http", "walkdir", - "warp", ] [[package]] name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - -[[package]] -name = "headers" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" -dependencies = [ - "base64", - "bitflags", - "bytes 1.0.1", - "headers-core", - "http", - "mime", - "sha-1 0.9.6", - "time", -] - -[[package]] -name = "headers-core" -version = "0.2.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] -[[package]] -name = "http" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" -dependencies = [ - "bytes 1.0.1", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" -dependencies = [ - "bytes 1.0.1", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" - -[[package]] -name = "httpdate" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" - [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07d6baa1b441335f3ce5098ac421fb6547c46dda735ca1bc6d0153c838f9dd83" -dependencies = [ - "bytes 1.0.1", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "idna" version = "0.2.3" @@ -717,9 +529,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown", @@ -727,14 +539,14 @@ dependencies = [ [[package]] name = "inferno" -version = "0.10.6" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3cbcc228d2ad2e99328c2b19f38d80ec387ca6a29f778e40e32ca9f25448c3" +checksum = "16d4bde3a7105e59c66a4104cfe9606453af1c7a0eac78cb7d5bc263eb762a70" dependencies = [ - "ahash 0.6.3", + "ahash", "atty", "indexmap", - "itoa", + "itoa 1.0.1", "lazy_static", "log", "num-format", @@ -743,62 +555,41 @@ dependencies = [ "str_stack", ] -[[package]] -name = "input_buffer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" -dependencies = [ - "bytes 1.0.1", -] - [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "itertools" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -dependencies = [ - "either", + "cfg-if", ] [[package]] name = "itertools" -version = "0.9.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] [[package]] -name = "itertools" -version = "0.10.1" +name = "itoa" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" -dependencies = [ - "either", -] +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -811,26 +602,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -841,81 +633,41 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "memmap" -version = "0.7.0" +name = "memmap2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f" dependencies = [ "libc", - "winapi", ] [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "mime_guess" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" dependencies = [ "adler", - "autocfg", -] - -[[package]] -name = "mio" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", ] [[package]] @@ -924,35 +676,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "multipart" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error 1.2.3", - "rand 0.7.3", - "safemem", - "tempfile", - "twoway", -] - [[package]] name = "nix" -version = "0.17.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" +checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" dependencies = [ "bitflags", - "cc", - "cfg-if 0.1.10", + "cfg-if", "libc", - "void", ] [[package]] @@ -961,15 +693,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", -] - [[package]] name = "num-format" version = "0.4.0" @@ -977,42 +700,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" dependencies = [ "arrayvec", - "itoa", + "itoa 0.4.8", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "object" -version = "0.25.3" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "oorandom" @@ -1034,27 +766,25 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ - "cfg-if 1.0.0", - "instant", + "cfg-if", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-sys", ] [[package]] @@ -1103,151 +833,120 @@ checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" dependencies = [ "maplit", "pest", - "sha-1 0.8.2", + "sha-1", ] [[package]] name = "petgraph" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ "fixedbitset", "indexmap", ] [[package]] -name = "pin-project" -version = "1.0.7" +name = "plotters" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "plotters" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", ] [[package]] name = "plotters-backend" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" [[package]] name = "plotters-svg" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" dependencies = [ "plotters-backend", ] [[package]] name = "pprof" -version = "0.3.20" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937e4766a8d473f9dd3eb318c654dec77d6715a87ab50081d6e5cfceea73c105" +checksum = "1bba88ee898c63351101af3e60c66c5398c517681ce533eef8caff10ecf11ec1" dependencies = [ "backtrace", + "cfg-if", + "findshlibs", "inferno", - "lazy_static", "libc", "log", "nix", + "once_cell", "parking_lot", "prost", "prost-build", "prost-derive", + "smallvec", "symbolic-demangle", "tempfile", "thiserror", ] -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" dependencies = [ "unicode-xid", ] [[package]] name = "prost" -version = "0.6.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212" +checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" dependencies = [ - "bytes 0.5.6", + "bytes", "prost-derive", ] [[package]] name = "prost-build" -version = "0.6.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26" +checksum = "65a1118354442de7feb8a2a76f3d80ef01426bd45542c8c1fdffca41a758f846" dependencies = [ - "bytes 0.5.6", + "bytes", + "cfg-if", + "cmake", "heck", - "itertools 0.8.2", + "itertools", + "lazy_static", "log", "multimap", "petgraph", "prost", "prost-types", + "regex", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.6.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", - "itertools 0.8.2", + "itertools", "proc-macro2", "quote", "syn", @@ -1255,130 +954,37 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.6.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ - "bytes 0.5.6", + "bytes", "prost", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quick-xml" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26aab6b48e2590e4a64d1ed808749ba06257882b461d01ca71baeb747074a6dd" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.2", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" -dependencies = [ - "getrandom 0.2.3", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.2", -] - [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -1388,31 +994,30 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -1442,20 +1047,21 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.27" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fddb3b23626145d1776addfc307e1a1851f60ef6ca64f376bcb889697144cf0" +checksum = "e74fdc210d8f24a7dbfedc13b04ba5764f5232754ccebfdf5fff1bad791ccbc6" dependencies = [ "bytemuck", ] [[package]] name = "rhai" -version = "0.20.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d862e125236e74d2a5033e88b9cb9404010a6a39516a388f570975494fe73bce" +checksum = "9f06953bb8b9e4307cb7ccc0d9d018e2ddd25a30d32831f631ce4fe8f17671f7" dependencies = [ - "ahash 0.7.4", + "ahash", + "bitflags", "instant", "num-traits", "rhai_codegen", @@ -1466,41 +1072,69 @@ dependencies = [ [[package]] name = "rhai_codegen" -version = "0.3.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643fd67d19aafd45a9e335afe4183dc58ba0cc6a1f43fbe34c7d92c041cdcafc" +checksum = "faa0ff1c9dc19c9f8bba510a2a75d3f0449f6233570c2672c7e31c692a11a59a" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "rust-embed" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rustc-demangle" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "safemem" -version = "0.3.3" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "same-file" @@ -1511,12 +1145,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" @@ -1525,36 +1153,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "serde" -version = "1.0.126" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -1562,9 +1178,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -1573,23 +1189,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" -dependencies = [ - "form_urlencoded", - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -1607,47 +1211,33 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.9.6" +name = "sha2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] -[[package]] -name = "slab" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" - [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smartstring" -version = "0.2.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ada87540bf8ef4cf8a1789deb175626829bb59b1fefd816cf7f7f55efcdbae9" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" dependencies = [ + "autocfg", "static_assertions", -] - -[[package]] -name = "socket2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" -dependencies = [ - "libc", - "winapi", + "version_check", ] [[package]] @@ -1670,21 +1260,21 @@ checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" [[package]] name = "symbolic-common" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8e101b55bbcf228c855fa34fc4312e4f58b4a3251f1298bc0f97b71557815d" +checksum = "9ea2ab8b85d27d49d184438b4b77fbd521b385cc9c5c802f60e784f2df25a03d" dependencies = [ "debugid", - "memmap", + "memmap2", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e257e28c2cbcf60a0c21089d32ff8b6cdc7efa6125b13693d29e8986aa1cd99" +checksum = "7939b15a1c62633d1fce17f8a7b668312eaa2d3b117bf4ced5e6e77870c43b6a" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -1693,9 +1283,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.73" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" dependencies = [ "proc-macro2", "quote", @@ -1704,13 +1294,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "fastrand", "libc", - "rand 0.8.3", "redox_syscall", "remove_dir_all", "winapi", @@ -1718,9 +1308,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] @@ -1736,18 +1326,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1756,170 +1346,66 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" dependencies = [ + "itoa 1.0.1", "libc", - "winapi", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ + "num_threads", "serde", - "serde_json", -] - -[[package]] -name = "tinyvec" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" -dependencies = [ - "tinyvec_macros", + "time-macros", ] [[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aea337f72e96efe29acc234d803a5981cd9a2b6ed21655cd7fc21cfe021e8ec7" -dependencies = [ - "autocfg", - "bytes 1.0.1", - "libc", - "memchr", - "mio", - "num_cpus", - "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-stream" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8864d706fdb3cc0843a49647ac892720dac98a6eeb818b77190592cf4994066" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b" -dependencies = [ - "futures-util", - "log", - "pin-project", - "tokio", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" -dependencies = [ - "bytes 1.0.1", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.1" +name = "time-macros" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" [[package]] -name = "tracing" -version = "0.1.26" +name = "tiny_http" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "e0d6ef4e10d23c1efb862eecad25c5054429a71958b4eeef85eb5e7170b477ca" dependencies = [ - "cfg-if 1.0.0", + "ascii", + "chunked_transfer", "log", - "pin-project-lite", - "tracing-core", + "time", + "url", ] [[package]] -name = "tracing-core" -version = "0.1.18" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "lazy_static", + "serde", + "serde_json", ] [[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "tungstenite" -version = "0.12.0" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "base64", - "byteorder", - "bytes 1.0.1", - "http", - "httparse", - "input_buffer", - "log", - "rand 0.8.3", - "sha-1 0.9.6", - "url", - "utf-8", + "tinyvec_macros", ] [[package]] -name = "twoway" -version = "0.1.8" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "typenum" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" @@ -1927,23 +1413,11 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -1954,23 +1428,17 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -1984,29 +1452,17 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "uuid" -version = "0.8.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" [[package]] name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "void" -version = "1.0.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" @@ -2019,51 +1475,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "warp" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054" -dependencies = [ - "bytes 1.0.1", - "futures", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "multipart", - "percent-encoding", - "pin-project", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tower-service", - "tracing", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -2072,19 +1483,19 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -2097,9 +1508,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2107,9 +1518,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -2120,15 +1531,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.51" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -2136,10 +1547,12 @@ dependencies = [ [[package]] name = "which" -version = "3.1.1" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ + "either", + "lazy_static", "libc", ] @@ -2173,3 +1586,46 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/vendor/handlebars/Cargo.toml b/vendor/handlebars/Cargo.toml index f46e0bd13..f40384c26 100644 --- a/vendor/handlebars/Cargo.toml +++ b/vendor/handlebars/Cargo.toml @@ -3,29 +3,45 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" +rust-version = "1.57" name = "handlebars" -version = "4.1.0" +version = "4.3.3" authors = ["Ning Sun "] description = "Handlebars templating implemented in Rust." homepage = "https://github.com/sunng87/handlebars-rust" documentation = "https://docs.rs/crate/handlebars/" readme = "README.md" -keywords = ["handlebars", "templating", "web"] -categories = ["template-engine", "web-programming"] +keywords = [ + "handlebars", + "templating", + "web", +] +categories = [ + "template-engine", + "web-programming", +] license = "MIT" repository = "https://github.com/sunng87/handlebars-rust" +resolver = "2" + [package.metadata.docs.rs] -features = ["dir_source", "script_helper"] -rustdoc-args = ["--cfg", "docsrs"] +features = [ + "dir_source", + "script_helper", + "rust-embed", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] [lib] name = "handlebars" @@ -35,9 +51,14 @@ path = "src/lib.rs" name = "handlebars-cli" path = "src/cli.rs" +[[example]] +name = "script" +required-features = ["script_helper"] + [[bench]] name = "bench" harness = false + [dependencies.log] version = "0.4.0" @@ -47,12 +68,16 @@ version = "2.1.0" [dependencies.pest_derive] version = "2.1.0" -[dependencies.quick-error] -version = "2.0" - [dependencies.rhai] -version = "0.20" -features = ["sync", "serde"] +version = "1.6" +features = [ + "sync", + "serde", +] +optional = true + +[dependencies.rust-embed] +version = "6.3.0" optional = true [dependencies.serde] @@ -61,17 +86,18 @@ version = "1.0.0" [dependencies.serde_json] version = "1.0.39" +[dependencies.thiserror] +version = "1" + [dependencies.walkdir] version = "2.2.3" optional = true + [dev-dependencies.criterion] version = "0.3" [dev-dependencies.env_logger] -version = "0.8" - -[dev-dependencies.maplit] -version = "1.0.0" +version = "0.9" [dev-dependencies.serde_derive] version = "1.0.75" @@ -79,20 +105,29 @@ version = "1.0.75" [dev-dependencies.tempfile] version = "3.0.0" -[dev-dependencies.tokio] -version = "1" -features = ["macros", "rt-multi-thread"] +[dev-dependencies.time] +version = "0.3.7" +features = [ + "serde", + "formatting", + "parsing", +] -[dev-dependencies.warp] -version = "0.3" +[dev-dependencies.tiny_http] +version = "0.11" [features] default = [] dir_source = ["walkdir"] no_logging = [] script_helper = ["rhai"] + [target."cfg(unix)".dev-dependencies.pprof] -version = "0.3.13" -features = ["flamegraph", "protobuf"] +version = "0.10" +features = [ + "flamegraph", + "prost-codec", +] + [badges.maintenance] status = "actively-developed" diff --git a/vendor/handlebars/README.md b/vendor/handlebars/README.md index 4a9c41827..18d21abfb 100644 --- a/vendor/handlebars/README.md +++ b/vendor/handlebars/README.md @@ -4,16 +4,11 @@ handlebars-rust [Handlebars templating language](https://handlebarsjs.com) implemented in Rust and for Rust. -Handlebars-rust is the template engine that renders the official Rust website -[rust-lang.org](https://www.rust-lang.org), [its -book](https://doc.rust-lang.org/book/). - -[![Build Status](https://travis-ci.org/sunng87/handlebars-rust.svg?branch=master)](https://travis-ci.org/sunng87/handlebars-rust) -[![](https://meritbadge.herokuapp.com/handlebars)](https://crates.io/crates/handlebars) +[![CI](https://github.com/sunng87/handlebars-rust/actions/workflows/main.yml/badge.svg)](https://github.com/sunng87/handlebars-rust/actions/workflows/main.yml) +[![](https://img.shields.io/crates/v/handlebars)](https://crates.io/crates/handlebars) [![](https://img.shields.io/crates/d/handlebars.svg)](https://crates.io/crates/handlebars) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![Docs](https://docs.rs/handlebars/badge.svg)](https://docs.rs/crate/handlebars/) -![rustc](https://img.shields.io/badge/rustc-1.50+-lightgray.svg) [![Donate](https://img.shields.io/badge/donate-liberapay-yellow.svg)](https://liberapay.com/Sunng/donate) ## Getting Started @@ -55,6 +50,8 @@ Examples are provided in source tree to demo usage of various api. to use custom helpers. * [render_file](https://github.com/sunng87/handlebars-rust/blob/master/examples/render_file.rs) similar to render, but render to file instead of string +* [helper_macro](https://github.com/sunng87/handlebars-rust/blob/master/examples/helper_macro.rs) + demos usage of `handlebars_helper!` to simplify helper development * [partials](https://github.com/sunng87/handlebars-rust/blob/master/examples/partials.rs) template inheritance with handlebars * [decorator](https://github.com/sunng87/handlebars-rust/blob/master/examples/decorator.rs) @@ -71,7 +68,7 @@ Examples are provided in source tree to demo usage of various api. ## Minimum Rust Version Policy Handlebars will track Rust nightly and stable channel. When dropping -support for previous stable versions, I will bump **major** version +support for previous stable versions, I will bump **patch** version and clarify in CHANGELOG. ## Document @@ -133,7 +130,7 @@ And using it in your template: {{hex 16}} ``` -By default, handlebars-rust ships [additional helpers](https://github.com/sunng87/handlebars-rust/blob/master/src/helpers/helper_boolean.rs#L5) +By default, handlebars-rust ships [additional helpers](https://github.com/sunng87/handlebars-rust/blob/master/src/helpers/helper_extras.rs#L6) (compared with original js version) that is useful when working with `if`. @@ -146,7 +143,7 @@ moment, and can change in future. Every time I look into a templating system, I will investigate its support for [template -inheritance](https://docs.djangoproject.com/en/1.9/ref/templates/language/#template-inheritance). +inheritance](https://docs.djangoproject.com/en/3.2/ref/templates/language/#template-inheritance). Template include is not sufficient for template reuse. In most cases you will need a skeleton of page as parent (header, footer, etc.), and @@ -164,6 +161,13 @@ loaded from files or directory. This can be handy for template development. Handlebars 3.0 can be used in WebAssembly projects. +#### Fully scriptable + +With [rhai](https://github.com/rhaiscript/rhai) script support, you +can implement your own helper with the scripting language. Together +with the template lanaguage itself, template development can be fully +scriptable without changing rust code. + ## Related Projects ### Web frameworks @@ -174,7 +178,7 @@ Handlebars 3.0 can be used in WebAssembly projects. example](https://github.com/seanmonstar/warp/blob/master/examples/handlebars_template.rs) * Tower-web: [Built-in](https://github.com/carllerche/tower-web) * Actix: [handlebars - example](https://github.com/actix/examples/blob/master/template_engines/handlebars/src/main.rs) + example](https://github.com/actix/examples/blob/master/templating/handlebars/src/main.rs) * Tide: [tide-handlebars](https://github.com/No9/tide-handlebars) ### Adopters diff --git a/vendor/handlebars/examples/dev_mode.rs b/vendor/handlebars/examples/dev_mode.rs index 99017474f..3256eed37 100644 --- a/vendor/handlebars/examples/dev_mode.rs +++ b/vendor/handlebars/examples/dev_mode.rs @@ -2,10 +2,9 @@ use std::sync::Arc; use handlebars::Handlebars; use serde_json::json; -use warp::{self, Filter}; +use tiny_http::{Response, Server}; -#[tokio::main] -async fn main() { +fn handlebars() -> Handlebars<'static> { let mut reg = Handlebars::new(); // enable dev mode for template reloading reg.set_dev_mode(true); @@ -14,14 +13,19 @@ async fn main() { reg.register_template_file("tpl", "./examples/dev_mode/template.hbs") .unwrap(); - let hbs = Arc::new(reg); - let route = warp::get().map(move || { + reg +} + +fn main() { + let hbs = Arc::new(handlebars()); + + let server = Server::http("127.0.0.1:3030").expect("Failed to start demo server."); + println!("Edit ./examples/dev_mode/template.hbs and request http://localhost:3030 to see the change on the fly."); + + for req in server.incoming_requests() { let result = hbs .render("tpl", &json!({"model": "t14s", "brand": "Thinkpad"})) .unwrap_or_else(|e| e.to_string()); - warp::reply::html(result) - }); - - println!("Edit ./examples/dev_mode/template.hbs and request http://localhost:3030 to see the change on the run."); - warp::serve(route).run(([127, 0, 0, 1], 3030)).await; + req.respond(Response::from_string(result)).unwrap(); + } } diff --git a/vendor/handlebars/examples/error.rs b/vendor/handlebars/examples/error.rs index 3fb874e2b..ed0f7c423 100644 --- a/vendor/handlebars/examples/error.rs +++ b/vendor/handlebars/examples/error.rs @@ -3,11 +3,44 @@ extern crate handlebars; #[macro_use] extern crate serde_json; -use std::error::Error; +use std::error::Error as StdError; -use handlebars::Handlebars; +use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError}; +use thiserror::Error; -fn main() -> Result<(), Box> { +#[derive(Debug, Error)] +pub enum HelperError { + #[error("db error")] + DbError, + #[error("api error")] + ApiError, +} + +/// A helper that raise error according to parameters +pub fn error_helper( + h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + _: &mut dyn Output, +) -> Result<(), RenderError> { + let param = h + .param(0) + .ok_or(RenderError::new("Param 0 is required for error helper."))?; + match param.value().as_str() { + Some("db") => Err(RenderError::from_error( + "helper error", + HelperError::DbError, + )), + Some("api") => Err(RenderError::from_error( + "helper error", + HelperError::ApiError, + )), + _ => Ok(()), + } +} + +fn main() -> Result<(), Box> { env_logger::init(); let mut handlebars = Handlebars::new(); @@ -36,5 +69,18 @@ fn main() -> Result<(), Box> { println!("{}", be1.source().unwrap()); println!("{:?}", be1.source().unwrap().source()); + // process error generated in helper + handlebars.register_helper("err", Box::new(error_helper)); + let e2 = handlebars + .render_template("{{err \"db\"}}", &json!({})) + .unwrap_err(); + // down-casting the error to user defined type + match e2.source().and_then(|e| e.downcast_ref::()) { + Some(HelperError::DbError) => { + println!("Detected error from helper: db error",) + } + _ => {} + } + Ok(()) } diff --git a/vendor/handlebars/examples/helper_macro.rs b/vendor/handlebars/examples/helper_macro.rs new file mode 100644 index 000000000..dcc6ea31a --- /dev/null +++ b/vendor/handlebars/examples/helper_macro.rs @@ -0,0 +1,63 @@ +use std::error::Error; + +use handlebars::{handlebars_helper, Handlebars, JsonRender}; +use serde_json::{json, Value}; +use time::format_description::parse; +use time::OffsetDateTime; + +// define a helper using helper +// a date format helper accept an `OffsetDateTime` as parameter +handlebars_helper!(date: |dt: OffsetDateTime| dt.format(&parse("[year]-[month]-[day]").unwrap()).unwrap()); + +// a helper returns number of provided parameters +handlebars_helper!(nargs: |*args| args.len()); + +// a helper joins all values, using both hash and parameters +handlebars_helper!(join: |{sep:str=","}, *args| + args.iter().map(|a| a.render()).collect::>().join(sep) +); + +handlebars_helper!(isdefined: |v: Value| !v.is_null()); + +// a helper provides format +handlebars_helper!(date2: |dt: OffsetDateTime, {fmt:str = "[year]-[month]-[day]"}| + dt.format(&parse(fmt).unwrap()).unwrap() +); + +fn main() -> Result<(), Box> { + // create the handlebars registry + let mut handlebars = Handlebars::new(); + + handlebars.register_helper("date", Box::new(date)); + handlebars.register_helper("date2", Box::new(date2)); + handlebars.register_helper("nargs", Box::new(nargs)); + handlebars.register_helper("join", Box::new(join)); + handlebars.register_helper("isdefined", Box::new(isdefined)); + + let data = OffsetDateTime::now_utc(); + + println!("{}", handlebars.render_template("{{date this}}", &data)?); + println!("{}", handlebars.render_template("{{date2 this}}", &data)?); + println!( + "{}", + handlebars.render_template("{{date2 this fmt=\"[day]/[month]/[year]\"}}", &data)? + ); + + println!("{}", handlebars.render_template("{{nargs 1 2 3 4}}", &())?); + + println!( + "{}", + handlebars.render_template("{{join 1 2 3 4 sep=\"|\" }}", &())? + ); + + println!( + "{}", + handlebars.render_template( + r#"{{isdefined a}} {{isdefined b}} +{{#if (isdefined a)}}a{{/if}} {{#if (isdefined b)}}b{{/if}}"#, + &json!({"a": 1}) + )? + ); + + Ok(()) +} diff --git a/vendor/handlebars/examples/partials.rs b/vendor/handlebars/examples/partials.rs index 80b20c2f7..017dd04b7 100644 --- a/vendor/handlebars/examples/partials.rs +++ b/vendor/handlebars/examples/partials.rs @@ -1,9 +1,8 @@ extern crate env_logger; extern crate handlebars; -#[macro_use] -extern crate maplit; use handlebars::Handlebars; +use serde_json::json; use std::error::Error; fn main() -> Result<(), Box> { @@ -15,14 +14,14 @@ fn main() -> Result<(), Box> { handlebars.register_template_file("base0", "./examples/partials/base0.hbs")?; handlebars.register_template_file("base1", "./examples/partials/base1.hbs")?; - let data0 = btreemap! { - "title".to_string() => "example 0".to_string(), - "parent".to_string() => "base0".to_string() - }; - let data1 = btreemap! { - "title".to_string() => "example 1".to_string(), - "parent".to_string() => "base1".to_string() - }; + let data0 = json!({ + "title": "example 0", + "parent": "base0" + }); + let data1 = json!({ + "title": "example 1", + "parent": "base1" + }); println!("Page 0"); println!("{}", handlebars.render("template", &data0)?); diff --git a/vendor/handlebars/examples/script.rs b/vendor/handlebars/examples/script.rs index bedd426cd..de89fa482 100644 --- a/vendor/handlebars/examples/script.rs +++ b/vendor/handlebars/examples/script.rs @@ -5,7 +5,6 @@ use std::error::Error; #[macro_use] extern crate serde_json; -#[cfg(feature = "script_helper")] fn main() -> Result<(), Box> { let mut handlebars = Handlebars::new(); @@ -31,9 +30,3 @@ fn main() -> Result<(), Box> { println!("{}", handlebars.render("tpl", &data)?); Ok(()) } - -#[cfg(not(feature = "script_helper"))] -fn main() -> Result<(), Box> { - println!("Please enable feature flag script_helper for this example"); - Ok(()) -} diff --git a/vendor/handlebars/release.toml b/vendor/handlebars/release.toml index e0f365aa1..6ee7a8383 100644 --- a/vendor/handlebars/release.toml +++ b/vendor/handlebars/release.toml @@ -1,4 +1,6 @@ sign-commit = true +sign-tag = true +dev-version = true pre-release-replacements = [ {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", prerelease=false}, {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", prerelease=false}, diff --git a/vendor/handlebars/src/context.rs b/vendor/handlebars/src/context.rs index 10e15fd90..86f99ba4d 100644 --- a/vendor/handlebars/src/context.rs +++ b/vendor/handlebars/src/context.rs @@ -45,7 +45,7 @@ fn parse_json_visitor<'a, 'reg>( for path_seg in relative_path { match path_seg { PathSeg::Named(the_path) => { - if let Some((holder, base_path)) = get_in_block_params(&block_contexts, the_path) { + if let Some((holder, base_path)) = get_in_block_params(block_contexts, the_path) { with_block_param = Some((holder, base_path)); } break; @@ -171,10 +171,7 @@ impl Context { block_contexts: &VecDeque>, ) -> Result, RenderError> { // always use absolute at the moment until we get base_value lifetime issue fixed - let resolved_visitor = parse_json_visitor(&relative_path, block_contexts, true); - - // debug logging - debug!("Accessing context value: {:?}", resolved_visitor); + let resolved_visitor = parse_json_visitor(relative_path, block_contexts, true); match resolved_visitor { ResolvedPath::AbsolutePath(paths) => { @@ -223,6 +220,12 @@ impl Context { } } +impl From for Context { + fn from(data: Json) -> Context { + Context { data } + } +} + #[cfg(test)] mod test { use crate::block::{BlockContext, BlockParams}; @@ -359,9 +362,9 @@ mod test { #[test] fn test_key_name_with_this() { - let m = btreemap! { - "this_name".to_string() => "the_value".to_string() - }; + let m = json!({ + "this_name": "the_value" + }); let ctx = Context::wraps(&m).unwrap(); assert_eq!( navigate_from_root(&ctx, "this_name").unwrap().render(), diff --git a/vendor/handlebars/src/decorators/mod.rs b/vendor/handlebars/src/decorators/mod.rs index b8bad900f..bd2d23458 100644 --- a/vendor/handlebars/src/decorators/mod.rs +++ b/vendor/handlebars/src/decorators/mod.rs @@ -105,9 +105,9 @@ mod test { .register_template_string("t0", "{{*foo}}".to_string()) .unwrap(); - let data = btreemap! { - "hello".to_string() => "world".to_string() - }; + let data = json!({ + "hello": "world" + }); assert!(handlebars.render("t0", &data).is_err()); @@ -132,9 +132,9 @@ mod test { .register_template_string("t0", "{{hello}}{{*foo}}{{hello}}".to_string()) .unwrap(); - let data = btreemap! { - "hello".to_string() => "world".to_string() - }; + let data = json!({ + "hello": "world" + }); handlebars.register_decorator( "foo", diff --git a/vendor/handlebars/src/error.rs b/vendor/handlebars/src/error.rs index f4721623f..618d68e4f 100644 --- a/vendor/handlebars/src/error.rs +++ b/vendor/handlebars/src/error.rs @@ -1,10 +1,13 @@ -use std::error::Error; -use std::fmt; +// use std::backtrace::Backtrace; +use std::error::Error as StdError; +use std::fmt::{self, Write}; use std::io::Error as IOError; use std::num::ParseIntError; use std::string::FromUtf8Error; use serde_json::error::Error as SerdeError; +use thiserror::Error; + #[cfg(feature = "dir_source")] use walkdir::Error as WalkdirError; @@ -12,14 +15,16 @@ use walkdir::Error as WalkdirError; use rhai::{EvalAltResult, ParseError}; /// Error when rendering data on template. -#[derive(Debug, Default)] +#[derive(Debug, Default, Error)] pub struct RenderError { pub desc: String, pub template_name: Option, pub line_no: Option, pub column_no: Option, - cause: Option>, + #[source] + cause: Option>, unimplemented: bool, + // backtrace: Backtrace, } impl fmt::Display for RenderError { @@ -38,14 +43,6 @@ impl fmt::Display for RenderError { } } -impl Error for RenderError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - self.cause - .as_ref() - .map(|e| e.as_ref() as &(dyn Error + 'static)) - } -} - impl From for RenderError { fn from(e: IOError) -> RenderError { RenderError::from_error("Cannot generate output.", e) @@ -115,7 +112,7 @@ impl RenderError { pub fn from_error(error_info: &str, cause: E) -> RenderError where - E: Error + Send + Sync + 'static, + E: StdError + Send + Sync + 'static, { let mut e = RenderError::new(error_info); e.cause = Some(Box::new(cause)); @@ -129,39 +126,31 @@ impl RenderError { } } -quick_error! { /// Template parsing error - #[derive(Debug)] - pub enum TemplateErrorReason { - MismatchingClosedHelper(open: String, closed: String) { - display("helper {:?} was opened, but {:?} is closing", - open, closed) - } - MismatchingClosedDecorator(open: String, closed: String) { - display("decorator {:?} was opened, but {:?} is closing", - open, closed) - } - InvalidSyntax { - display("invalid handlebars syntax.") - } - InvalidParam (param: String) { - display("invalid parameter {:?}", param) - } - NestedSubexpression { - display("nested subexpression is not supported") - } - IoError(err: IOError, name: String) { - display("Template \"{}\": {}", name, err) - } - #[cfg(feature = "dir_source")] - WalkdirError(err: WalkdirError) { - display("Walk dir error: {}", err) - } - } +#[derive(Debug, Error)] +pub enum TemplateErrorReason { + #[error("helper {0:?} was opened, but {1:?} is closing")] + MismatchingClosedHelper(String, String), + #[error("decorator {0:?} was opened, but {1:?} is closing")] + MismatchingClosedDecorator(String, String), + #[error("invalid handlebars syntax.")] + InvalidSyntax, + #[error("invalid parameter {0:?}")] + InvalidParam(String), + #[error("nested subexpression is not supported")] + NestedSubexpression, + #[error("Template \"{1}\": {0}")] + IoError(IOError, String), + #[cfg(feature = "dir_source")] + #[error("Walk dir error: {err}")] + WalkdirError { + #[from] + err: WalkdirError, + }, } /// Error on parsing template. -#[derive(Debug)] +#[derive(Debug, Error)] pub struct TemplateError { pub reason: TemplateErrorReason, pub template_name: Option, @@ -194,8 +183,6 @@ impl TemplateError { } } -impl Error for TemplateError {} - impl From<(IOError, String)> for TemplateError { fn from(err_info: (IOError, String)) -> TemplateError { let (e, name) = err_info; @@ -206,7 +193,7 @@ impl From<(IOError, String)> for TemplateError { #[cfg(feature = "dir_source")] impl From for TemplateError { fn from(e: WalkdirError) -> TemplateError { - TemplateError::of(TemplateErrorReason::WalkdirError(e)) + TemplateError::of(TemplateErrorReason::from(e)) } } @@ -218,7 +205,7 @@ fn template_segment(template_str: &str, line: usize, col: usize) -> String { let mut buf = String::new(); for (line_count, line_content) in template_str.lines().enumerate() { if line_count >= line_start && line_count <= line_end { - buf.push_str(&format!("{:4} | {}\n", line_count, line_content)); + let _ = writeln!(&mut buf, "{:4} | {}", line_count, line_content); if line_count == line - 1 { buf.push_str(" |"); for c in 0..line_content.len() { @@ -257,16 +244,11 @@ impl fmt::Display for TemplateError { } #[cfg(feature = "script_helper")] -quick_error! { - #[derive(Debug)] - pub enum ScriptError { - IoError(err: IOError) { - from() - source(err) - } - ParseError(err: ParseError) { - from() - source(err) - } - } +#[derive(Debug, Error)] +pub enum ScriptError { + #[error(transparent)] + IoError(#[from] IOError), + + #[error(transparent)] + ParseError(#[from] ParseError), } diff --git a/vendor/handlebars/src/grammar.pest b/vendor/handlebars/src/grammar.pest index 250d9d213..ac6776ee2 100644 --- a/vendor/handlebars/src/grammar.pest +++ b/vendor/handlebars/src/grammar.pest @@ -14,14 +14,20 @@ literal = { string_literal | null_literal = @{ "null" ~ !symbol_char } boolean_literal = @{ ("true"|"false") ~ !symbol_char } -number_literal = @{ "-"? ~ ASCII_DIGIT+ ~ "."? ~ ASCII_DIGIT* ~ ("E" ~ "-"? ~ ASCII_DIGIT+)? } -json_char = { +number_literal = @{ "-"? ~ ASCII_DIGIT+ ~ "."? ~ ASCII_DIGIT* ~ ("E" ~ "-"? ~ ASCII_DIGIT+)? ~ !symbol_char } +json_char_double_quote = { !("\"" | "\\") ~ ANY | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) } -string_inner = @{ json_char* } -string_literal = ${ "\"" ~ string_inner ~ "\"" } +json_char_single_quote = { + !("'" | "\\") ~ ANY + | "\\" ~ ("'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") + | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) +} +string_inner_double_quote = @{ json_char_double_quote* } +string_inner_single_quote = @{ json_char_single_quote* } +string_literal = ${ ("\"" ~ string_inner_double_quote ~ "\"") | ("'" ~ string_inner_single_quote ~ "'") } array_literal = { "[" ~ literal? ~ ("," ~ literal)* ~ "]" } object_literal = { "{" ~ (string_literal ~ ":" ~ literal)? ~ ("," ~ string_literal ~ ":" ~ literal)* ~ "}" } @@ -50,12 +56,17 @@ pro_whitespace_omitter = { "~" } expression = { !invert_tag ~ "{{" ~ pre_whitespace_omitter? ~ ((identifier ~ (hash|param)+) | name ) ~ pro_whitespace_omitter? ~ "}}" } -html_expression_triple_bracket = _{ "{{{" ~ pre_whitespace_omitter? ~ - ((identifier ~ (hash|param)+) | name ) ~ - pro_whitespace_omitter? ~ "}}}" } +html_expression_triple_bracket_legacy = _{ "{{{" ~ pre_whitespace_omitter? ~ + ((identifier ~ (hash|param)+) | name ) ~ + pro_whitespace_omitter? ~ "}}}" } +html_expression_triple_bracket = _{ "{{" ~ pre_whitespace_omitter? ~ "{" ~ + ((identifier ~ (hash|param)+) | name ) ~ + "}" ~ pro_whitespace_omitter? ~ "}}" } + amp_expression = _{ "{{" ~ pre_whitespace_omitter? ~ "&" ~ name ~ pro_whitespace_omitter? ~ "}}" } -html_expression = { html_expression_triple_bracket | amp_expression } +html_expression = { (html_expression_triple_bracket_legacy | html_expression_triple_bracket) + | amp_expression } decorator_expression = { "{{" ~ pre_whitespace_omitter? ~ "*" ~ exp_line ~ pro_whitespace_omitter? ~ "}}" } diff --git a/vendor/handlebars/src/grammar.rs b/vendor/handlebars/src/grammar.rs index 1fd292ce1..6e61cd4e4 100644 --- a/vendor/handlebars/src/grammar.rs +++ b/vendor/handlebars/src/grammar.rs @@ -4,26 +4,6 @@ #[grammar = "grammar.pest"] pub struct HandlebarsParser; -#[inline] -pub(crate) fn whitespace_matcher(c: char) -> bool { - c == ' ' || c == '\t' -} - -#[inline] -pub(crate) fn newline_matcher(c: char) -> bool { - c == '\n' || c == '\r' -} - -pub(crate) fn ends_with_empty_line(text: &str) -> bool { - text.trim_end_matches(whitespace_matcher) - .ends_with(newline_matcher) -} - -pub(crate) fn starts_with_empty_line(text: &str) -> bool { - text.trim_start_matches(whitespace_matcher) - .starts_with(newline_matcher) -} - #[cfg(test)] mod test { use super::{HandlebarsParser, Rule}; @@ -191,6 +171,7 @@ mod test { "{{exp 1}}", "{{exp \"literal\"}}", "{{exp \"literal with space\"}}", + "{{exp 'literal with space'}}", r#"{{exp "literal with escape \\\\"}}"#, "{{exp ref}}", "{{exp (sub)}}", @@ -199,6 +180,8 @@ mod test { "{{exp {}}}", "{{exp key=1}}", "{{exp key=ref}}", + "{{exp key='literal with space'}}", + "{{exp key=\"literal with space\"}}", "{{exp key=(sub)}}", "{{exp key=(sub 0)}}", "{{exp key=(sub 0 key=1)}}", @@ -225,6 +208,12 @@ mod test { "{{&html}}", "{{{html 1}}}", "{{{html p=true}}}", + "{{{~ html}}}", + "{{{html ~}}}", + "{{{~ html ~}}}", + "{{~{ html }~}}", + "{{~{ html }}}", + "{{{ html }~}}", ]; for i in s.iter() { assert_rule!(Rule::html_expression, i); diff --git a/vendor/handlebars/src/helpers/helper_each.rs b/vendor/handlebars/src/helpers/helper_each.rs index 4b76e7ce7..2be28dc9c 100644 --- a/vendor/handlebars/src/helpers/helper_each.rs +++ b/vendor/handlebars/src/helpers/helper_each.rs @@ -18,7 +18,7 @@ fn update_block_context<'reg>( is_first: bool, value: &Json, ) { - if let Some(ref p) = base_path { + if let Some(p) = base_path { if is_first { *block.base_path_mut() = copy_on_push_vec(p, relative_path); } else if let Some(ptr) = block.base_path_mut().last_mut() { @@ -83,7 +83,7 @@ impl HelperDef for EachHelper { Json::Array(ref list) if !list.is_empty() || (list.is_empty() && h.inverse().is_none()) => { - let block_context = create_block(&value); + let block_context = create_block(value); rc.push_block(block_context); let len = list.len(); @@ -100,8 +100,8 @@ impl HelperDef for EachHelper { block.set_local_var("last", to_json(is_last)); block.set_local_var("index", index.clone()); - update_block_context(block, array_path, i.to_string(), is_first, &v); - set_block_param(block, h, array_path, &index, &v)?; + update_block_context(block, array_path, i.to_string(), is_first, v); + set_block_param(block, h, array_path, &index, v)?; } t.render(r, ctx, rc, out)?; @@ -113,28 +113,28 @@ impl HelperDef for EachHelper { Json::Object(ref obj) if !obj.is_empty() || (obj.is_empty() && h.inverse().is_none()) => { - let block_context = create_block(&value); + let block_context = create_block(value); rc.push_block(block_context); - let mut is_first = true; + let len = obj.len(); + let obj_path = value.context_path(); - for (k, v) in obj.iter() { + for (i, (k, v)) in obj.iter().enumerate() { if let Some(ref mut block) = rc.block_mut() { - let key = to_json(k); + let is_first = i == 0usize; + let is_last = i == len - 1; + let key = to_json(k); block.set_local_var("first", to_json(is_first)); + block.set_local_var("last", to_json(is_last)); block.set_local_var("key", key.clone()); - update_block_context(block, obj_path, k.to_string(), is_first, &v); - set_block_param(block, h, obj_path, &key, &v)?; + update_block_context(block, obj_path, k.to_string(), is_first, v); + set_block_param(block, h, obj_path, &key, v)?; } t.render(r, ctx, rc, out)?; - - if is_first { - is_first = false; - } } rc.pop_block(); @@ -159,7 +159,6 @@ pub static EACH_HELPER: EachHelper = EachHelper; #[cfg(test)] mod test { - use crate::json::value::to_json; use crate::registry::Registry; use serde_json::value::Value as Json; use std::collections::BTreeMap; @@ -188,7 +187,10 @@ mod test { ) .is_ok()); assert!(handlebars - .register_template_string("t1", "{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}") + .register_template_string( + "t1", + "{{#each this}}{{@first}}|{{@last}}|{{@key}}:{{this}}|{{/each}}" + ) .is_ok()); let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]); @@ -199,9 +201,13 @@ mod test { let mut m: BTreeMap = BTreeMap::new(); m.insert("ftp".to_string(), 21); + m.insert("gopher".to_string(), 70); m.insert("http".to_string(), 80); let r1 = handlebars.render("t1", &m); - assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string()); + assert_eq!( + r1.ok().unwrap(), + "true|false|ftp:21|false|false|gopher:70|false|true|http:80|".to_string() + ); } #[test] @@ -303,15 +309,15 @@ mod test { assert!(handlebars .register_template_string("t0", "{{#each a}}1{{else}}empty{{/each}}") .is_ok()); - let m1 = btreemap! { - "a".to_string() => Vec::::new(), - }; + let m1 = json!({ + "a": [] + }); let r0 = handlebars.render("t0", &m1).unwrap(); assert_eq!(r0, "empty"); - let m2 = btreemap! { - "b".to_string() => Vec::::new() - }; + let m2 = json!({ + "b": [] + }); let r1 = handlebars.render("t0", &m2).unwrap(); assert_eq!(r1, "empty"); } @@ -322,9 +328,9 @@ mod test { assert!(handlebars .register_template_string("t0", "{{#each a as |i|}}{{i}}{{/each}}") .is_ok()); - let m1 = btreemap! { - "a".to_string() => vec![1,2,3,4,5] - }; + let m1 = json!({ + "a": [1,2,3,4,5] + }); let r0 = handlebars.render("t0", &m1).unwrap(); assert_eq!(r0, "12345"); } @@ -337,10 +343,10 @@ mod test { {{/each}}"; assert!(handlebars.register_template_string("t0", template).is_ok()); - let m = btreemap! { - "ftp".to_string() => 21, - "http".to_string() => 80 - }; + let m = json!({ + "ftp": 21, + "http": 80 + }); let r0 = handlebars.render("t0", &m); assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string()); } @@ -354,10 +360,10 @@ mod test { assert!(handlebars.register_template_string("t0", template).is_ok()); - let m = btreemap! { - "ftp".to_string() => 21, - "http".to_string() => 80 - }; + let m = json!({ + "ftp": 21, + "http": 80 + }); let r0 = handlebars.render("t0", &m); assert_eq!(r0.ok().unwrap(), "ftp:21|http:80|".to_string()); } @@ -371,12 +377,12 @@ mod test { ) .is_ok()); - let data = btreemap! { - "a".to_string() => to_json(&btreemap! { - "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}] - }), - "d".to_string() => to_json(&1) - }; + let data = json!({ + "a": { + "b": [{"c": [1]}] + }, + "d": 1 + }); let r0 = handlebars.render("t0", &data); assert_eq!(r0.ok().unwrap(), "1".to_string()); @@ -389,10 +395,10 @@ mod test { {{#if @first}}template<{{/if}}{{this}}{{#if @last}}>{{else}},{{/if}}\ {{/each}}{{/each}}"; assert!(handlebars.register_template_string("t0", template).is_ok()); - let data = btreemap! { - "typearg".to_string() => vec!["T".to_string()], - "variant".to_string() => vec!["1".to_string(), "2".to_string()] - }; + let data = json!({ + "typearg": ["T"], + "variant": ["1", "2"] + }); let r0 = handlebars.render("t0", &data); assert_eq!(r0.ok().unwrap(), "templatetemplate".to_string()); } diff --git a/vendor/handlebars/src/helpers/helper_if.rs b/vendor/handlebars/src/helpers/helper_if.rs index 5a6e42fc0..342c74567 100644 --- a/vendor/handlebars/src/helpers/helper_if.rs +++ b/vendor/handlebars/src/helpers/helper_if.rs @@ -36,7 +36,7 @@ impl HelperDef for IfHelper { let tmpl = if value { h.template() } else { h.inverse() }; match tmpl { - Some(ref t) => t.render(r, ctx, rc, out), + Some(t) => t.render(r, ctx, rc, out), None => Ok(()), } } @@ -136,6 +136,12 @@ mod test { .unwrap() ); + assert_eq!( + "yes\r\n", + hbs.render_template("{{#if a}}\r\nyes\r\n{{/if}}\r\n", &json!({"a": true})) + .unwrap() + ); + assert_eq!( "x\ny", hbs.render_template("{{#if a}}x{{/if}}\ny", &json!({"a": true})) @@ -147,5 +153,37 @@ mod test { hbs.render_template("{{#if a}}\nx\n{{^}}\ny\n{{/if}}\nz", &json!({"a": false})) .unwrap() ); + + assert_eq!( + r#"yes + foo + bar + baz"#, + hbs.render_template( + r#"yes + {{#if true}} + foo + bar + {{/if}} + baz"#, + &json!({}) + ) + .unwrap() + ); + + assert_eq!( + r#" foo + bar + baz"#, + hbs.render_template( + r#" {{#if true}} + foo + bar + {{/if}} + baz"#, + &json!({}) + ) + .unwrap() + ); } } diff --git a/vendor/handlebars/src/helpers/helper_lookup.rs b/vendor/handlebars/src/helpers/helper_lookup.rs index bf887debe..8662d55a0 100644 --- a/vendor/handlebars/src/helpers/helper_lookup.rs +++ b/vendor/handlebars/src/helpers/helper_lookup.rs @@ -52,8 +52,6 @@ pub static LOOKUP_HELPER: LookupHelper = LookupHelper; mod test { use crate::registry::Registry; - use std::collections::BTreeMap; - #[test] fn test_lookup() { let mut handlebars = Registry::new(); @@ -67,13 +65,11 @@ mod test { .register_template_string("t2", "{{lookup kk \"a\"}}") .is_ok()); - let mut m: BTreeMap> = BTreeMap::new(); - m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]); - m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]); + let m = json!({"v1": [1,2,3], "v2": [9,8,7]}); - let m2 = btreemap! { - "kk".to_string() => btreemap!{"a".to_string() => "world".to_string()} - }; + let m2 = json!({ + "kk": {"a": "world"} + }); let r0 = handlebars.render("t0", &m); assert_eq!(r0.ok().unwrap(), "987".to_string()); diff --git a/vendor/handlebars/src/helpers/helper_with.rs b/vendor/handlebars/src/helpers/helper_with.rs index c4d31cd0e..2ea6bd4f6 100644 --- a/vendor/handlebars/src/helpers/helper_with.rs +++ b/vendor/handlebars/src/helpers/helper_with.rs @@ -25,7 +25,7 @@ impl HelperDef for WithHelper { .ok_or_else(|| RenderError::new("Param not found for helper \"with\""))?; if param.value().is_truthy(false) { - let mut block = create_block(¶m); + let mut block = create_block(param); if let Some(block_param) = h.block_param() { let mut params = BlockParams::new(); @@ -60,7 +60,6 @@ pub static WITH_HELPER: WithHelper = WithHelper; #[cfg(test)] mod test { - use crate::json::value::to_json; use crate::registry::Registry; #[derive(Serialize)] @@ -211,12 +210,12 @@ mod test { assert!(handlebars .register_template_string("t0", "{{#with a}}{{#with b}}{{../../d}}{{/with}}{{/with}}") .is_ok()); - let data = btreemap! { - "a".to_string() => to_json(&btreemap! { - "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}] - }), - "d".to_string() => to_json(1) - }; + let data = json!({ + "a": { + "b": [{"c": [1]}] + }, + "d": 1 + }); let r0 = handlebars.render("t0", &data); assert_eq!(r0.ok().unwrap(), "1".to_string()); diff --git a/vendor/handlebars/src/helpers/mod.rs b/vendor/handlebars/src/helpers/mod.rs index bfd50c1f4..ff5fa2495 100644 --- a/vendor/handlebars/src/helpers/mod.rs +++ b/vendor/handlebars/src/helpers/mod.rs @@ -32,7 +32,8 @@ pub type HelperResult = Result<(), RenderError>; /// ``` /// use handlebars::*; /// -/// fn upper(h: &Helper<'_, '_>, _: &Handlebars<'_>, _: &Context, rc: &mut RenderContext<'_, '_>, out: &mut Output) +/// fn upper(h: &Helper<'_, '_>, _: &Handlebars<'_>, _: &Context, rc: +/// &mut RenderContext<'_, '_>, out: &mut dyn Output) /// -> HelperResult { /// // get parameter from helper or throw an error /// let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or(""); diff --git a/vendor/handlebars/src/helpers/scripting.rs b/vendor/handlebars/src/helpers/scripting.rs index cec3b9763..abd567ae9 100644 --- a/vendor/handlebars/src/helpers/scripting.rs +++ b/vendor/handlebars/src/helpers/scripting.rs @@ -98,10 +98,16 @@ mod test { let ast = engine.compile(&script).unwrap(); let params = vec![PathAndJson::new(None, ScopedJson::Derived(json!(true)))]; - let hash = btreemap! { - "me" => PathAndJson::new(None, ScopedJson::Derived(json!("no"))), - "you" => PathAndJson::new(None, ScopedJson::Derived(json!("yes"))), - }; + + let mut hash = BTreeMap::new(); + hash.insert( + "me", + PathAndJson::new(None, ScopedJson::Derived(json!("no"))), + ); + hash.insert( + "you", + PathAndJson::new(None, ScopedJson::Derived(json!("yes"))), + ); let result = call_script_helper(¶ms, &hash, &engine, &ast) .unwrap() diff --git a/vendor/handlebars/src/json/path.rs b/vendor/handlebars/src/json/path.rs index 8270371b2..17a7a91ee 100644 --- a/vendor/handlebars/src/json/path.rs +++ b/vendor/handlebars/src/json/path.rs @@ -6,7 +6,7 @@ use pest::Parser; use crate::error::RenderError; use crate::grammar::{HandlebarsParser, Rule}; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum PathSeg { Named(String), Ruled(Rule), @@ -16,7 +16,7 @@ pub enum PathSeg { /// /// It can be either a local variable like `@first`, `../@index`, /// or a normal relative path like `a/b/c`. -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum Path { Relative((Vec, String)), Local((usize, String, String)), diff --git a/vendor/handlebars/src/lib.rs b/vendor/handlebars/src/lib.rs index 7e0aac830..1f9ab1ed3 100644 --- a/vendor/handlebars/src/lib.rs +++ b/vendor/handlebars/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/handlebars/4.1.0")] +#![doc(html_root_url = "https://docs.rs/handlebars/4.3.3")] #![cfg_attr(docsrs, feature(doc_cfg))] //! # Handlebars //! @@ -73,7 +73,7 @@ //! Every time I look into a templating system, I will investigate its //! support for [template inheritance][t]. //! -//! [t]: https://docs.djangoproject.com/en/1.9/ref/templates/language/#template-inheritance +//! [t]: https://docs.djangoproject.com/en/3.2/ref/templates/language/#template-inheritance //! //! Template include is not sufficient for template reuse. In most cases //! you will need a skeleton of page as parent (header, footer, etc.), and @@ -155,7 +155,7 @@ //! use handlebars::Handlebars; //! use std::collections::BTreeMap; //! -//! # fn main() -> Result<(), Box> { +//! # fn main() -> Result<(), Box> { //! let mut handlebars = Handlebars::new(); //! let source = "hello {{world}}"; //! @@ -166,6 +166,14 @@ //! # } //! ``` //! +//! #### Additional features for loading template from +//! +//! * Feature `dir_source` enables template loading +//! `register_templates_directory` from given directory. +//! * Feature `rust-embed` enables template loading +//! `register_embed_templates` from embedded resources in rust struct +//! generated with `RustEmbed`. +//! //! ### Rendering Something //! //! Since handlebars is originally based on JavaScript type system. It supports dynamic features like duck-typing, truthy/falsey values. But for a static language like Rust, this is a little difficult. As a solution, we are using the `serde_json::value::Value` internally for data rendering. @@ -188,7 +196,7 @@ //! age: i16, //! } //! -//! # fn main() -> Result<(), Box> { +//! # fn main() -> Result<(), Box> { //! let source = "Hello, {{name}}"; //! //! let mut handlebars = Handlebars::new(); @@ -367,13 +375,8 @@ #[macro_use] extern crate log; -#[cfg(test)] -#[macro_use] -extern crate maplit; #[macro_use] extern crate pest_derive; -#[macro_use] -extern crate quick_error; #[cfg(test)] #[macro_use] extern crate serde_derive; diff --git a/vendor/handlebars/src/macros.rs b/vendor/handlebars/src/macros.rs index 14cb0152c..bd1eab0bb 100644 --- a/vendor/handlebars/src/macros.rs +++ b/vendor/handlebars/src/macros.rs @@ -38,7 +38,7 @@ #[macro_export] macro_rules! handlebars_helper { - ($struct_name:ident: |$($name:ident: $tpe:tt),* + ($struct_name:ident: |$($name:ident: $tpe:tt$(<$($gen:ty),+>)?),* $($(,)?{$($hash_name:ident: $hash_tpe:tt=$dft_val:literal),*})? $($(,)?*$args:ident)? $($(,)?**$kwargs:ident)?| @@ -71,11 +71,11 @@ macro_rules! handlebars_helper { stringify!($struct_name), stringify!($name), ))) .and_then(|x| - handlebars_helper!(@as_json_value x, $tpe) + handlebars_helper!(@as_json_value x, $tpe$(<$($gen),+>)?) .ok_or_else(|| $crate::RenderError::new(&format!( "`{}` helper: Couldn't convert parameter {} to type `{}`. \ It's {:?} as JSON. Got these params: {:?}", - stringify!($struct_name), stringify!($name), stringify!($tpe), + stringify!($struct_name), stringify!($name), stringify!($tpe$(<$($gen),+>)?), x, h.params(), ))) )?; @@ -117,6 +117,7 @@ macro_rules! handlebars_helper { (@as_json_value $x:ident, bool) => { $x.as_bool() }; (@as_json_value $x:ident, null) => { $x.as_null() }; (@as_json_value $x:ident, Json) => { Some($x) }; + (@as_json_value $x:ident, $tpe:tt$(<$($gen:ty),+>)?) => { serde_json::from_value::<$tpe$(<$($gen),+>)?>($x.clone()).ok() }; } #[cfg(feature = "no_logging")] diff --git a/vendor/handlebars/src/output.rs b/vendor/handlebars/src/output.rs index f1c5865a5..67e62b849 100644 --- a/vendor/handlebars/src/output.rs +++ b/vendor/handlebars/src/output.rs @@ -46,3 +46,9 @@ impl StringOutput { String::from_utf8(self.buf) } } + +impl Default for StringOutput { + fn default() -> Self { + StringOutput::new() + } +} diff --git a/vendor/handlebars/src/partial.rs b/vendor/handlebars/src/partial.rs index a472d5d14..bcf9803fd 100644 --- a/vendor/handlebars/src/partial.rs +++ b/vendor/handlebars/src/partial.rs @@ -20,7 +20,7 @@ fn find_partial<'reg: 'rc, 'rc: 'a, 'a>( d: &Decorator<'reg, 'rc>, name: &str, ) -> Result>, RenderError> { - if let Some(ref partial) = rc.get_partial(name) { + if let Some(partial) = rc.get_partial(name) { return Ok(Some(Cow::Borrowed(partial))); } @@ -52,29 +52,38 @@ pub fn expand_partial<'reg: 'rc, 'rc>( return Err(RenderError::new("Cannot include self in >")); } - // if tname == PARTIAL_BLOCK let partial = find_partial(rc, r, d, tname)?; if let Some(t) = partial { // clone to avoid lifetime issue // FIXME refactor this to avoid let mut local_rc = rc.clone(); + + // if tname == PARTIAL_BLOCK let is_partial_block = tname == PARTIAL_BLOCK; + // add partial block depth there are consecutive partial + // blocks in the stack. if is_partial_block { local_rc.inc_partial_block_depth(); + } else { + // depth cannot be lower than 0, which is guaranted in the + // `dec_partial_block_depth` method + local_rc.dec_partial_block_depth(); } + let mut block = None; let mut block_created = false; - if let Some(ref base_path) = d.param(0).and_then(|p| p.context_path()) { + // create context if param given + if let Some(base_path) = d.param(0).and_then(|p| p.context_path()) { // path given, update base_path - let mut block = BlockContext::new(); - *block.base_path_mut() = base_path.to_vec(); - block_created = true; - local_rc.push_block(block); - } else if !d.hash().is_empty() { - let mut block = BlockContext::new(); + let mut block_inner = BlockContext::new(); + *block_inner.base_path_mut() = base_path.to_vec(); + block = Some(block_inner); + } + + if !d.hash().is_empty() { // hash given, update base_value let hash_ctx = d .hash() @@ -86,9 +95,25 @@ pub fn expand_partial<'reg: 'rc, 'rc>( local_rc.evaluate2(ctx, &Path::current())?.as_json(), &hash_ctx, ); - block.set_base_value(merged_context); + + if let Some(ref mut block_inner) = block { + block_inner.set_base_value(merged_context); + } else { + let mut block_inner = BlockContext::new(); + block_inner.set_base_value(merged_context); + block = Some(block_inner); + } + } + + if let Some(block_inner) = block { + // because block is moved here, we need another bool variable to track + // its status for later cleanup block_created = true; - local_rc.push_block(block); + // clear blocks to prevent block params from parent + // template to be leaked into partials + // see `test_partial_context_issue_495` for the case. + local_rc.clear_blocks(); + local_rc.push_block(block_inner); } // @partial-block @@ -96,6 +121,9 @@ pub fn expand_partial<'reg: 'rc, 'rc>( local_rc.push_partial_block(pb); } + // indent + local_rc.set_indent_string(d.indent()); + let result = t.render(r, ctx, &mut local_rc, out); // cleanup @@ -103,10 +131,6 @@ pub fn expand_partial<'reg: 'rc, 'rc>( local_rc.pop_block(); } - if is_partial_block { - local_rc.dec_partial_block_depth(); - } - if d.template().is_some() { local_rc.pop_partial_block(); } @@ -174,10 +198,7 @@ mod test { "include navbar".to_string() ); assert_eq!( - handlebars - .render("t6", &btreemap! {"a".to_string() => "2".to_string()}) - .ok() - .unwrap(), + handlebars.render("t6", &json!({"a": "2"})).ok().unwrap(), "2".to_string() ); assert_eq!( @@ -257,6 +278,19 @@ mod test { ); } + #[test] + fn teset_partial_context_with_both_hash_and_param() { + let mut hbs = Registry::new(); + hbs.register_template_string("one", "This is a test. {{> two this name=\"fred\" }}") + .unwrap(); + hbs.register_template_string("two", "Lets test {{name}} and {{root_name}}") + .unwrap(); + assert_eq!( + "This is a test. Lets test fred and tom", + hbs.render("one", &json!({"root_name": "tom"})).unwrap() + ); + } + #[test] fn test_partial_subexpression_context_hash() { let mut hbs = Registry::new(); @@ -297,7 +331,7 @@ mod test { } #[test] - fn test_nested_partials() { + fn test_nested_partial_block() { let mut handlebars = Registry::new(); let template1 = "{{> @partial-block }}"; let template2 = "{{#> t1 }}{{> @partial-block }}{{/ t1 }}"; @@ -330,4 +364,293 @@ mod test { "fruit: carrot,fruit: tomato," ); } + + #[test] + fn line_stripping_with_inline_and_partial() { + let tpl0 = r#"{{#*inline "foo"}}foo +{{/inline}} +{{> foo}} +{{> foo}} +{{> foo}}"#; + let tpl1 = r#"{{#*inline "foo"}}foo{{/inline}} +{{> foo}} +{{> foo}} +{{> foo}}"#; + + let hbs = Registry::new(); + assert_eq!( + r#"foo +foo +foo +"#, + hbs.render_template(tpl0, &json!({})).unwrap() + ); + assert_eq!( + r#" +foofoofoo"#, + hbs.render_template(tpl1, &json!({})).unwrap() + ); + } + + #[test] + fn test_partial_indent() { + let outer = r#" {{> inner inner_solo}} + +{{#each inners}} + {{> inner}} +{{/each}} + + {{#each inners}} + {{> inner}} + {{/each}} +"#; + let inner = r#"name: {{name}} +"#; + + let mut hbs = Registry::new(); + + hbs.register_template_string("inner", inner).unwrap(); + hbs.register_template_string("outer", outer).unwrap(); + + let result = hbs + .render( + "outer", + &json!({ + "inner_solo": {"name": "inner_solo"}, + "inners": [ + {"name": "hello"}, + {"name": "there"} + ] + }), + ) + .unwrap(); + + assert_eq!( + result, + r#" name: inner_solo + + name: hello + name: there + + name: hello + name: there +"# + ); + } + // Rule::partial_expression should not trim leading indent by default + + #[test] + fn test_partial_prevent_indent() { + let outer = r#" {{> inner inner_solo}} + +{{#each inners}} + {{> inner}} +{{/each}} + + {{#each inners}} + {{> inner}} + {{/each}} +"#; + let inner = r#"name: {{name}} +"#; + + let mut hbs = Registry::new(); + hbs.set_prevent_indent(true); + + hbs.register_template_string("inner", inner).unwrap(); + hbs.register_template_string("outer", outer).unwrap(); + + let result = hbs + .render( + "outer", + &json!({ + "inner_solo": {"name": "inner_solo"}, + "inners": [ + {"name": "hello"}, + {"name": "there"} + ] + }), + ) + .unwrap(); + + assert_eq!( + result, + r#" name: inner_solo + + name: hello + name: there + + name: hello + name: there +"# + ); + } + + #[test] + fn test_nested_partials() { + let mut hb = Registry::new(); + hb.register_template_string("partial", "{{> @partial-block}}") + .unwrap(); + hb.register_template_string( + "index", + r#"{{#>partial}} + Yo + {{#>partial}} + Yo 2 + {{/partial}} +{{/partial}}"#, + ) + .unwrap(); + assert_eq!( + r#" Yo + Yo 2 +"#, + hb.render("index", &()).unwrap() + ); + + hb.register_template_string("partial2", "{{> @partial-block}}") + .unwrap(); + let r2 = hb + .render_template( + r#"{{#> partial}} +{{#> partial2}} +:( +{{/partial2}} +{{/partial}}"#, + &(), + ) + .unwrap(); + assert_eq!(":(\n", r2); + } + + #[test] + fn test_partial_context_issue_495() { + let mut hb = Registry::new(); + hb.register_template_string( + "t1", + r#"{{~#*inline "displayName"~}} +Template:{{name}} +{{/inline}} +{{#each data as |name|}} +Name:{{name}} +{{>displayName name="aaaa"}} +{{/each}}"#, + ) + .unwrap(); + + hb.register_template_string( + "t1", + r#"{{~#*inline "displayName"~}} +Template:{{this}} +{{/inline}} +{{#each data as |name|}} +Name:{{name}} +{{>displayName}} +{{/each}}"#, + ) + .unwrap(); + + let data = json!({ + "data": ["hudel", "test"] + }); + + assert_eq!( + r#"Name:hudel +Template:hudel +Name:test +Template:test +"#, + hb.render("t1", &data).unwrap() + ); + } + + #[test] + fn test_multiline_partial_indent() { + let mut hb = Registry::new(); + + hb.register_template_string( + "t1", + r#"{{#*inline "thepartial"}} + inner first line + inner second line +{{/inline}} + {{> thepartial}} +outer third line"#, + ) + .unwrap(); + assert_eq!( + r#" inner first line + inner second line +outer third line"#, + hb.render("t1", &()).unwrap() + ); + + hb.register_template_string( + "t2", + r#"{{#*inline "thepartial"}}inner first line +inner second line +{{/inline}} + {{> thepartial}} +outer third line"#, + ) + .unwrap(); + assert_eq!( + r#" inner first line + inner second line +outer third line"#, + hb.render("t2", &()).unwrap() + ); + + hb.register_template_string( + "t3", + r#"{{#*inline "thepartial"}}{{a}}{{/inline}} + {{> thepartial}} +outer third line"#, + ) + .unwrap(); + assert_eq!( + r#" + inner first line + inner second lineouter third line"#, + hb.render("t3", &json!({"a": "inner first line\ninner second line"})) + .unwrap() + ); + + hb.register_template_string( + "t4", + r#"{{#*inline "thepartial"}} + inner first line + inner second line +{{/inline}} + {{~> thepartial}} +outer third line"#, + ) + .unwrap(); + assert_eq!( + r#" inner first line + inner second line +outer third line"#, + hb.render("t4", &()).unwrap() + ); + + let mut hb2 = Registry::new(); + hb2.set_prevent_indent(true); + + hb2.register_template_string( + "t1", + r#"{{#*inline "thepartial"}} + inner first line + inner second line +{{/inline}} + {{> thepartial}} +outer third line"#, + ) + .unwrap(); + assert_eq!( + r#" inner first line + inner second line +outer third line"#, + hb2.render("t1", &()).unwrap() + ) + } } diff --git a/vendor/handlebars/src/registry.rs b/vendor/handlebars/src/registry.rs index e7f5f1cfd..438f8573c 100644 --- a/vendor/handlebars/src/registry.rs +++ b/vendor/handlebars/src/registry.rs @@ -17,12 +17,10 @@ use crate::output::{Output, StringOutput, WriteOutput}; use crate::render::{RenderContext, Renderable}; use crate::sources::{FileSource, Source}; use crate::support::str::{self, StringWriter}; -use crate::template::Template; +use crate::template::{Template, TemplateOptions}; #[cfg(feature = "dir_source")] -use std::path; -#[cfg(feature = "dir_source")] -use walkdir::{DirEntry, WalkDir}; +use walkdir::WalkDir; #[cfg(feature = "script_helper")] use rhai::Engine; @@ -30,6 +28,9 @@ use rhai::Engine; #[cfg(feature = "script_helper")] use crate::helpers::scripting::ScriptHelper; +#[cfg(feature = "rust-embed")] +use rust_embed::RustEmbed; + /// This type represents an *escape fn*, that is a function whose purpose it is /// to escape potentially problematic characters in a string. /// @@ -62,6 +63,7 @@ pub struct Registry<'reg> { escape_fn: EscapeFn, strict_mode: bool, dev_mode: bool, + prevent_indent: bool, #[cfg(feature = "script_helper")] pub(crate) engine: Arc, @@ -90,21 +92,6 @@ impl<'reg> Default for Registry<'reg> { } } -#[cfg(feature = "dir_source")] -fn filter_file(entry: &DirEntry, suffix: &str) -> bool { - let path = entry.path(); - - // ignore hidden files, emacs buffers and files with wrong suffix - !path.is_file() - || path - .file_name() - .map(|s| { - let ds = s.to_string_lossy(); - ds.starts_with('.') || ds.starts_with('#') || !ds.ends_with(suffix) - }) - .unwrap_or(true) -} - #[cfg(feature = "script_helper")] fn rhai_engine() -> Engine { Engine::new() @@ -120,6 +107,7 @@ impl<'reg> Registry<'reg> { escape_fn: Arc::new(html_escape), strict_mode: false, dev_mode: false, + prevent_indent: false, #[cfg(feature = "script_helper")] engine: Arc::new(rhai_engine()), #[cfg(feature = "script_helper")] @@ -178,7 +166,7 @@ impl<'reg> Registry<'reg> { /// Return dev mode state, default is false /// /// With dev mode turned on, handlebars enables a set of development - /// firendly features, that may affect its performance. + /// friendly features, that may affect its performance. pub fn dev_mode(&self) -> bool { self.dev_mode } @@ -186,9 +174,30 @@ impl<'reg> Registry<'reg> { /// Enable or disable dev mode /// /// With dev mode turned on, handlebars enables a set of development - /// firendly features, that may affect its performance. + /// friendly features, that may affect its performance. + /// + /// **Note that you have to enable dev mode before adding templates to + /// the registry**. Otherwise it won't take effect at all. pub fn set_dev_mode(&mut self, enabled: bool) { self.dev_mode = enabled; + + // clear template source when disabling dev mode + if !enabled { + self.template_sources.clear(); + } + } + + /// Enable or disable indent for partial include tag `{{>}}` + /// + /// By default handlebars keeps indent whitespaces for partial + /// include tag, to change this behaviour, set this toggle to `true`. + pub fn set_prevent_indent(&mut self, enable: bool) { + self.prevent_indent = enable; + } + + /// Return state for `prevent_indent` option, default to `false`. + pub fn prevent_indent(&self) -> bool { + self.prevent_indent } /// Register a `Template` @@ -196,6 +205,9 @@ impl<'reg> Registry<'reg> { /// This is infallible since the template has already been parsed and /// insert cannot fail. If there is an existing template with this name it /// will be overwritten. + /// + /// Dev mode doesn't apply for pre-compiled template because it's lifecycle + /// is not managed by the registry. pub fn register_template(&mut self, name: &str, tpl: Template) { self.templates.insert(name.to_string(), tpl); } @@ -211,7 +223,13 @@ impl<'reg> Registry<'reg> { where S: AsRef, { - let template = Template::compile_with_name(tpl_str, name.to_owned())?; + let template = Template::compile2( + tpl_str.as_ref(), + TemplateOptions { + name: Some(name.to_owned()), + prevent_indent: self.prevent_indent, + }, + )?; self.register_template(name, template); Ok(()) } @@ -227,7 +245,10 @@ impl<'reg> Registry<'reg> { self.register_template_string(name, partial_str) } - /// Register a template from a path + /// Register a template from a path on file system + /// + /// If dev mode is enabled, the registry will keep reading the template file + /// from file system everytime it's visited. pub fn register_template_file

( &mut self, name: &str, @@ -262,11 +283,14 @@ impl<'reg> Registry<'reg> { /// /// This method is not available by default. /// You will need to enable the `dir_source` feature to use it. + /// + /// When dev_mode enabled, like `register_template_file`, templates is reloaded + /// from file system everytime it's visied. #[cfg(feature = "dir_source")] #[cfg_attr(docsrs, doc(cfg(feature = "dir_source")))] pub fn register_templates_directory

( &mut self, - tpl_extension: &'static str, + tpl_extension: &str, dir_path: P, ) -> Result<(), TemplateError> where @@ -274,40 +298,88 @@ impl<'reg> Registry<'reg> { { let dir_path = dir_path.as_ref(); - let prefix_len = if dir_path - .to_string_lossy() - .ends_with(|c| c == '\\' || c == '/') - // `/` will work on windows too so we still need to check - { - dir_path.to_string_lossy().len() - } else { - dir_path.to_string_lossy().len() + 1 - }; + // Allowing dots at the beginning as to not break old + // applications. + let tpl_extension = tpl_extension.strip_prefix('.').unwrap_or(tpl_extension); let walker = WalkDir::new(dir_path); let dir_iter = walker .min_depth(1) .into_iter() - .filter(|e| e.is_ok() && !filter_file(e.as_ref().unwrap(), tpl_extension)); + .filter_map(|e| e.ok().map(|e| e.into_path())) + // Checks if extension matches + .filter(|tpl_path| { + tpl_path + .extension() + .map(|extension| extension == tpl_extension) + .unwrap_or(false) + }) + // Rejects any hidden or temporary files. + .filter(|tpl_path| { + tpl_path + .file_stem() + .map(|stem| stem.to_string_lossy()) + .map(|stem| !(stem.starts_with('.') || stem.starts_with('#'))) + .unwrap_or(false) + }) + .filter_map(|tpl_path| { + tpl_path + .strip_prefix(dir_path) + .ok() + .map(|tpl_canonical_name| { + tpl_canonical_name + .with_extension("") + .components() + .map(|component| component.as_os_str().to_string_lossy()) + .collect::>() + .join("/") + }) + .map(|tpl_canonical_name| (tpl_canonical_name, tpl_path)) + }); + + for (tpl_canonical_name, tpl_path) in dir_iter { + self.register_template_file(&tpl_canonical_name, &tpl_path)?; + } - for entry in dir_iter { - let entry = entry?; + Ok(()) + } - let tpl_path = entry.path(); - let tpl_file_path = entry.path().to_string_lossy(); + /// Register templates using a + /// [RustEmbed](https://github.com/pyros2097/rust-embed) type + /// + /// File names from embed struct are used as template name. + /// + /// ```skip + /// #[derive(RustEmbed)] + /// #[folder = "templates"] + /// struct Assets; + /// + /// let mut hbs = Handlebars::new(); + /// hbs.register_embed_templates::(); + /// ``` + /// + #[cfg(feature = "rust-embed")] + #[cfg_attr(docsrs, doc(cfg(feature = "rust-embed")))] + pub fn register_embed_templates(&mut self) -> Result<(), TemplateError> + where + E: RustEmbed, + { + for item in E::iter() { + let file_name = item.as_ref(); + if let Some(file) = E::get(file_name) { + let data = file.data; - let tpl_name = &tpl_file_path[prefix_len..tpl_file_path.len() - tpl_extension.len()]; - // replace platform path separator with our internal one - let tpl_canonical_name = tpl_name.replace(path::MAIN_SEPARATOR, "/"); - self.register_template_file(&tpl_canonical_name, &tpl_path)?; + let tpl_content = String::from_utf8_lossy(data.as_ref()); + self.register_template_string(file_name, tpl_content)?; + } } - Ok(()) } /// Remove a template from the registry pub fn unregister_template(&mut self, name: &str) { self.templates.remove(name); + self.template_sources.remove(name); } /// Register a helper @@ -335,7 +407,6 @@ impl<'reg> Registry<'reg> { /// (value * 100).to_string() + label /// ``` /// - /// #[cfg(feature = "script_helper")] #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))] pub fn register_script_helper(&mut self, name: &str, script: &str) -> Result<(), ScriptError> { @@ -347,6 +418,9 @@ impl<'reg> Registry<'reg> { } /// Register a [rhai](https://docs.rs/rhai/) script from file + /// + /// When dev mode is enable, script file is reloaded from original file + /// everytime it is called. #[cfg(feature = "script_helper")] #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))] pub fn register_script_helper_file

( @@ -365,6 +439,22 @@ impl<'reg> Registry<'reg> { self.register_script_helper(name, &script) } + /// Borrow a read-only reference to current rhai engine + #[cfg(feature = "script_helper")] + #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))] + pub fn engine(&self) -> &Engine { + self.engine.as_ref() + } + + /// Set a custom rhai engine for the registry. + /// + /// *Note that* you need to set custom engine before adding scripts. + #[cfg(feature = "script_helper")] + #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))] + pub fn set_engine(&mut self, engine: Engine) { + self.engine = Arc::new(engine); + } + /// Register a decorator pub fn register_decorator( &mut self, @@ -389,7 +479,7 @@ impl<'reg> Registry<'reg> { /// Get a reference to the current *escape fn*. pub fn get_escape_fn(&self) -> &dyn Fn(&str) -> String { - &*self.escape_fn + self.escape_fn.as_ref() } /// Return `true` if a template is registered for the given name @@ -411,7 +501,15 @@ impl<'reg> Registry<'reg> { let r = source .load() .map_err(|e| TemplateError::from((e, name.to_owned()))) - .and_then(|tpl_str| Template::compile_with_name(tpl_str, name.to_owned())) + .and_then(|tpl_str| { + Template::compile2( + tpl_str.as_ref(), + TemplateOptions { + name: Some(name.to_owned()), + prevent_indent: self.prevent_indent, + }, + ) + }) .map(Cow::Owned) .map_err(RenderError::from); Some(r) @@ -433,6 +531,7 @@ impl<'reg> Registry<'reg> { } /// Return a registered helper + #[inline] pub(crate) fn get_or_load_helper( &'reg self, name: &str, @@ -460,6 +559,7 @@ impl<'reg> Registry<'reg> { } /// Return a registered decorator + #[inline] pub(crate) fn get_decorator( &self, name: &str, @@ -468,6 +568,10 @@ impl<'reg> Registry<'reg> { } /// Return all templates registered + /// + /// **Note that** in dev mode, the template returned from this method may + /// not reflect its latest state. This method doesn't try to reload templates + /// from its source. pub fn get_templates(&self) -> &HashMap { &self.templates } @@ -475,6 +579,7 @@ impl<'reg> Registry<'reg> { /// Unregister all templates pub fn clear_templates(&mut self) { self.templates.clear(); + self.template_sources.clear(); } #[inline] @@ -489,7 +594,7 @@ impl<'reg> Registry<'reg> { { self.get_or_load_template(name).and_then(|t| { let mut render_context = RenderContext::new(t.name.as_ref()); - t.render(self, &ctx, &mut render_context, output) + t.render(self, ctx, &mut render_context, output) }) } @@ -516,7 +621,7 @@ impl<'reg> Registry<'reg> { output.into_string().map_err(RenderError::from) } - /// Render a registered template and write some data to the `std::io::Write` + /// Render a registered template and write data to the `std::io::Write` pub fn render_to_write(&self, name: &str, data: &T, writer: W) -> Result<(), RenderError> where T: Serialize, @@ -527,6 +632,21 @@ impl<'reg> Registry<'reg> { self.render_to_output(name, &ctx, &mut output) } + /// Render a registered template using reusable `Context`, and write data to + /// the `std::io::Write` + pub fn render_with_context_to_write( + &self, + name: &str, + ctx: &Context, + writer: W, + ) -> Result<(), RenderError> + where + W: Write, + { + let mut output = WriteOutput::new(writer); + self.render_to_output(name, ctx, &mut output) + } + /// Render a template string using current registry without registering it pub fn render_template(&self, template_string: &str, data: &T) -> Result where @@ -537,23 +657,52 @@ impl<'reg> Registry<'reg> { Ok(writer.into_string()) } - /// Render a template string using reused context data + /// Render a template string using reusable context data pub fn render_template_with_context( &self, template_string: &str, ctx: &Context, ) -> Result { - let tpl = Template::compile(template_string)?; + let tpl = Template::compile2( + template_string, + TemplateOptions { + prevent_indent: self.prevent_indent, + ..Default::default() + }, + )?; let mut out = StringOutput::new(); { let mut render_context = RenderContext::new(None); - tpl.render(self, &ctx, &mut render_context, &mut out)?; + tpl.render(self, ctx, &mut render_context, &mut out)?; } out.into_string().map_err(RenderError::from) } + /// Render a template string using resuable context, and write data into + /// `std::io::Write` + pub fn render_template_with_context_to_write( + &self, + template_string: &str, + ctx: &Context, + writer: W, + ) -> Result<(), RenderError> + where + W: Write, + { + let tpl = Template::compile2( + template_string, + TemplateOptions { + prevent_indent: self.prevent_indent, + ..Default::default() + }, + )?; + let mut render_context = RenderContext::new(None); + let mut out = WriteOutput::new(writer); + tpl.render(self, ctx, &mut render_context, &mut out) + } + /// Render a template string using current registry without registering it pub fn render_template_to_write( &self, @@ -565,11 +714,8 @@ impl<'reg> Registry<'reg> { T: Serialize, W: Write, { - let tpl = Template::compile(template_string)?; let ctx = Context::wraps(data)?; - let mut render_context = RenderContext::new(None); - let mut out = WriteOutput::new(writer); - tpl.render(self, &ctx, &mut render_context, &mut out) + self.render_template_with_context_to_write(template_string, &ctx, writer) } } @@ -944,8 +1090,7 @@ mod test { .unwrap(); assert_eq!( "0123", - reg.render_with_context("t0", &Context::wraps(&data).unwrap()) - .unwrap() + reg.render_with_context("t0", &Context::from(data)).unwrap() ); } @@ -1089,4 +1234,17 @@ mod test { dir.close().unwrap(); } + + #[test] + #[cfg(feature = "script_helper")] + fn test_engine_access() { + use rhai::Engine; + + let mut registry = Registry::new(); + let mut eng = Engine::new(); + eng.set_max_string_size(1000); + registry.set_engine(eng); + + assert_eq!(1000, registry.engine().max_string_size()); + } } diff --git a/vendor/handlebars/src/render.rs b/vendor/handlebars/src/render.rs index 188ea221a..036352b3a 100644 --- a/vendor/handlebars/src/render.rs +++ b/vendor/handlebars/src/render.rs @@ -14,6 +14,7 @@ use crate::json::value::{JsonRender, PathAndJson, ScopedJson}; use crate::output::{Output, StringOutput}; use crate::partial; use crate::registry::Registry; +use crate::support; use crate::template::TemplateElement::*; use crate::template::{ BlockParam, DecoratorTemplate, HelperTemplate, Parameter, Template, TemplateElement, @@ -47,10 +48,11 @@ pub struct RenderContextInner<'reg: 'rc, 'rc> { /// root template name root_template: Option<&'reg String>, disable_escape: bool, + indent_string: Option<&'reg String>, } impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { - /// Create a render context from a `Write` + /// Create a render context pub fn new(root_template: Option<&'reg String>) -> RenderContext<'reg, 'rc> { let inner = Rc::new(RenderContextInner { partials: BTreeMap::new(), @@ -60,6 +62,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { current_template: None, root_template, disable_escape: false, + indent_string: None, }); let mut blocks = VecDeque::with_capacity(5); @@ -73,7 +76,6 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { } } - // TODO: better name pub(crate) fn new_for_block(&self) -> RenderContext<'reg, 'rc> { let inner = self.inner.clone(); @@ -101,6 +103,10 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { self.blocks.pop_front(); } + pub(crate) fn clear_blocks(&mut self) { + self.blocks.clear(); + } + /// Borrow a reference to current block context pub fn block(&self) -> Option<&BlockContext<'reg>> { self.blocks.front() @@ -190,7 +196,19 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { } pub(crate) fn dec_partial_block_depth(&mut self) { - self.inner_mut().partial_block_depth -= 1; + let depth = &mut self.inner_mut().partial_block_depth; + if *depth > 0 { + *depth -= 1; + } + } + + pub(crate) fn set_indent_string(&mut self, indent: Option<&'reg String>) { + self.inner_mut().indent_string = indent; + } + + #[inline] + pub(crate) fn get_indent_string(&self) -> Option<&'reg String> { + self.inner.indent_string } /// Remove a registered partial @@ -201,7 +219,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { fn get_local_var(&self, level: usize, name: &str) -> Option<&Json> { self.blocks .get(level) - .and_then(|blk| blk.get_local_var(&name)) + .and_then(|blk| blk.get_local_var(name)) } /// Test if given template name is current template. @@ -275,9 +293,10 @@ impl<'reg, 'rc> fmt::Debug for RenderContextInner<'reg, 'rc> { f.debug_struct("RenderContextInner") .field("partials", &self.partials) .field("partial_block_stack", &self.partial_block_stack) + .field("partial_block_depth", &self.partial_block_depth) .field("root_template", &self.root_template) .field("current_template", &self.current_template) - .field("disable_eacape", &self.disable_escape) + .field("disable_escape", &self.disable_escape) .finish() } } @@ -435,6 +454,7 @@ pub struct Decorator<'reg, 'rc> { params: Vec>, hash: BTreeMap<&'reg str, PathAndJson<'reg, 'rc>>, template: Option<&'reg Template>, + indent: Option<&'reg String>, } impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { @@ -463,6 +483,7 @@ impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { params: pv, hash: hm, template: dt.template.as_ref(), + indent: dt.indent.as_ref(), }) } @@ -495,6 +516,10 @@ impl<'reg: 'rc, 'rc> Decorator<'reg, 'rc> { pub fn template(&self) -> Option<&'reg Template> { self.template } + + pub fn indent(&self) -> Option<&'reg String> { + self.indent + } } /// Render trait @@ -747,6 +772,20 @@ pub(crate) fn do_escape(r: &Registry<'_>, rc: &RenderContext<'_, '_>, content: S } } +#[inline] +fn indent_aware_write( + v: &str, + rc: &mut RenderContext<'_, '_>, + out: &mut dyn Output, +) -> Result<(), RenderError> { + if let Some(indent) = rc.get_indent_string() { + out.write(support::str::with_indent(v, indent).as_ref())?; + } else { + out.write(v.as_ref())?; + } + Ok(()) +} + impl Renderable for TemplateElement { fn render<'reg: 'rc, 'rc>( &'reg self, @@ -755,11 +794,8 @@ impl Renderable for TemplateElement { rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output, ) -> Result<(), RenderError> { - match *self { - RawString(ref v) => { - out.write(v.as_ref())?; - Ok(()) - } + match self { + RawString(ref v) => indent_aware_write(v.as_ref(), rc, out), Expression(ref ht) | HtmlExpression(ref ht) => { let is_html_expression = matches!(self, HtmlExpression(_)); if is_html_expression { @@ -789,8 +825,7 @@ impl Renderable for TemplateElement { } else { let rendered = context_json.value().render(); let output = do_escape(registry, rc, rendered); - out.write(output.as_ref())?; - Ok(()) + indent_aware_write(output.as_ref(), rc, out) } } } else { @@ -1117,3 +1152,37 @@ fn test_zero_args_heler() { "Output name: first_name not resolved" ); } + +#[test] +fn test_identifiers_starting_with_numbers() { + let mut r = Registry::new(); + + assert!(r + .register_template_string("r1", "{{#if 0a}}true{{/if}}") + .is_ok()); + let r1 = r.render("r1", &json!({"0a": true})).unwrap(); + assert_eq!(r1, "true"); + + assert!(r.register_template_string("r2", "{{eq 1a 1}}").is_ok()); + let r2 = r.render("r2", &json!({"1a": 2, "a": 1})).unwrap(); + assert_eq!(r2, "false"); + + assert!(r + .register_template_string("r3", "0: {{0}} {{#if (eq 0 true)}}resolved from context{{/if}}\n1a: {{1a}} {{#if (eq 1a true)}}resolved from context{{/if}}\n2_2: {{2_2}} {{#if (eq 2_2 true)}}resolved from context{{/if}}") // YUP it is just eq that barfs! is if handled specially? maybe this test should go nearer to specific helpers that fail? + .is_ok()); + let r3 = r + .render("r3", &json!({"0": true, "1a": true, "2_2": true})) + .unwrap(); + assert_eq!( + r3, + "0: true \n1a: true resolved from context\n2_2: true resolved from context" + ); + + // these should all be errors: + assert!(r.register_template_string("r4", "{{eq 1}}").is_ok()); + assert!(r.register_template_string("r5", "{{eq a1}}").is_ok()); + assert!(r.register_template_string("r6", "{{eq 1a}}").is_ok()); + assert!(r.render("r4", &()).is_err()); + assert!(r.render("r5", &()).is_err()); + assert!(r.render("r6", &()).is_err()); +} diff --git a/vendor/handlebars/src/support.rs b/vendor/handlebars/src/support.rs index bd5564d32..b02aca6db 100644 --- a/vendor/handlebars/src/support.rs +++ b/vendor/handlebars/src/support.rs @@ -57,6 +57,64 @@ pub mod str { output } + /// add indent for lines but last + pub fn with_indent(s: &str, indent: &str) -> String { + let mut output = String::new(); + + let mut it = s.chars().peekable(); + while let Some(c) = it.next() { + output.push(c); + // check if c is not the last character, we don't append + // indent for last line break + if c == '\n' && it.peek().is_some() { + output.push_str(indent); + } + } + + output + } + + #[inline] + pub(crate) fn whitespace_matcher(c: char) -> bool { + c == ' ' || c == '\t' + } + + #[inline] + pub(crate) fn newline_matcher(c: char) -> bool { + c == '\n' || c == '\r' + } + + #[inline] + pub(crate) fn strip_first_newline(s: &str) -> &str { + if let Some(s) = s.strip_prefix("\r\n") { + s + } else if let Some(s) = s.strip_prefix('\n') { + s + } else { + s + } + } + + pub(crate) fn find_trailing_whitespace_chars(s: &str) -> Option<&str> { + let trimmed = s.trim_end_matches(whitespace_matcher); + if trimmed.len() == s.len() { + None + } else { + Some(&s[trimmed.len()..]) + } + } + + pub(crate) fn ends_with_empty_line(text: &str) -> bool { + let s = text.trim_end_matches(whitespace_matcher); + // also matches when text is just whitespaces + s.ends_with(newline_matcher) || s.is_empty() + } + + pub(crate) fn starts_with_empty_line(text: &str) -> bool { + text.trim_start_matches(whitespace_matcher) + .starts_with(newline_matcher) + } + #[cfg(test)] mod test { use crate::support::str::StringWriter; diff --git a/vendor/handlebars/src/template.rs b/vendor/handlebars/src/template.rs index 87f853799..617f47711 100644 --- a/vendor/handlebars/src/template.rs +++ b/vendor/handlebars/src/template.rs @@ -9,23 +9,39 @@ use pest::{Parser, Position, Span}; use serde_json::value::Value as Json; use crate::error::{TemplateError, TemplateErrorReason}; -use crate::grammar::{self, HandlebarsParser, Rule}; +use crate::grammar::{HandlebarsParser, Rule}; use crate::json::path::{parse_json_path_from_iter, Path}; +use crate::support; use self::TemplateElement::*; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct TemplateMapping(pub usize, pub usize); /// A handlebars template -#[derive(PartialEq, Clone, Debug, Default)] +#[derive(PartialEq, Eq, Clone, Debug, Default)] pub struct Template { pub name: Option, pub elements: Vec, pub mapping: Vec, } -#[derive(PartialEq, Clone, Debug)] +#[derive(Default)] +pub(crate) struct TemplateOptions { + pub(crate) prevent_indent: bool, + pub(crate) name: Option, +} + +impl TemplateOptions { + fn name(&self) -> String { + self.name + .as_ref() + .cloned() + .unwrap_or_else(|| "Unnamed".to_owned()) + } +} + +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Subexpression { // we use box here avoid resursive struct definition pub element: Box, @@ -84,13 +100,13 @@ impl Subexpression { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum BlockParam { Single(Parameter), Pair((Parameter, Parameter)), } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct ExpressionSpec { pub name: Parameter, pub params: Vec, @@ -100,7 +116,7 @@ pub struct ExpressionSpec { pub omit_pro_ws: bool, } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum Parameter { // for helper name only Name(String), @@ -110,7 +126,7 @@ pub enum Parameter { Subexpression(Subexpression), } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct HelperTemplate { pub name: Parameter, pub params: Vec, @@ -122,6 +138,18 @@ pub struct HelperTemplate { } impl HelperTemplate { + pub fn new(exp: ExpressionSpec, block: bool) -> HelperTemplate { + HelperTemplate { + name: exp.name, + params: exp.params, + hash: exp.hash, + block_param: exp.block_param, + block, + template: None, + inverse: None, + } + } + // test only pub(crate) fn with_path(path: Path) -> HelperTemplate { HelperTemplate { @@ -140,12 +168,26 @@ impl HelperTemplate { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct DecoratorTemplate { pub name: Parameter, pub params: Vec, pub hash: HashMap, pub template: Option